そうだ、ゲームを作ろう

現状や学んだことなど記録するブログ。間違ってたらごめんね

ぷちコン供養第一弾「Unstoppable Arkanoid」振り返り

ぷちコン供養の概要はこちら

wvigler.hatenablog.com

今回第一弾「Unstoppable Arkanoid」を公開しましたのでその振り返りです。

<動画>

<プレイアブル版>

drive.google.com

お品書き

・ゲームの選択

・LabelBlueprint

・演出について

・メニュー画面の操作

・BGMのVolume

 

○ゲームの選択

上の記事にも書いてありますが、これを思い付いた時にはもう18日しかない状態で「ここからある程度のものを作るには挙動を物理に任せられるゲームしかない」と思ってブロック崩しに決めました。

前回ぷちコンのことが半分トラウマみたいになってまして、「絶対に間に合うようにしたい!」という強い意志があったのもかなりあります。

ま、結果として色々考えてたら結局ギリギリになっちゃいましたけれども

それからブロック崩しというゲームについてですが

ぶっちゃけ物理制御するのは向いてないような気がします

理由としてですが、ヒットした時にイレギュラーな挙動が起こりすぎるからですね。プレイアブル版をやってみると分かるんですが、特にボールとボールがぶつかってしまった時に片方がめちゃくちゃ減速したりします。こっちとしてはぶつかっても速度を保って欲しいんですがね…

それから何らかの原因でバウンドが完全に水平、または垂直になってしまうとゲームが停滞してしまいます。一応ForwardVectorがあまりにも偏った値になった場合、ある程度補正がかかるようにしてあったりするんですが、あまりに不自然な挙動になってしまうとそれはそれでどうなんだということで、一応補正の関数を載せておきますがアドバイス等ありましたらぜひお願いします。

f:id:wvigler:20201002101644p:plain

f:id:wvigler:20201002101753p:plain

それから横からバーを突っ込ませるようにしてボールを打ち返した場合、かなりの確率で下に落ちてしまいます。そうでなくてもアイスホッケーのように多くの場合打ち返したボールが急加速してしまうので、結果的に目で追えなくなって死にます。

まあバーをゆっくり動かすようにすれば解決なのかも知れませんが、画面上に2つのボールが存在することが前提のゲームで、あまり「バーが遅かったから拾えなかった」みたいなストレスを与えるのもいかがなものかと思い、この速度にしてます。

結果としてこのゲームのゲーム性は「物理をなるべく暴れさせないように細心の注意をはらいながら、爆発でコンボを繋いでいくゲーム」となっています。プレイしているとまるで1分30秒+αの綱渡りをしているような感覚に陥るんですが、これはこれで面白いということで結果オーライかもしれません。(ただ初心者には優しくない)

 

○LabelBlueprint

このゲームでは一切UMGを使用しておりません。じゃあ文字はText3Dかというとそうでもなく、Blenderで文字のメッシュを作成しそれをBP_NeonLabelというBlueprintで並べて表示しています。ぶっちゃけあんまり意味は無い気がしますが、まあ自己満で作りました。仕組みとしてはExtentの倍の値をプラスしながらStringから取得したCharaに対応する文字メッシュを置いていくだけです。一応用途別に「OffsetなしでConstructionScriptで使用する関数」「Offsetありで左揃えで文字を表示する関数」「Offsetありで右揃えで文字を表示する関数」の三種類を作成しています。

表示するたびにStaticMeshをDestroyする構造なのでタイム表示をこれにしていいのか悩みましたが、結果僕の環境では問題無いようでした。

 

○演出について

今回は「FlowerPinball」の時と違いオープニングやゲーム開始時などにちょっとした演出を挟んでいます。これを何が管理するのがベストなのか?普通に考えれば「GameModeに任せればいいじゃん?」なのですが、GameModeだとゲームの最初にGetActorOfClassやGetActorsOfClassで使用するActorをGetしなければなりません。

その負荷を嫌って今回はBP_ProduceJunctionというBlueprintを作成してこれに一括で演出を任せることにしました。これでEditableな変数でActorを指定すれば先の関数を使わなくて済む!やったぜ!

結果としてGameModeに任せるのが多分一番いい、ということが分かりました。

第一に面倒臭いです。Actor指定するのはまだいいのですが演出を呼び出す側からもBP_ProduceJunctionをGetしなくてはならないので(そこでGetActor~関数を使うと本末転倒ですし)めちゃくちゃ手間が増えます。その点GameModeはどのActorからでも呼び出せるので、手軽に使えます。

第二に大して負荷は問題になりません。所詮GetActor~関数が呼び出されるのは最初だけです。Actor数が爆発的に増えて負荷が増大したとしてもロード画面を挟めば解決します。相当長い時間待たせない限りユーザーがやる気を無くすほどのストレスを与えるとは考えにくいです。もちろんTickでGetActor~を毎フレーム呼び出すとかは止めたほうが良いと思いますが…

というわけでこれは今回限りですね

 

○メニュー画面の操作

よくある「一回だけ上下左右を押すと普通に動く&押し続けると連続で動く」という動作。自分の中でやり方がほぼ確立しました。

f:id:wvigler:20201003064330p:plain

ClearAllTimersの中身はこちら

f:id:wvigler:20201003064442p:plain

配列のClearは必要なのか検証してないんですが、一応入れてあります。

SetTimerByEventはもちろんSetTimerByFunctionNameでも構いません。というかスッキリするので自分はそっちでやってます。

各方向に対してそれぞれ別のFunctionかEventが必要なのが玉に瑕ですね…

 

○BGMのVolume

これはちょっと自分用のメモみたいなものですが…

ボリューム調整の場合、

f:id:wvigler:20201003070928p:plain

こんな感じでSetSoundMixClassOverrideとPushSoundMixModifierを組み合わせて実装すると思うんですが、これでBGMの音量を0にした場合BGMが消えてしまい、再び音量を戻しても流れなくなってしまいます。これは設定で

f:id:wvigler:20201003071323p:plain

VoiceManagement->VirtualizationModeがデフォルトでRestartになっているためです。つまり音量が0になった場合、そのSoundを次回また流されるまでは消す、という設定になっているわけですね。SEの場合すぐ次のSoundが流れるので問題にならないのですが、BGMの場合はこの設定をPlay when Silentにしてあげると想定通りの動作になります。

 

以上、「Unstoppable Arkanoid」振り返りでした。

勝手知ったる物理ゲーと思いきや、意外と詰まるところも多かったのが印象的でした。

ご意見、ご質問、ご指摘などありましたらぜひお願いいたします。