読者です 読者をやめる 読者になる 読者になる

GameProgrammar's Night

ゲームプログラム系の覚え書き

UE4 FloatingPawnMovement を使う

UnrealEngine4

 FloatingPawnMovementとは、UE4が用意している移動を担うComponentの一つです。
 CharacterMovementのように状態(歩き、ジャンプ、しゃがみ)があるわけでもなく、設定したパラメータ通りに位置を変化させるだけのシンプルな実装のMovementComponentです。
 シンプルですが2Dゲームで使うには十分な機能を持っており、自分のゲームでの移動はFloatingPawnMovementをメインに使っています。
 

移動させる

f:id:katze_7514:20161026154832p:plain

 移動させる時は、AddInputVectorノードを使います。
 FloatingPawnMovementは、移動させたい方向のベクトルを与えることで移動します。

●X+方向なら(1.0, 0.0, 0.0)
f:id:katze_7514:20161026161546p:plain

●45度方向だったら(cos45, sin45, 0.0)
f:id:katze_7514:20161026161554p:plain

 方向ベクトルの長さは「0.0~1.0」です。1.0以上与えても1.0として扱われます。この長さは、次に説明する速度パラメータのスケール値として働きます。

 AddInputVectorは呼ぶ度に方向ベクトルが加算されて行きます。FloatingPawnMovementのTickが呼ばれるまでの加算結果を用いて移動処理が実行されます。
 これを利用することで、Pawnの外部からの影響を受ける特殊な移動処理を簡単に実現することもできます。

ある地点に引っ張られる

 青いエフェクトが出ている間、通常の移動処理に加えて、中央に移動する方向ベクトルをAddInputVectorすることで実現しています。

速度パラメータ

 MovementComponentでの移動は、与えたベクトル方向に加速していき、最大の速さに到達したら速さアップを止めます。ベクトルの入力が無くなったら減速します。
 移動の調整は、それらのパラメータをいじることで行います。

f:id:katze_7514:20161026150207p:plain

パラメータ名 意味(単位)
Max Speed 最大の速さ(unit/sec)
Acceleration 加速度(unit/sec)
Deceleration 減速度(unit/sec)
Turning Boost 方向転換した際の追加加速スケール

 単位は、unit/secです。2Dゲームで、PPUを1.0に設定している場合は、pixel/sec と思って大丈夫です。

 TurningBoostは、どれだけ素早く方向転換できるか、ということを示すパラメータです。TurningBoostの値が大きいほど素早く方向転換が行われ、小さいほどゆっくり方向転換します。動作としては、方向転換する時だけ、加速度がTurningBoost倍されます。

 デフォルトの値では、加速も減速も方向転換も、かなり素早く行う設定となっています。そのため、すぐに最大の速さになりますし、ピタっと静止できるし、瞬間的に方向転換します。

慣性のある移動(滑りながら移動)

 速度パラメータ設定の応用として、慣性のつく設定を紹介します。
 以下のように、最大の速さ以外のパラメータの値を大きく下げ、また加速より減速の値を低くします。

f:id:katze_7514:20161026180052p:plain

 すると次の動画のようになります。

youtu.be

移動制限パラメータ

 移動する平面を指定することができます。指定した平面以外へは動かなくなります。
 詳細パネルのPlanarMovementで設定します。
 
f:id:katze_7514:20161026154839p:plain

 図の設定だと、移動がXY平面のみとなりZ方向には動かなくなります。

パラメータ 意味
Constrain to Plane チェックを入れると平面に移動が制限される
Snap to Plane at Start Spawnした時から指定した平面に制限するか
Plane Constraint Axis Setting 移動制限したい平面の簡易設定。移動制限する平面の法線軸を指定。Customを選んだ場合は次の2項目を自分でいれる
Plane Constraint Normal 移動制限平面との法線ベクトル
Plane Constraint Origin 移動制限平面の法線ベクトルの原点

 ただし、Pawnに直接Locationを入れれば(AddWorldLocationなど)、動かない方向にも動きます。あくまで、FloatingPawnMovementによる移動が制限される設定となります。

Navigation

 FloatingPawnMovementは、Navigation移動に対応しています。AIControllerを持つPawnに持たせれば、MoveTo系ノードを使うことで、今まで紹介したパラメータに従ってNavigationします。

