気づけばツール漬け

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

「グレイちゃんきをつけて」制作メモ

 

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

第7回UE4ぷちコン応募作の「グレイちゃんきをつけて」の制作記録メモです。

ぷちコンからだいぶ時間がたってしまいましたが、せっかく「金澤賞」いただけたのだし、やはりまとめておいた方がイイかと思いまして。

 

応募の動画URL

https://youtu.be/LWozCX3s2hE

アップしたパッケージURL

https://www.dropbox.com/s/34v1ap2co94qle5/WindowsNoEditor.zip?dl=0

 

●内容

 

●はじめに

テーマのサプライズを辞書でしらべると、「不意打ち」というのが目に入ったので、コレで何かできないかな~と考えました。できあがったものを見直してみると、不意打ちとは少し違うかなという感じもありますが、いきなりでびっくりする部分はあるからいいかなと。

他にも3、4個考えましたが、自分の実力では無理なので諦めました。

 

とにかく時間がないので、

「極め本で学んだ範囲+ちょっと挑戦」

という目標でやってみました。

とりあえず、ゲームの形を思いついたと同時に、敵はグレイマン、プレイヤーはグレイちゃんと決めました。

せっかくのUE4だし。かわいいし。

グレイちゃんはこちら。

www.gray-chan.com

 

●必要最低限を洗い出す

妄想にまかせたまますすめると、とても自分の力では実現できそうもなく、時間切れでできなくて悔しい思いをするのはいやなので、必要最低限をやろうと決めました。

 

「これがないと成り立たない」「コレがあれば成立する」という部分をメモしていきました。

「グレイちゃんきをつけて」の最低限の仕様は

・グレイちゃんは同じ速度でまっすぐ歩き、コースは変わらない。マップの端まで到達したらゴールとする。

・敵は固定で配置する。敵ごとに、攻撃かフェイントかをランダムに設定する。

・敵はグレイちゃんが近づくと、グレイちゃんの方を見る。

・グレイちゃんを見つつ、ランダムな時間をあけて、攻撃またはフェイントをする。

・グレイちゃんはActionボタンでいつでもガードの動作をする。ガード中は移動しない。

・ガードの受付時間内に敵の攻撃をうければ、ガード成功として反撃を出す。

・ガードの受付時間内に攻撃を受けなかったら、ガード失敗とする。

・ガードせずに、敵の攻撃を受けてしまったら、負けとしてやられモーションする。

・その後一定時間で立ち直り、再びあるく。

という内容です。

 

プロトタイプはこんな感じでした。

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

 

 

●ロジックから考え始める

ロジック考えて実装するってのを、私はまともにやったことがなかったので、そこから着手します。

普段はビジュアル方面の作業が多いし、UE4はそれすらもまともにやったことがなかった状態でした。

このゲームの要は、「ガードの成功、または失敗と、その結果を受け渡しする仕組み」です。

コレが想定通りに動けばよし、という感じで作り始めました。

最初、アクションなのでコライダ同士ぶつけて、HITイベントで処理かな~と考えてましたが、それはやめました。
厳密な判定は必要ないですし、あたりはずれの判定だけでいいので、フラグのやり取りで行けないかと考えました。

 

●実装

動作ごとのフラグの設定と、フラグによって分岐してイベントを飛ばすというやり取りでやってみました。

フラグがたつたび、行動するたびに、PrintStringを挟んで画面に出力して確認する作業してました。

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

敵側は、ビヘイビアツリーを使って行動を決めてます。

たぶん、ビヘイビアツリーつかわなくても実現できるのですが、これも挑戦の一つだったので使ってみました。

※以下からの図のBPは完成時のものです。

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

MeasureDistanceでグレイちゃんとの距離が一定距離内に入ったら、FindTargetでブラックボードに書き込んで、ENBTTask_LookAtでグレイちゃんの方を見続けるようにしました。

その後ENBTTask_Attackで攻撃を決定します。

攻撃かフェイントかは、1=攻撃、2=フェイント、3=なにもしない の数値でスイッチで分岐させてます。分岐させた後、敵のBPのイベントを呼び出します。

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

攻撃は、LineTraceByChannelを使いました。

LineTraceでグレイちゃんを受け取り、その中のフラグを見て行動を決定するイベントを呼び出します。

敵側からグレイちゃんに「行動して」って感じでイベントを呼び出してます。

敵側は攻撃した時、グレイちゃんがガードしてるかどうかだけ見れば良く、

ガードしてたら自分はやられるので、一定の待ち時間後にやられ動作に移行します。

ガードしてなかったら、自分の攻撃が通ったのでそのままにして、後は何もしません。

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

グレイちゃんの方は、

まず、サードパーソンキャラクターのBPの中で、前に移動する部分だけ残して、パルスを切って行きました。

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

移動速度を設定する変数に固定値を設定して、0と固定値をセットし直すことで、移動と停止を実現してます。強引です。一番最初にこれをやって、とりあえずコレでいいやということで次に行きました。

 

グレイちゃんの前方を覆うようにトリガーを設置して一緒に動かします。センサーの役割です。

このセンサーに敵が入ったら、キャストして敵を取得しておきます。

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

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

同時に2体入らないように、敵の距離を配置で調整しました。もし敵が自由に動くようにするなら、別の仕組みで対処しないとならないでしょう。

 

ガードしたら、ガード中であるフラグを立てておき、敵がそれを見て勝ちか負けかを判断します。

同時にグレイちゃんも判断します。

ガードを開始したら、ガードのタイマーをスタートして、タイマーがきれたらイベントを飛ばして、ガード失敗扱いにします。

ガードが成功したら、すぐにガードのタイマーはリセットします。

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

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

 

