Technology Blog

技術ブログ

2020.04.03

UE4で1人称視点の3DSTGを作ってみる(第一回)


お久しぶりです。
さて、突然ですが今回からは数回にかけて簡単な3DSTGのようなものを作っていこうと思います。
とりあえず初回である今回は『空中を浮遊する敵』を作るところからやっていきます。

使用するUE4のバージョンは4.23.1です。
(最新ではないですが、現時点で最新バージョンの4.24でも問題なくこの手順で実装できます)

1.実装前の準備

まずはプロジェクトを作成します。
名前は自由ですが今回は『BLOG_3DSTG』と名付けています。
テンプレートにはFirstPersonを使用し、プロジェクトは『ブループリント』を選択します。
(C++でも同様の実装は問題なく可能です)

さて、このFirstPersonテンプレートでは簡易的なFPS系ゲームのプレイヤーの実装が一通りされています。
今回の記事では敵の移動までを行うため、プレイヤー部分の実装はテンプレートをそのまま使います。
(プレイヤーは一切触りません)

ただし、このFirstPersonテンプレートではあまり敵らしいデザインのメッシュが存在しません
ということで…。

2.よそのテンプレートからデータを持ってくる

ハイ、よそのテンプレートからメッシュを持ってきます
画像のUFOを敵のメッシュとして使っていきます。

このUFOはFirstPersonと同じUE4のテンプレートに含まれています。
今回はTwinStickテンプレートから引っ張ってきます。
Flyingなど、UFOのメッシュが持ってこれるのであればなんでもいいです。
自前でメッシュが用意できる場合はそちらを使った方がいいでしょう。

一度作成したプロジェクトフォルダをエクスプローラから開き、
その中からUFOメッシュが含まれるディレクトリをそのまま『1』で作ったプロジェクトにコピーしましょう。
エクスプローラからプロジェクトを操作する前にプロジェクトファイルはどちらも閉じておきましょう
(そもそも本来はエクスプローラからプロジェクトをいじるべきではないのですが…)

これで『2』で作ったプロジェクトの役目は終わりですので消してしまって大丈夫です。

3.敵BPの作成

さて、ここからが本番になります。
まずは敵キャラ用のBPを作っていきましょう。
『Charactor』を継承して『BP_FlyingEnemy』を作ります
作成したBP_FlyingEnemyを開き、Meshの子としてStaticMeshコンポーネントを追加し、ここに先ほどコピーしたUFOを設定します。
(UFOはスタティックメッシュであるため、デフォルトのメッシュ=スケルタルメッシュに設定できない)

このまま置いておくと実際のコリジョンと見かけのコリジョンがズレてしまうため、CapsuleComponentのサイズを調整します。
CapsuleComponent>CapsuleHalfHeightを34に設定してください。

これで敵BPそのものの作成は完了です。
(実装はもう少ししてから行います)

4.スプラインBPの作成

続いては『敵の移動に使うスプラインBP』を作成します。
空中に浮かぶ敵の移動処理の実装には様々な方法がありますが、
今回はこのスプラインを使う方法で進めていきます。

まずはActorを継承して『BP_EnemyMoveSpline』を作成します。
BP_EnemyMoveSplineを開き、親としてSplineMesh、その子としてSplineコンポーネントを追加します。

これでスプラインBPの作成も完了です。

5.スプラインの配置と設定

では今度はレベルに『4』で作成したBP_EnemyMoveSplineを配置・設定していきましょう。
ドラッグ&ドロップにてBP_EnemyMoveSplineを配置し、スプラインのポイントを上の画像のようにレベル上でUの字になるようにしましょう。
なお、スプラインは右クリックにてポイントを追加できるほか、選択中の左右にあるマーカーから選択中のポイントの向きの微調整が可能です。

次に配置したBP_Spline>Spline>ClosedLoopにチェックを入れます
こうすることでスプラインの始点と終点が繋がります
繋がった際にスプラインが壁にめり込んでしまうこともあるので、
その場合はスプラインの位置や向きを修正しましょう。

そして最後にBP_Spline>Spline>Durationの値を20に変更します。
これは簡単にいうと『始点から終点までに到達するまでにかかる時間』です。

6.移動ロジックの実装1

ここからはBPをいじっていきます。
『3』で作成したBP_FlyingEnemyを開きます。

まずはBeginPlayでSetMovementModeを行い移動モードをFlyingに変更します。
何もせず空中にBP_FlyingEnemyを配置してプレイするとわかりますが、
移動モードを変更してやらないとUFOはすぐにストーンと墜落してしまいます。

これはスポーン直後だと空中にいるため、移動モードがFallingになり落下しているのが原因です。
コレに対応するために移動モードをFlyingに変更する必要があります。
(移動モードを変更させたくない場合は重力を無効化してやる方法もあるがケースバイケース)