注意点

 FloatingPawnMovementは、AddInputVectorでベクトルが追加されなかった場合に減速する仕組み上、前フレームとの位置差分を速度ベクトルに変換する処理が入っています。
 そのため、直接Locationを入れて動かすことと併用している場合、想定してない移動になることがまれにあります。

 自分の場合は、移動制限せずに、描画順制御のためにZ方向の移動だけはSetWorldLocationで行っていた所、Z方向に速度が発生してしまいました。描画順がおかしくなったり、衝突するはずのコリジョンが当たらなくなったりしていました。

PlayStation4のコントーラをWindowsで使う時の開発側の注意点

DirectX Input

 PS4がアップデートされて、PCからリモートプレイができるようになりました。
 それに合わせて、PS4コントローラをPCにUSB接続するだけで、ゲームパッドとして利用することができるようにもなりました。そのため、これからPCゲームをPS4コントローラで遊ぶ人が増えると思います。
 UEDirectInputPadPluginでPS4コントローラを使った所、キーコンフィグBPがちゃんと動かないと言われまして調査しました。

 その結果、開発側としては、考慮しておいた方が良い事項がありましたので、書いておきたいと思います。

PS4コントローラ

  • DirectInputで動作している
  • L2/R2ボタンは、回転軸とボタンの両方にマッピングされている
    • L2はX回転と7ボタン
    • R2はY回転と8ボタン
    • 回転は-1.0(押されてない)~1.0(一番下まで押し込む)の範囲の値が取得される*1

f:id:katze_7514:20160806154518p:plain

 1つのボタンで2つ値が返ってくるので、キーコンフィグを作る時にはちょっと頭にいれて置くと良いと思います。

 PS4コントローラが意図している所は理解できるんですが、どうせならXInputで動くようにしてくれれば良いのにね……。と思ったのですが、タッチパッドの情報を使うためにDirectInputにしているのかもしれません。PSボタンは13ボタン、タッチパッドボタンは14ボタンに割り当てられています。

*1:XInputのLT/RTは0.0~1.0

UE4 アクターの入力取得をコントロールする

UnrealEngine4 Input

docs.unrealengine.com
docs.unrealengine.com

 この辺りに書いてあることと独自調査を元にキー/パッド/マウス入力(以下単に入力)で悩まないようにするためのまとめとなっています。

入力を取得できるようにする設定

 あらゆるActorは適切な設定を行うことで、入力を取得できるようになります。

詳細パネル

f:id:katze_7514:20160719230556j:plain

 デフォルト設定は詳細パネルのInputの項目で行います。
 [AutoReceiveInput]の項目を入力取得したいPlayerIndexに設定することで、そのプレイヤーからの入力を取得することができます。一人用の場合、Player0にしておけばOKです。
 [Input Priority]については後述します。

BPノード

f:id:katze_7514:20160719230606j:plain

 実行中に入力取得の可否をコントロールする時は、上記のEnable/DisableInputを使います。
 名前通り、EnableInputは入力取得ができるようになり、DisableInputは入力取得ができなくなります。
 Actorピンに設定したいActorを接続します。
 PlayerControllerピンは入力を取得したいPlayerIndexを持つPlayerControllerを接続しますが、一人用の場合は何も接続しなくても大丈夫です。

入力取得の順序

 UE4の入力取得は、実はブロードキャストされておらず、決まった順番で入力情報が配送されていきます。あるアクターで入力が使われると、その後の順番になっているアクターは入力取得することができません。
 例えば、Wキーを取得するHogeアクターとFooアクターがあり、入力順序が、Hoge→Foo だった時、HogeでWキーを取得すると、FooではWキーの入力取得ができません。

 この入力順序は、詳細パネルの[InputPriority]でコントロールします。値が大きい方が先に入力を取得できます。
 ただし、いくつかのアクターは固定順序になっていますので、実際には以下の通りになります。

  1. 以下に無いActorがPriority降順
  2. PlayerControllerのComponent
  3. PlayerController
  4. [常にロード]のLevel
  5. PlayerPawnのComponent
  6. PlayerPawn

の順番に配送されていきます。
 PlayerPawnとはPlayerControllerにPossessされているPawnのことです。
 同一Priorityの時は、後から生成されたもの、後からEnableInputをしたアクターが優先度高くなります。

 なお、配送処理自体はPlayerControllerのTickタイミングで行われていますので、PlayerControllerのTickを停止するとすべての入力を取得できなくなりますので、ご注意ください。

