気づけばツール漬け

3D,2Dのツールを色々使ってみた記録を書いていきたいです。

「アイスクリーム早食い競争」制作メモ キャラなど前編

GameImage

第14回UE4ぷちコン応募作「アイスクリーム早食い競争」の制作メモです。UE4.25.3を使いました。
テーマの「なつやすみ」は、幅が広くアイディア出しに苦労しました。どちらかといえば、色々定番が浮かんできて、何をどうするか迷った感じです。
夏になったら何するだろう?と考えて、アイスクリームがふと浮かんだので、そこから広げていきました。町内規模で行われる、なんか微妙な行事をイメージして作ってみました。
競技っぽく見せるには相手が必要で、しかもできるだけ多いほうがいいので、AIで動かすのをがんばってみました。今回のキャラ編では、プレイヤーキャラとAIキャラの構造なんかを書いていきます。

 

応募した動画はこちら。

youtu.be

パッケージを個人のDropoboxにアップしました。よかったら遊んでみてください。
出どころ不明のアプリのダイアログが出るかもしれませんが、詳細をクリックすると開けると思います。

drive.google.com


 

キャラの構造

キャラクターは全員同じ動作をします。分けて作るとほとんど同じ処理をコピペで書いていくことになってしまうと思ったので、どうせなら共通の親を作って、そこからプレヤーキャラとAIキャラをチャイルドで作ろうと考え作業開始しました。難しかったらコピペで増やせばいいやと思いつつ、どこまで共通にできるか試した感じです。
最終的には、ほぼ全部の機能を共通化できました。

f:id:mi-zmix:20200903212820p:plain
それぞれのチャイルドは、直接マテリアルの設定で色をかえました。あと、コンストラクションスクリプトで0~3のIDを設定しました。このIDと各種値を一緒にして、ウィジェットにわたしたり、GameInstanceに格納したりしました。

f:id:mi-zmix:20200903212441p:plain

それぞれのキャラクターの個別のパラメータは、親BPのビギンプレイで、キャラデータが入った構造体から各キャラのIDをもとに抜き出して設定しました。

f:id:mi-zmix:20200903213021p:plain

動きと入力

基本の移動はサードパーソンテンプレートのものをそのまま使い、入力はPlayerControllerに移しました。入力(の模擬処理)はAIもやるので分けました。

入力からのノードを、まるまるカット&ペーストして、ターゲットをControlledPawnにつなぐことで動かせます。このゲームではジャンプは使わないので削除しました。
アイスを拾ったり頭痛になったりするため、途中でプレイヤーの入力を受け付けなくする必要があったので、ゲートをつないで開けたり閉めたりできるようにしました。

f:id:mi-zmix:20200903213547p:plain
AIControllerでも同様に入力を受け付けないように仕組みました。AIの移動にはAIMoveToを使いました。今回のゲームでは、ビヘイビアツリーは使いませんでした。単純に、ターゲットになるアイスを見つけて、そこに向かってMoveToして、アイスとオーバーラップしたら止まるという流れです。
じつはゲートでなんとかなるかと思ってたのですが、ゲートを閉じてもMoveToのターゲットがワールドの原点になって移動してしまうので、移動を止めるときは、StopMovementを使いました。
キャラクターの親BPが止めるためのイベントを呼んでいるので、念の為プレイヤーと同じ処理にした感じです。

f:id:mi-zmix:20200903213746p:plain

食べる動作の入力は、タイマーを使いました。一定時間ごとにボタンを押している想定です。この時間は各キャラ毎に変えました(緑山は早食い設定なので、間隔が短めだったりなど)。

f:id:mi-zmix:20200903214313p:plain

タイマーのイベントから、インターフェイスでControlledPawnの食べる動作につなぎました。

f:id:mi-zmix:20200903214248p:plain

イベントの受け渡し

コントローラーからキャラクターへという呼び出しの時はインターフェイスを使いました。ターゲットをControlledPawnにすることでプレイヤーキャラもAIキャラも同じイベントや関数が使えました。主にゲーム開始、終了時の通知に使いました。

f:id:mi-zmix:20200903215226p:plain

ゲーム開始や終了時はGameModeで管理してるのですが、直接各コントローラーに動く(または止まる)ようにイベントを飛ばしても、ちゃんと動いてくれなかった(たぶん、コントローラーを特定できない?)ので、キャラクターをTagで検索して、それぞれのキャラクターのコントローラーに対してインターフェイスで通知を送り、コントローラーから各ControlledPawnに通知するという流れにしました。

f:id:mi-zmix:20200903215444p:plain

