UE4、BPでのデストラクタ処理の作り方
アクタ(AActor継承クラス)がDestroyされたときの流れ
- Destroy()呼ばれる
- Destroy()の中でDestroyed()呼ばれる
- Destroyed()の中でReceiveDestroyed()呼ばれる
- Destroyed()の中でOnDestroyed()呼ばれる
BPではReceiveDestroyedとOnDestroyedを使用する、これらの関数はC++側には実装はない
ReceiveDestroyed
BlueprintImplementableEventとして定義されているので、BPでオーバーライドして使用する
DisplayName = “Destroyed”となっているので、BPでは"Event Destroyed"ノードとして現れる(C++のDestroyed()とは別)
参考
Unreal Engine | ゲームプレイ要素をブループリントに公開する
OnDestroyed
イベントディスパッチャー(DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam)として定義されていて、BPではバインドして使用する
ReceiveDestroyedとの違いは、DestroyedされたActorがポインタとして返ってくるのでどうこうしたいならこちらを使用する
参考
Unreal Engine | マルチキャスト デリゲート
実行順序は、ReceiveDestroyedのほうが一行だけ先に呼ばれる
SVNでリビジョン管理やる
いい加減ソースコントロール使う、SVNが楽そうなのでそれでやる
1.TortoiseSVNのインストールまでやる
2.リポジトリを適当なところに作成する、ここに差分が集まってくる、デフォルトのフォルダ構造作りますかって言われるけど作らないでそのままOK押して終了する
3.プロジェクト作成する
空じゃないんだが?って言われるけどそのままやる
5.差分取るファイルを選択してAddしていく、ドキュメントによるとこれ(チェックついてるやつ)をやる、SourceはC++プロジェクトじゃないとない
6.コミットしておく(一番上の階層(プロジェクトフォルダ)でやると1発で全部やってくれる)
7.UE側でsvnに接続する、左上のSourceControlアイコンを押す
これでとりあえずできるようになった、エディタからコミットできるのはContentsのものだけなのでC++の編集とかはエクスプローラーから自分でやる(多分)
ラベルは設定してないので空欄だけれど、そもそもラベルの必要性いまいちよく分かってないので、よく分かったら追記します
参考
Unreal Engine | ソース コントロールとして SVN を使用する
TortoiseSVN の基礎勉強 〜TortoiseSVN によるバージョン管理を使う〜 — バージョン管理システム入門(初心者向け)
UE4 ソースコントロールを使ってアセット管理をする - Let's Enjoy Unreal Engine
セーブについて
UE4にはセーブとロード用の関数が用意されている
セーブデータ自体はSaveGameクラスを拡張して定義する、このクラスに作成した変数がファイルに書き込まれる
SaveGameクラス自体はUObjectを継承しているだけで全く実装はなく、セーブ系の関数を使う時にこのクラスを継承しているかどうかを見ているだけ
C++で書いても、UPROPETYで公開できるようなものしかセーブされないので、例えばTMapで所持アイテムを管理しているとかなら、ロード時にパースする処理が必要
参考
Unreal Engine | ゲームを保存する
Unreal Engine | ゲームをブループリントで保存する
Unreal Engine | ゲームを C++ で保存する
翻訳について
ローカライゼーションダッシュボードを使ってテキストをローカライズする。 - Qiita
FTextを検索して置換することができる、なのでHUDに出てくる文字は全てをFTextでやっておく、むしろ置換対象に出てくるのでこれ以外では使わない
こんな構造体を使用するDataTableから全抽出してくれて便利
UE4.13、C++側で構造体を定義してBPで使う
USTRUCT(BlueprintType) struct FGameItem { GENERATED_USTRUCT_BODY() UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item") FName key; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item") int32 num; // Constructer FGameItem() { key = FName(TEXT("none")); num = 0; } FGameItem(const FName InKey, const int32 InNum) { key = InKey; num = InNum; } // Functions int32 GetNum() const { return num; } int32 AddNum(int32 InNum) { return num += InNum; } int32 SubNum(int32 InNum) { return num -= InNum; } };
これでエディタで構造体を作ったときのように、BPで構造体型の変数が作れたり、breakノードが使えるようになる
・コンストラクタでデフォルト値を設定する
・UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Category") を設定したメンバ変数がbreakで展開される
・UFUNCTIONマクロは使えない(多分)
上記SS内のTMapでこの構造体を管理して、値をBPでみたいというコード、ついで
public: // Player ItemList typedef TMap<FName, TSharedPtr<FGameItem>> ItemMap; ItemMap ItemList; UFUNCTION(BlueprintCallable, Category = "Item") bool GetItem(const FName InKey, FGameItem& Item) { if (ItemList.Contains(InKey)) { Item = *ItemList[InKey]; return true; } return false; }
参考
Structs, USTRUCTS(), They're Awesome - Epic Wiki
Rama is God.
4.13のレンダーターゲットへのブループリント描画
4.13の新機能、テクスチャのUV座標を取得と、レンダーターゲットへのブループリント描画を触っておく
テクスチャのUV座標取得
関数FindCollisionUVがそれ、実装はGameplayStatic.cppにある
エンジン設定でbSupportUVFromHitResultsを有効にすると使えるようになる、これを有効にするとメモリ負荷が増える
Linetrace結果のHit構造体を引数にとって、Hit先のコリジョンを取得し、HitPointのUV座標を計算する
ノードはこんなかんじ、UVChannelは設定を特にいじってなければ0が通常のテクスチャUV、1はライトマップ用になっているはず
参考
UBodySetup | Unreal Engine API Reference
レンダーターゲットへのブループリント描画
レンダーターゲットはそもそも何かで、今までのバージョンでは、例えば監視カメラがあったとして、それが写している映像をマップ内のモニタに表示させたい、みたいなときに(のみ)使用されていたリアルタイム生成テクスチャ、のような感じであった
今回のアップデートで追加されたこの機能は、カメラの映像を反映させるだけでなく、ユーザー側から結構自由にレンダーターゲットをいじれるようになる機能で、上記のUV座標取得と組み合わせることで、例えば板ポリに直接お絵かきとか可能になる
レンダーターゲット描写の関数は色々あり、順に確認する
DrawMaterialToRenderTarget
指定したレンダーターゲットに指定したマテリアルを描写する
マテリアルのemissiveとOpacityアウトプットのみが描写されるので、それ用に作る
また内部的にはCanvasを利用してるので、UI用マテリアルでも動く
この関数ではただマテリアルを転写して終わりなので、色々やるようの方を確認する
BeginDrawCanvasToRenderTarget / EndDrawCanvasToRenderTarget
BeginDrawCanvasToRenderTargetでは、レンダーターゲットのサイズのCanvasを生成する、そのCanvasに対し、Canvas描写系の関数を実行し、EndDrawCanvasToRenderTargetでCanvasをレンダーターゲットに反映するという流れ
このときに、上記のUV座標取得と組み合わせることで、任意の位置への描写が可能になる
どれも実装はKismetRenderingLibrary.cppにある
参考
UCanvas | Unreal Engine API Reference
Time値を渡してやると色々できそう、機能紹介の波紋のノードの解説あるのかな
例えばTimeを使いたいとき、TextureRenderTargetのHDRのチェックを外していると、1以上の値が切り捨てられているので動かなくなる、逆に通常の範囲内での使用ならこのチェックは外していい
箱の上に上がる、柵を乗り越える
箱の上に上がりたい
CharacterMovementのパラメーターにはMaxStepHeightがあり、これは歩ける段差の最大の高さ、階段の1段
これが例えば30cmだとする、ここで乗り越えられる箱の最大の高さを決める、1mとする
すると、30cm ~ 1m の高さのオブジェクトには乗り越えられることになる
いきなりいろいろやると面倒なので、とりあえず、1mの箱の上に上がる処理を考えていく
アニメ作る
高さ可変をやるなら、手の位置がIKで変動する、考えるのがめんどくさい、1mFIXでアニメを打つ、適当にやる
カプセルの移動問題
ルートモーションでうまいことできない挙動なので(うまいことやったらできるのかも)、アニメーション終了時にカプセルの位置を更新する必要がある
とりあえず思いついたのは、コンストラクションで指定ノード(BodyRootとか)とカプセル位置のオフセットを保存しておき、終了時の指定ノードからカプセル座標を逆算する
とやっていたけれど、どうしても1フレームテレポートのグリッチがでる、StateMachine使うともっと顕著になって、結果ブレンドも良くない
物理アニメとかもこのワープでかなりグリッチが出るので、ルートモーションで素直に作り直す
ルートモーションでやる
なんかコントローラーを移動させないと行けない気がしていて、ルートモーション無理とか思い込んでたけど、Rootノードを直接操作すればいい話で普通にできた
・そのままだとY方向のルートモーション聞かないので、アニメーション再生中は一時的にflyingモードに変える、終了で戻す
・コリジョンも無効にする、ただ射撃があるようなゲームだと長時間無敵になってしまうので考える、乗り越えオブジェクト専用のプリセットを作成する等
・ルートモーション、AnimBP全体で使うか使わないか共通の設定なので、特定モーションで使う使わないがあると動きがおかしくなる、必要なアニメで設定を切り替えるようにする
・アニメ終了時に即ルートモーション設定切り替えると、AnimationPhysicsでグリッチが出るので、ちょっとDelayを挟む
次は、のりこえ可能判定の処理を考えてみる、とりあえず2パターン
乗り越えが発生しそうなパターンを見ると、単に乗り越えポイントを指定するのが一番単純かつ確実そう
AND条件で、"プレイヤーが壁の方向を見ている"も入れる
・確実なマップデザインができる
・アセットが膨大になってくると絶対めんどくさい、設定し忘れ出る
2.Traceで自動的に乗り越えられる場所を判定する
・自動でやってくれるので超楽
・グリッチでそう
・アルゴリズム考えるのがいろいろレギュレーション出来てからになる
将来的には2をやり、今回は1でやってみる
変更するのは判定の部分だけなので、乗り越え実行とかは共通の物を使えるはず
残る問題は可変乗り越え高さに対する手のIK
問題が出たら追記