愛をもってゲームをつくるゴリラのブログ

UE4初心者のゴリラがいろいろ頑張ります。

空中を歩くAIをつくってみる

こんばんは、ごりです。

2か月ぶりの更新です。

今回は飛行AIを作ってみたいと思います。

ナビメッシュだと地上のAIには使えるのに空中にいるAIには使えないんですよね...

 

www.unrealengine.com

 

上記のようなプラグインも出ているみたいですが、

今回はこのプラグインを使わずに作っていきたいと思います。

そしてナビメッシュも使いません。

 

UE4をやっている人なら一度は見たことのあるこのノードを使います。

  

f:id:m-goolee-y:20180903194747p:plain

 

これをつかってビヘイビアツリーのMoveToタスクを作ると、空中のキャラクターも動いてくれるようになります。

 

作り方は、まずビヘイビアツリーの

f:id:m-goolee-y:20180903193338p:plain

[新規タスク]のBTTask_BlueprintBase をクリックして、新しくブループリントクラスを作ります。

クリックするとビヘイビアツリーと同じフォルダに

f:id:m-goolee-y:20180903193533p:plain

こいつが作られるので、名前を BTTask_CustomMoveTo

に変更しておきましょう。

変更したらダブルクリックして開きます。

 

次に関数のオーバライド一覧から

RecieveExecuteAIをクリックします。

f:id:m-goolee-y:20180903201658p:plain

 

タスク開始時の処理を作っていきます。

ブラックボードに移動先の座標が書かれているとして、

[BlackBoard Key Selector]型の変数を追加します。

名前は NextLocation とします。

f:id:m-goolee-y:20180903195323p:plain

また移動先までの距離(Length)の変数も追加しておきます。

変数を追加したら下記の画像の通りに、ノードをつないでいきます。

f:id:m-goolee-y:20180903202739p:plain

 

開始時の処理はこれで完了です。

続いて移動処理を書いていきます。