ガードが成功したなら、グレイちゃんは反撃の流れ、敵はやられる流れに移行します。

これは単純に時間の流れななので、ディレイ等で調整しました。実際、ちょっとずれてます。

 

これでゲームの流れができました。

終始、「こんなんでいいのかなあ?」「まあうごいてるからいいか」という感じでした。

とにかく「実現したいことが実現できていれば良い」ということで進めてました。

改良とか拡張しようと思ったら後でこまるのかもしれないけど、そのときに困って経験値にすればいいんだと思います。

実際想定した困り方とは違うかもしれないし、そもそも困らないかもしれないし、わからないのですよ。

悩んでる時間がもったいないです。*1

 

ゲームの流れができたので、あとは見た目の作成に入ります。

※キャラモーション関連については、別でまとめるつもりです。

↓ こちらにまとめました。

http://mi-zmix.hatenablog.com/entry/2017/05/10/232003

 

●アニメーションと合わせる

キャラモーションを作ったら、想定したタイミングでPrintStringを置いてた所を、アニメーションブループリントと連携するイベントで置き換えていきます。

このあたりも、どうやるのがいいか色々考えましたが、カスタムイベントで動かす方法をとりました。

 

行き当たりばったりで進めても、ノードのつなぎ変えが分かり易いのでBPはいいですね。

 

ほとんどのアニメーションは、フラグをONにして次に遷移して、ディレイで設定した時間がきたらフラグをOFFにするという流れにしてます。

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

ステートマシンの方は、敵もグレイちゃんも、モーションの再生が終わったら次に進むという感じで設定しました。図はグレイちゃんのステートマシン。

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

一通り動くようになったら、ディレイを挟んでそれぞれのアニメーションのタイミングを調整しました。

ガード中と、敵のはじかれ中は、再生速度を調整して、待ち時間に対応するようにしました。

 

●エフェクトとSE

エフェクトは、インフィニットブレードの物から流用しました。

SEはUniversal Sound Fx(有料)を使いました。

エフェクトもSEも、ほぼ全部アニメーションの中に仕込んでいます。

当たったから出るのではなく、あたったと思う瞬間に出す感じです。

人は目で見るより、耳の方が反応が早いので、その辺も意識して発生をずらしたりしてます。

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

 

●敵の配置について

「ランダムに配置しつつも、攻撃してくる敵は6人にしたい」

というのを実現するために、色々試行錯誤しました。

最初は敵の攻撃の種類を完全にランダムにしていましたが、この場合「攻撃してくる敵がだれもいない」という事がありえるので、どうにかして意図的に敵の種類を調整したいと考えていました。*2

 

「ランダムに配置しつつも、攻撃してくる敵は6人にしたい」

というのを実現するために、色々試行錯誤しました。

配列の中身をランダムに入れ替えるって、BPでどうやるんだろ? ってのがいまいちわからなかったので、

最終的には配列の構造体を作って、構造体の中からランダムに配列を選択する。

という方法を取りました。

こちらのページを参考にしました。

katze.hatenablog.jp

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

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

配列一個分の中は、手動でランダムに見えるように設定してます。

この組み合わせを6個ほど作って構造体にしてます。ちからわざです。

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

●パッケージ化で苦労する

エラーのメッセージがまったくわからないので、ひたすらググりました。

ずらずらと表示されるログの内容は、プログラマさんなら見ればわかると言うものらしく、コレがわかるのとわからないの境目ってなんだろな? とか考えつつ、ひたすらググります。

 

まず、プラグインにひっかかってました。

プラグインを解除しまくることで、とりあえずはいきなり終了する事態から脱します。

その次は、「ファイル名が長い」ってのにひっかかってました。フォルダのパスまで含めて全部で256文字以内って、けっこう厳しい制限な気がします。

SEのファイル名が最初からものすごく長く、さらにフォルダも深くなっていたので、なおさら長くなってました。

これらの中から使ってる分だけ抽出して、深くないフォルダに移動し、さらにリネームしました。

あと、パッケージを出力するフォルダも、ドライブの直下に置いて対処しました。

仕上げで、コンテンツフォルダ上で、FixUp Redirectors in Folder もやっておきます。

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

 

そんなこんなでパッケージ化はできたものの、内容は全部で4GB弱くらいあったので、DVDには入るかな~ と軽く現実逃避しつつ、こりゃだめだなてことで、なんとか小さくしようと試みます。

応募動画には問題なさそうなので、4GBくらいあるパッケージの状態で動画にしました。

 

こちらのページを参考にして、整理しました。

unrealengine.hatenablog.com

www.the-saurus.net

「次からは、ちゃんと使ったアセット整理する」と心に誓うのでした。

プロジェクトフォルダの中もスッキリ整理できて、

最終的には背景も変えて、だいぶダイエットできました。

 

●おわりに

この挑戦は自分にとってはものすごく大きかったです。

タイトルから始まり、メインがあり、ゲームの終わりがあって、タイトルに戻るという一連の流れをUE4で作れて良かったと思います。

「極め本」にはお世話になりました。この本はUE4が初めてならば、絶対に読んでおく方が良い本だと思います。

また、alweiさんのブログと、ヒストリアさんのブログにもかなりお世話になりました。ぐぐったら公式の次に出て来る頻度ですので。

マテリアル関連をいじれなかったので、今度はその辺に挑戦したいです。

 

UE4はノードコーディングがめちゃくちゃ楽しいですね。

また次のぷちコンも挑戦したいですし、ぷちコンじゃなくても何か作らねば。

 

*1:ただし、仕事では別だと思います。さっさと相談するのです。

*2:テスト中では、12人中1人しかいないという事がありました。