キャラクターからコントローラーへという呼び出しの時は、イベントディスパッチャを使いました。食べる時に動きを止めたり、頭痛のときに動きをとめたり、回復したら動き出したりという通知を送りました。あと、食べたアイスの個数もイベントディスパッチャを使って、各コントローラーで加算するようにしました。キャラクター側で加算すると、全員で同じ値を更新するという挙動になったので。

f:id:mi-zmix:20200903215851p:plain

頭痛ゲージとHPゲージ

頭痛ゲージもHPゲージも、どちらも減らす処理はタイマーを使いました。止めたり再開したり消したりが簡単にできるのでタイマーにしました。
下図のマクロを作って、カスタムイベントでタイマーを止めたり動かしたりできるようにしました。

f:id:mi-zmix:20200903220228p:plain

タイマー用のマクロの中身はこんな感じです。

f:id:mi-zmix:20200903220412p:plain

頭痛用とHP用の増やす値はアイス側に設定していて、アイスを食べたときにその値を取得して加算しました。アイス側の値は共通ですが、受け取るキャラ側のキャパシティがそれぞれ違うので、頭痛になりにくかったり、HP多めだったりしています。

f:id:mi-zmix:20200903220627p:plain

そういえば、プレイヤーのHPが0になったときリタイア扱いになりますが、自分が動けなくなるだけでゲームは動き続けています。そのまま放置していれば、CPU君たちがゲームを終わらせてくれるのでリザルトへ移行します。これは仕様です。

2個以上同時に拾ったときの対処

テストプレイ中2個同時に拾った時、ちょっと血の気が引きました。面倒なことになったと……最初は2個ひろっても、1個しか食べてないことになってしまっていて、場にスポーンした数より合計数が減っていたので対処することにしました。

最初は1個ずつしか拾えない制限をかけるつもりでしたが、これはこれで面倒そうだったのであきらめました。2個取ってもなんとかなるようにしました。実際の競技だと仮定すると、2個同時に取るってフェアじゃないというか、ルール違反ぽいと思いますが……。

拾ったアイスアクターを順番に配列にいれて、その配列から抜き出して食べる流れにしました。

f:id:mi-zmix:20200903235658p:plain

f:id:mi-zmix:20200903235714p:plain

f:id:mi-zmix:20200903235733p:plain

地面にあるアイスと、手に持つアイスは別なものです。地面から拾ったらそのアイスの種類を取得して消します。それと同時に、手に持つアイスを右手のソケットにスポーンしました。手にスポーンしたアイスは、配列に入れておきます。

f:id:mi-zmix:20200904000258p:plain

食べるイベントの流れで、持ってる分を順番に処理しました。

f:id:mi-zmix:20200904000523p:plain
実は、2個同時に取ってももあまりいいことはありません。1個ずつ食べると、食べ終わったときに頭痛ゲージを大幅に減らすように仕組んでいるのですが、2個同時に取るとその仕組は働かず、頭痛ゲージが持ち越しになるので若干不利になっています。

AIの動き

アイスを探すのは、スフィアトレースを使いました。半径が3000くらいの巨大なスフィアで場にあるアイスを一気に取得します。複数がHitするマルチの方を使いました。

f:id:mi-zmix:20200904000832p:plain

アイスを取得した配列の中で、一番近くにあるやつをターゲットにして、AIMoveToにわたす流れです。

f:id:mi-zmix:20200904002106p:plain

また、赤い色の夕陽君だけはランダムに選んでそこに向かうという挙動にしました。ひたすら走り回る動きをすることが多くなるので、後ろから突然現れたりと場を賑やかすのに一役買っています。

f:id:mi-zmix:20200904002149p:plain
食べる動作はタイマーで勝手に動いているので、アイスを手に持ちさえすれば、自動的に食べてくれます。

アイスを食べ終わった時は、少し時間を開けて周囲を見回すアニメーションを入れました(アニメーションさせる時間を確保した)。この時間がないとCPUは無駄がない最強の動きをするので設定しました。

 アイスを食べ終わったあとや、頭痛から回復したあとに、あらためてアイスを探すためのイベントを配置しました。また、ターゲットにしていたアイスが他の人にとられてしまったら次のを探すようにタイマーのイベントで定期的に確認するようにしました。

f:id:mi-zmix:20200904002520p:plain

ちゃんとデバッグしてないですが、相手が取ろうとしている直前でプレイヤーが取った時に、次を探そうとするので動いていると思います。

 

キャラ編は以上です。
次は、アイスの構造とかその他について書こうと思います。

続き書きました。

mi-zmix.hatenablog.com