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
問題が出たら追記
歩行のブレンドスペースの構築
三人称視点のプレイヤーはいろんな方向に動いて、それぞれで足の動きが異なる
代表的な動きを作り、ブレンドスペースを使用して360度動けるようになる、代表的な動きは前後左右の4つだけど、斜め移動も入れて8個あるとかなり見栄えが良くなる
更に移動自体にもシークエンスがあって、スティックの傾きに応じて 歩き(警戒)、歩き(通常)、走り くらいに切り替わると楽しい
とりあえずこの8*3の24アニメーション用意出来たとして、どのようにブレンドしていくかを考える
ブレンド方法、ブレンドスペースを使う以外にも、AnimBPやStateMachineがあるけれど、こちらはどちらかというと一瞬の切り替えの補完で、例えば一連の歩行モーション ⇔ しゃがみ歩行モーション とかに使用すると良さそう
更に、入力がゲームパッドのスティックの時、InputScaleはX軸Y軸で [-1.0, 1.0] なので、かなり都合がよい
ここで問題は
・ゲームパッドの右上入力は(1.0, 1.0)ではなく、(0.7, 0.7)である(物理的にNormalizeされている)
・アニメーションの歩幅の変動が均一でない可能性
→例えば歩き(警戒)は24frameで50cm、歩き(通常)は1m、走りは2.8mになっている
・FLeft → BLeftへの補完の際、足の前後入れ替わりがある
→Left付近の補完で足がめり込むことになる
・キーボード入力はデジタルに0 or 1しか取れない
以下解決策
ゲームパッドの右上入力は(1.0, 1.0)ではなく、(0.7, 0.7)である(物理的にNormalizeされている)
・単に斜め移動のアニメーションをそのように作る
→例えば直進の移動距離が1mなら、Xに1m、Yに1m移動する足の動きを作ると良い
→→ゲーム内で実際に採用されるモーションの確認がしにくい、グリッチが出る可能性がある
アニメーションの歩幅の変動が均一でない可能性
ブレンドスペースにInputScaleの値を利用すると、InputScaleが1/3の時は歩き(警戒)、InputScaleが2/3の時は歩き、1の時は走りのモーションが再生される
この時キャラクターのスピードは、MaxWalkSpeed * InputScaleとなり、モーションの移動距離に緩急がある場合、床とモーションでズレが生じる
・Curveアセットを利用する
こんな風に、スピードとブレンドスペースの位置に応じたグラフを作成する、歩き(警戒)は50cm、歩き(通常)は1m、走りは2.8mの場合
前移動、横移動間で移動距離が異なる、走れる方向は前方のみも同様の方法で対応する、あんまり計算増えてもダメそうだけど
・ていうかルートモーション使う
多分同様の結果、どっちのほうが負荷少ないんでしょうか、知りません
FLeft → BLeftへの補完の際、足の前後入れ替わりがある
足の前後関係がアニメ間で同じでないと綺麗な補完が出来ないのだけれど、左上への移動と左後ろへの移動ではどうしても前後関係が入れ替わってしまう
左右への移動をやってみた時、右足が常に前のパターンと、左足が常に前のパターン2種類があることから想像できる
→我慢する(消極的解決)
→横移動をカニ歩きにする(消極的解決)
キーボード入力はデジタルに0 or 1しか取れない
→デフォのwasdを0.5にして、Shift押下時は1.0とかにする、低速が重要ならそちらもキーで切り替えるようにする
→最後に押されたキーがキーボードかパッドかはこんなノードで取得できる