関数のオーバーライド一覧から[Recieve Tick AIをクリックします。

f:id:m-goolee-y:20180903201535p:plain

 

ここで作る処理は、移動後の移動先までの残り距離の割合を計算し、閾値以下ならこのタスクは成功として返す処理となっています。

f:id:m-goolee-y:20180903203129p:plain

 

はい、これで自作のMoveToタスクが出来上がりました。

 

過去記事のEQSを使って動かしてみました

この時のAIのCharacter Movement はFlyingの状態にしてください。

 

www.youtube.com

 

ちゃんと空中を歩いていますね。

アニメーションを飛行アニメーションに変えたらそれっぽくなるかもしれないですね。

ちなみにこのカスタムMoveToはパス検索などしていないので、現状障害物をよけて進んだりはできません。

障害物をよける処理については、また後日に書きたいと思います。

 

ではまた。 

 

追記

CEDEC2018で空中のパス探索についての講演がありましたね。

それについても、そのうち実装出来たらと思います。

 

 

BehaviorTree でのMoveToタスクのカクつきを緩和してみる

お久しぶりです。ごりです。

1年ぶりの投稿です。

先日UE4勉強会in大阪(https://ue4study-osaka.connpass.com/event/93325/)にて

EQSについて講演してきました。

そのときに、BehaviorTreeのMoveToタスクについてのカクつきについて

質問があったので今回はそれについての記事にな

ります。

 

1年前の記事になりますが、このEQSを使って解説していきます。

 

goolee.hatenablog.com

 準備としてBlackBoardKeyにVectorDestination を追加しておいてください。

ここにEQSで計算した目標地点を格納します。

f:id:m-goolee-y:20180801210006p:plain

 

カクつくパターンのBehaviorTreeとして、以下のようにしました。

RunEQSQueryタスクにRandomWalk、BlackboardKeyにDestinationを設定します。

MoveToタスクの Blackboard keyにDestinationを設定します。

 

f:id:m-goolee-y:20180801210338p:plain

これで実行してみると...

f:id:m-goolee-y:20180801211207g:plain

 

カクついているのがわかると思います。

この対処法について、サービスで目標地点の近くにきたら目標地点を更新するという手法を提案しました。

そのサービスに中身について見ていきます。

BehaviorTreeの上部にある[新規サービス]からBTService_BlueprintBaseをクリック、新しくサービスを作成します。

作成したサービスの名前は UpdateDestinationとします。

f:id:m-goolee-y:20180801213249p:plain

 

サービスの更新間隔は以下のように設定してください。

f:id:m-goolee-y:20180801213514p:plain

新しく作成したサービスを開くと、イベントグラフには何もありません。

まずはカスタムイベントでEQSを実行するイベントを作成します。

RunEQSQueryノードでランダムウォークを設定し、

EQSの計算終了時に、目標地点をBlackBoardKeyに格納と目標地点までの距離を計算しています。

f:id:m-goolee-y:20180801213705p:plain

 

カスタムイベントを追加だけでは実行されません。

関数のオーバーライドから ReceiveSearchStartAI を選択します。

RecieveSearchStartAIではEQSの実行を行います。

今回の実装ではこのイベントは一回だけ呼ばれます。

f:id:m-goolee-y:20180801214308p:plain

 

次に関数のオーバーライドから RecieveTickAI を選択します。

f:id:m-goolee-y:20180801214558p:plain

 

RecieveTickAIでは残りの移動距離をチェックし一定の比率以下になったら目標地点を更新するようにしています。

f:id:m-goolee-y:20180801215046p:plain

 

これでサービスは完成です。

BehaviorTreeのRunEQSタスク削除し、以下のように設定しなおします。。

f:id:m-goolee-y:20180801215309p:plain

 

またMoveToの設定で BlackboardKey下の 

Observed Blackboard Value Tleranceを有効にする必要があります。

f:id:m-goolee-y:20180801215647p:plain

 

これで実行すると...

 

f:id:m-goolee-y:20180801215423g:plain

 

カクつきが緩和されたと思います。

それとBehaviorTreeがすっきりしましたね。

 

この手法以外にもカクつきをなくす方法はあると思います。

みなさんもいろいろ試してみてください。

間違っている点などありましたら、ご指摘いただけるとありがたいです。

 

ではまた。

 

 

 

EQSでランダムウォーク

こんばんは、goolee(ごり)です。

今日はEQSを用いたランダムウォークについて。

ランダムには動いているので、良しとしました。

では「EQS_RandomWalk」の名前のEQSを作ります。

f:id:m-goolee-y:20170815191602p:plain

今回用いたGenerator は「Circle」Generator です。

変更する部分は円の半径、生成するアイテム間の距離、トレースモードの3つです。

今回は

円の半径を300 。

生成するアイテム間の距離を DataBinding の設定を 「Randomnumber」 で

最小値を「100」最大値を「400」。

TraceData のTraceMode を 「None」にしました。

f:id:m-goolee-y:20170815191712p:plain

アイテム間の距離をランダムにすることで、プレイヤーの正面にアイテムが生成されない場合を作り、これによって前に進み続けて行きどまりになったら方向転換という動きだけにならないようにしました。

TraceModeを「None」にした理由ですが、

TraceModeが「Navigation」のままだと目の前に壁があると、壁の手前にアイテムが生成されてしまい、トレースのテストに影響が出てしまうと考えました。

f:id:m-goolee-y:20170815192956p:plain

なので「None」にして目の前に壁があっても壁の奥にアイテムが生成されるようにしました。

f:id:m-goolee-y:20170815193125p:plain

 

次に今回行ったテストは

・現在向いている方向にある点かどうか

・視界にはいっているかどうか

・到達可能かどうか

の3つです。

 

まず 現在向いている方向にある点かどうか です。

これには 「Dot」テストを行います。

変更する部分はTestPurposeを「ScoreOnly」に変えるだけです。

f:id:m-goolee-y:20170815195350p:plain

これは数学の内積ですね。

 

プレイヤーが向いている方向ベクトル(赤色)と

プレイヤーからアイテムまでのベクトル(青色)で内積を行っています。

赤色青色の矢印のなす角度Θが小さいほど内積の値は大きくなります。

つまり内積の値が大きくなるほど、向いている方向のアイテムになるということです。

 

f:id:m-goolee-y:20170815195244p:plain

 

では次に 視界にはいっているかどうか です。

これは前回書いた記事で行った 「Trace」テストを行います。

TestPurposeを「FilterOnly」にし Boolの一致のチェックをはずします。

f:id:m-goolee-y:20170815200644p:plain

f:id:m-goolee-y:20170815200850p:plain

最後に 到達可能かどうか です。

これには 「PathFinding 」のテストを行います。

これはアイテムまでの移動経路があるかどうかを判断してくれます。

変更する部分は TestPurposeを 「FilterOnly」に変えるだけです。

f:id:m-goolee-y:20170815201332p:plain

これでランダムウォークのEQSは完成です。

 

あとはこのようなビヘイビアツリーを作成すれば動きます。

移動のタスクは自作のものを使用していますが、「MoveTo」のタスクでも動くと思います。

f:id:m-goolee-y:20170815201637p:plain

 実際に動かした動画がこちらになります。


EQSでランダムウォーク

 

 

なにかおかしな点ありましたらコメントお願いします。

ではまた。

EQSで簡単な敵の探索をしてみる

お久しぶりです。ごりです。

今日は簡単な敵探索をEQSを使って実装したいと思います。

 

まず「EQS_FindEnemy」の名前のEQSをつくります。

f:id:m-goolee-y:20170811235343p:plain

 

今回使うGeneratorは 「ActorOfClass」です。

半径はお好みで設定。今回僕は半径1000で行っています。

探索する相手クラスを「BP_Enemy」としています。

f:id:m-goolee-y:20170811235953p:plain

 とりあえず現状でEQSを実行すると以下のようになります。

f:id:m-goolee-y:20170812000541p:plain

 赤色を探索を行うキャラクター、青色を敵キャラクターとしています。

敵キャラの位置にアイテムが生成されていることがわかります。

 

このアイテムの中からテストを行って一つの敵キャラクターに絞っていきます。

今回僕が行ったテストは

・プレイヤーから一番離れている敵

・プレイヤーから見える敵

の2つです。

 

まずプレイヤーから一番離れている敵のテストを実装していきます。

テストの中から「Distance」を選択。

TestPurposeを「ScoreOnly」にするだけです。

今回は一番離れているてきなので。SocringEquationを「Linear」のままにしていますが、

一番近い敵を探索したい場合は「InverseLinear」を使うと良いです。

設定し終わるとこのようになります。

f:id:m-goolee-y:20170812001745p:plain

 f:id:m-goolee-y:20170812002004p:plain

 

プレイヤーから離れるほど大きなスコアがついています。

では次にプレイヤーから見える敵のテストです。

これは「Trace」のテストを追加します。

TestPurposeを「FilterOnly」にし、

「Boolの一致」のチェックを外します。

f:id:m-goolee-y:20170812002726p:plain

f:id:m-goolee-y:20170812003437p:plain

これだと正しく計算されているかわからないので障害物をおいてみます。

f:id:m-goolee-y:20170812003509p:plain

プレイヤーから見えない敵キャラはスコア計算対象外となっていますね。

これで簡単な敵探索のEQS完成です。

f:id:m-goolee-y:20170812003658p:plain

このようなビヘイビアツリーを作成して動かすとこのように動きます。

youtu.be

 

ここ間違ってるなどありましたらコメントお願いします。

次回はランダムウォークでも作成したいと思います。

 

ではまた。

ウィジェットブループリント内でゲームパッドの入力をとれるようにした

どうも、ごりです。

 

今日はウィジェットブループリント内でのゲームパッドの入力の取り方を

僕なりにやってみました。

 

まずブループリントクラスを作成のところから、「ブループリントマクロライブラリ」を作成を選択して

f:id:m-goolee-y:20161112124913p:plain

親クラスは 「UserWidget」 で作成します。

名前は 「 GamePadInputMacroLibrary 」 とします。

f:id:m-goolee-y:20161112124953p:plain

 

今回はゲームパッドの左サムスティックで上下左右の入力とAボタンで決定するといった入力を取得したいと思います。

作成したマクロライブラリを開いて

 

まず右側の+マークをクリックして

「L_ThumStickY」「L_ThumStickX」「Button_A」と3つマクロを用意します。

 f:id:m-goolee-y:20161112125706p:plain

 

「L_ThumStickY」で説明します。

インプットに実行ピンを追加し名前を「Execute」

アウトプットピンに実行ピンを3つ追加し、「Up」「Down」「Neutral」とします。

f:id:m-goolee-y:20161112130253p:plain

 

次から処理になります。

f:id:m-goolee-y:20161112130501p:plain

「GetPlayerController」ノードから「Get Inpur Analog Stick State」を取得します。

Witch Stick は 左スティックなので 「CAS Left Stick」のままでいいです。

 

僕はサムスティックをある程度傾けた時に入力判定を取りたいので

閾値の絶対値を 0.9にしています。

 f:id:m-goolee-y:20161112130933p:plain

 

あとはStickYの値が閾値以上の場合は「Up」に

閾値以下の場合は「Down」に

それ以外は「Neutral」につなげばこれで完成です。

f:id:m-goolee-y:20161112132042p:plain

 

「L_ThumStickR」も同じように作ります。

f:id:m-goolee-y:20161112132210p:plain

f:id:m-goolee-y:20161112131926p:plain

 

次は「Button_A」についてです。

インプットには 実行ピンで「Execute」

アウトプットには 実行ピンで「Pressed」「NotPressed」

を追加します。

f:id:m-goolee-y:20161112132540p:plain

 

先ほどは「GetPlayerController」から「GetInputAnalogStickState」を取得していましたが、今度は「IsInputKeyDown」を取得します。

f:id:m-goolee-y:20161112132854p:plain

 

最後に ReturnValueが True なら Pressed

False なら Released につなげば 完成です。

 

f:id:m-goolee-y:20161112133045p:plain

 

あとは、入力を取得したいウィジェットブループリント内の

イベントティックに以下のようにつなげば入力を取得することができます。

 

f:id:m-goolee-y:20161112133657p:plain

 

これは毎フレーム判定しているので、InputAxis のような動作になります。

InputActionのようにしたい場合は、

このように DoOnce を使えば InputAction のようにすることもできます。

f:id:m-goolee-y:20161112134040p:plain

 

今回はマクロライブラリを使っての取得でしたが、

マクロライブラリを使わずにウィジェットブループリント内の仕組みで、取得する

方法があるみたいなので、いつかそれについてもやってみたいと思います。

 

これ間違っている、こうしたほうがもっと簡単などあれば

コメントお願いいたします。

キングダムハーツっぽいHPバー作ってみました。

お久しぶりです、ごりです。

 

今日は少し余裕があったので、マテリアルの勉強がてら

キングダムハーツのHPバーっぽいUIを作ってみました。

 

中身はまだ汚いので、きれいにしたら記事にするか、

プロジェクトごとあげるかします。

 

ではでは。(*- -)(*_ _)ペコリ

 

 

 

UE4のVRテンプレートやってみました。

ごりです。

 

 今更ですが、

UnrealEngine4のVer.4.13からVRテンプレートが追加されたので、

Viveでやってみました。

興味があった物を掴む処理の中身見ていきたいと思います。

 

まず入力のところから

f:id:m-goolee-y:20161029154555p:plain

プロジェクト設定-インプット を見ると、

トリガーを使うみたいです。

 

次にこの入力イベントを呼んでいる

コンテンツ-VirtualRealityBP-Blueprintsの中にある

「MotionControllerPawn」を見てみます。 

f:id:m-goolee-y:20161029154956p:plain

アクションイベントを呼び出すと

コンテンツ-VirtualRealityBP-Blueprintsの中にある

「BP_MotionController」内の「GrabActor」「ReleaseActor」という関数を

呼び出しているみたいです。

 

この2つの関数が物を掴む、離す処理っぽいです。

まず「GrabActor」関数から

f:id:m-goolee-y:20161029160026p:plain

f:id:m-goolee-y:20161029160028p:plain

 「WantstoGrip」という変数は手のアニメーションを握る状態か開く状態かを

使用する変数みたいで、

Trueの時に握って、Falseの時に離すようです。

次に「GetActorNearHand」関数は手に一番近いアクターを取得します。

しかしこの「GetActorNearHand」関数は

コンテンツ-VirtualRealityBP-Blueprints の中にある

「PickupActorInterface」というインターフェースを実装した

アクタークラスのみを取得するみたいです。

インターフェースについてはこちらの記事がすごくわかりやすいです。

 

unrealengine.hatenablog.com

 

アクターが取得出来たらリファレンスを保持して「PickUp」関数を呼び出ています。

この「Pickup」関数はアクター側の掴まれたときにどうするかの

処理になっていますね。

コンテンツ-VirtualRealityBP-Blueprints の中にある

「BP_PickupCube」がこのインターフェースを実装しているみたいなので

中身を見てみると、

f:id:m-goolee-y:20161029162353p:plain

 アクターの物理シミュレーションを止めて、BP_MotionController に取り付けているようです。

「PickupActorInterface」を実装したアクターにこの処理をかけば、物が掴めるようになりそうですね。

 

次は「ReleaseActor」関数の中身です。

 

f:id:m-goolee-y:20161029163709p:plain

f:id:m-goolee-y:20161029163711p:plain

手の情報と掴んでいるものが取り付けられている親の情報が一致したときに

 

インターフェースの「Drop」関数を呼んでいるようです。

f:id:m-goolee-y:20161029163952p:plain

 物理シミュレーションを再開し、親から外す処理のようですね。

 

以上がテンプレートの中の物を掴む処理となっています。

 

物を追加したいときは「BP_PickupCube」を複製してMeshを変えたら手っ取り早くすみます。

ただ「BP_PickupCube」は親クラスがStaticMeshActorになっているので

スケルタルメッシュを使いたい場合は親クラスがSkeltalMeshActorかアクター

にしてください。

 

試しに椅子を追加してみました。

 

 

初投稿なのと、自分で考えてやっているのでおかしなとこあれば

コメントください。

 

次回はVR空間で弓矢を打てるようにしたいと思います。