ちなみに移動モードでよく出てくるのは以下の3種です。
———-
Walking…通常移動、基本的に地上にいる時の状態
Falling…落下中、足元に地面がない時は基本的にコレ
Flying…空中移動、手動で設定する必要あり、重力の影響を受けない
———-

この状態で空中に配置してプレイするとUFOが墜落せずに浮き続けるようになります。

7.移動ロジックの実装2

ここから本格的な移動ロジックを実装します。
まずは変数としてBP_EnemyMoveSplineのリファレンスを持たせ、インスタンス編集を可能にしましょう
これはレベルに配置してから設定するパラメータで、『移動の参考にするスプライン』とでも思っていただきたいです。
名前は『UseSpline』にしておきましょう。

次にfloat型の変数『ElapsedTime』を作成します。
ここにはプレイを始めてからの経過時間を格納します。
スプライン上の移動には現在の時間が必要不可欠なので変数として持っておきます。

そして、上記の変数などを使用して画像のようにTickからノードを繋ぎましょう
(ロジックの説明はこの後すぐにします)

この状態でプレイしてみるとUFOがスプライン上をぐるっと回り、1周したところで停止するはずです。

※ロジック説明

一番最初の部分では変数ElapsedTimeに現在時間のカウントを行っています。
Tickノードの引数DeltaTimeは『そのフレームでの経過時間』で、それを毎フレーム加算しているというワケです。

そしてこの処理が敵の移動を行っている部分です。
『GetLocationAtTime』と『GetRotationAtTime』はスプラインが持つメソッドで、
『引数に指定された秒数でのスプライン上の位置』と『引数に指定された秒数でのスプライン上の向き』を表しています。
ここで現在の秒数、つまり変数ElapsedTimeを引数として使うことで、現在いるべき位置と向きを取得しています。
なお、ここではワールド座標を取得したいのでGetLocationAtTimeもGetRotationAtTimeもCoordinateSpaceをWorldに設定しておきましょう。

最後に取得した位置と向きをセットしてやればOKです。
画像ではSetActorTransformでまとめて設定してますが、
個別にSetActorLocation・SetActorRotationを行っても問題ありません。

8.移動ロジックの追加(ループ処理の追加)

ただ、この状態でプレイした場合、確かにUFOはスプライン上を移動しますが、1周したところで止まってしまいます
敵として扱うなら1周したら2周・3周としてほしいですよね?

ということでここからは移動ロジックに周回させるための処理を入れていきます。
まず、周回ができない原因ですが、ズバリ画像のこの部分です。

『GetLocationAtTimeとGetRotationAtTimeにElapsedTimeを引数として使い現在位置・向きを取得できる』と説明しましたが、
これはあくまで1周目だけの話です。2周目3周目となるとそうはいきません

確かに上記メソッドは引数の時間における現在座標を返してくれますが、
この引数の時間が1周にかかる時間、つまり『5』で設定したDurationTimeを上回ってしまうと
ずっと同じ座標(ループの終点座標)を返し続けてしまうのです。

これを回避するため、『スプラインのDurationTimeをオーバーしたら経過時間をリセットする』というロジックを追加します。

まずはfloat型の変数『LoopTime』を用意します。
ここには『1周にかかるループ時間』を格納しますが、ここの値は自動で設定されるようにしていきましょう

画像のようにBeginPlayの移動モード変更処理の直後にノードを追加します。

今度は位置変更処理の直後を画像のように実装します。
(ロジックはどちらもあとあと説明します)

このように実装を行ってからプレイをすれば、1周を終えたUFOが止まることなく2周目3周目とグルグル回るようになるはずです。

※ロジック解説

BeginPlay直後の処理は『設定されているスプラインを取得し、そのスプラインのDurationTimeをLoopTimeとして設定する』というものです。
これでスプライン側のパラメータによって簡単にLoopTimeに変化を持たせられるようになりました。

そしてこちらは『ElapsedTimeがLoopTimeをオーバーしていないかチェックする処理』です。
LoopTimeをElapsedTimeがオーバーしている(=1周が終わった)場合は即座にElapsedTimeをリセットしています。
ここで何周もスプライン上を移動できるようにしています。

9.ひとまず移動までできました

さて、これにて空中エネミーの超簡単な移動ロジックを作ることができました。
ただ、これだけじゃただグルグル回るUFOを見るだけなので、
次回はもう少しゲーム風にするためにUFOに攻撃が当たるようにしたり、
UFOの移動速度を変えられるようにしたいと思います。

オマケ.少しだけロジック部分の修正

説明のしやすさを優先したため、今回の実装は実際に使おうとした場合多少問題があります
その代表例がここですね。

ここでもしもSplineが設定されていなかった場合、予期せぬエラーが発生することになります。
ということで、基本的には以下の画像のようにリファレンスは検証済みゲットを行ってから実装に使うとよいでしょう。
検証済みゲットはリファレンスに対し右クリック→検証済みゲットとすることで可能です。

今回以降は検証済みゲットもフルに使っていきます。


関連ブログ