BlockInput

 詳細パネルに[BlockInput]という項目がありました。同一名のBPノードもあります。
 入力配送処理を終えるフラグです。このフラグがONになっているアクターより優先度が低いアクターは入力が一切取得できなくなります。

 DisableInputノードは、入力取得順序から一時的に外れる処理となっていますので、優先度が低いアクターが入力取得ができなくなることはありません。

ConsumeInput/GamePause

f:id:katze_7514:20160509155946j:plain

 入力にまつわる重要な設定に、ConsumeInputとGamePauseがあります。
 ConsumeInputは、優先度の低いアクターに入力を渡さないかどうかの設定です。先ほど上げた例ですと、HogeアクターのWキー入力のConsumeInputフラグをOFFにすると、FooアクターでもWキーを取得できるようになります。
 アクターの入力はGamePauseの影響を受けますので、GamePauseをすると入力取得を行いません。しかし、メニュー操作などGamePause中でも入力を取得したい時は、[Execute when Paused]フラグをONにすることで、GamePause中でも取得されるようになります。

UE4 Navigationができない時に確認すること

UnrealEngine4

 何度もNavigationができたりできなかったりして、いい加減嫌になったので本腰をいれて調べてみました。
 Navigation(static)が使えるのは以下の条件をすべて満たしている時になります。

  1. AIControllerを持つPawn
  2. UE4が用意したMovementComponentを持つPawn
    • CharacterMovement か FloatingPawnMovement
  3. NavMeshBoundsVolumeが「常にロード」になっているLevelに配置されている

以上です。
 サブレベルを使ってシーン遷移を実装していると、3番目の条件がかなり罠で、自分が悩まされていた原因でした。複数のNavMeshBoundsVolumeを切り替えながら使うということもできません。NavMeshBoundsVolumeがマップごとに変化する場合は、OpenLevelを使って遷移しないとダメなようです。
 なお、NavigationをDynamicにした場合はゲームが実行されてからNavMeshが計算されるので、この限りではありません。

UE4 BPで2次元配列を実現する

UnrealEngine4

 BPは使えるデータ構造が少なく1次元配列しか使えません。1次元配列だけでも組むこと自体はもちろん可能ですが、せめて2次元配列ぐらいは欲しい所です。
 というわけで、BPで2次元配列を扱うためのTIPSを紹介します。

1次元配列を2次元配列のように扱うインデックス計算をする

 配列のインデックス計算を工夫して、実体は1次元配列でも2次元配列のようにアクセスできるようにします。
 2次元配列として扱いたい配列に対して、以下のようなマクロを用意します。

f:id:katze_7514:20160625131401j:plain

 2次元配列にアクセスするための2つのインデックスと配列あたりのサイズを受け取って、実際に格納されているインデックスを計算します。
 これを使って

f:id:katze_7514:20160625145450j:plain

 のように使います。疑似コードで書くと

float f = FloatArray[0][2];

のような感じになっています。

 この形で2次元配列を使う時は、AddやRemoveを使うとインデックスがズレてしまうので使うことはできません。必ずSetItemArrayElemノードを使ってインデックスを使用してアクセスするようにしてください。SetItemArrayElemを利用した専用のAdd/Removeマクロを作ると良いと思います。

BP構造体を利用する

  • 配列の配列は作れない
  • 構造体の配列は作れる
  • 構造体のメンバーに配列を作ることはできる

以上のことより、構造体を介すことて簡単に2次元以上の配列を作ることができます。

 配列をメンバーにした構造体を作ります。 
f:id:katze_7514:20160625140501j:plain

 その構造体を配列にします。
f:id:katze_7514:20160625140630j:plain

 二次元配列の完成です。アクセスは以下の通り

f:id:katze_7514:20160625140954j:plain

 ゲームのパラメータを扱うならば、構造体に名前も付けられますし、こちらの方が優れているかもしれません。
 状況に応じて使い分けてみてください。

まとめ

 2次元配列の実現の仕方でした。これらの話を拡張することで多次元配列を作ることも可能です。
 それにしても、BPのデータ構造の貧弱さは、本当にどうにかして欲しい所です……。Mapのエディタ対応はよ!