Udemy Spine の使い方。インポートからアニメーションまで一貫したワークフローの解説 を受講しました
Udemy
Spine の使い方。インポートからアニメーションまで一貫したワークフローの解説
を受講した際のおぼえ書きです。
https://www.udemy.com/course/spine-in-jp/
まずこちらのコースは
Professional版のSpineが必要です、
Essential版では色々機能がつかえず、実際にできることが少ないです。
メッシュ、パス、クリッピング機能等多数の機能が利用できません。
ひざの曲げる方向を逆に指定することもできないです。
そんな、Essential版で学んだことを記述しています。
ボーンの分割)
ボーンを選択→分割ボタンをクリック
で一本のボーンを分割することができます。

フィボナッチにチェックをいれるとこのとおり

IKコンストレイン)
ボーンを二つ選択→IKコンストレインとを選択
作成したい場所をクリックすることで
IKコンストレインを作成することができます。
ポーズを選択することでIKコンストレインを移動することができ、
この通り腕が曲がります。

キーフレームの打ち方)
1フレーム目はすべてのボーンを選択して
回転とトランスレートのキーを打つことがオススメです。
(スケール、シアはなくてもよいです。)

クリーンアップ機能)
アニメーション選択⇔クリーンアップをクリックすることで
不要なアニメーションを削除することができます。

スキン機能)
スキン機能を利用し、色違いキャラをつくることができます。
ツリーからスキンを選択→スキンを作成
で色違いキャラの種類を増やすことができます。
ここでは素材フォルダがcolor2フォルダなので
color2という名前で作っておく必要があります。

差し替えたい素材を選択→スキンプレースホルダーを選択
各スキン用にアタッチメントを複製、アタッチメントの名前を変更にチェックをし実行することで

無事このように、素材違いのキャラを作ることができました。

実際にできたもの。

以上、Spine の使い方。インポートからアニメーションまで一貫したワークフローの解説
について学んだ際のおぼえがきになります。

UE4:アンリアルクエスト初級編サンプル解析
5月17日から22日の間、
UE4を利用した学習コンテスト、アンリアルクエストが行われました。
https://www.unrealengine.com/ja/blog/unrealquest-01-archives?sessionInvalidated=true
初級編サンプルが公開されたのでそちらを解析したのをまとめました。
https://epicgames.ent.box.com/s/a6usckg3g8h4mh4nkl811nt78wpdf423
いきなりブート画面がこれです。
テンションあがります!

ダメージ床)
BP_Spike

床のとげのモデルは、おそらくジオメトリで製作したものと思われ、
9つのとげモデルを1メッシュとしていました。

ダメージ部分はボックスコリジョンコンポーネントですね、
オーバーラップイベントとしてGetPlayerCharacterでプレイヤーかどうかを判別し
ApplyDamageノードを利用しダメージをあたえている。
ただそれだけの処理のようです。

落下床)
BP_FallingFloor

コリジョンのワイアーフレームの太さはこちらのLineThicknessで変更できます。
(これはとても利用価値のある有益な情報です!!)

ボックスにオーバーラップすると
SetTimerByEventノードを利用し一定時間後、物理を有効にすることで落下させています。

落下後レベルをリスタートすることなく、
一定時間後落下床を元の場所にもどし再開する。非常に丁寧な作りになっています。
(しっかりしています)

アニメーション付 落下床)
BP_FallingFloor_WithAnim

落下床のアニメーションは、
タイムラインか?と思いきやSetTimerByEventを利用した、
一定時間ごとにメッシュの向きをランダムで変化させることにより作成しています。
(なんかアニメーションがカワイイです!)

移動床(2点間))
2点の間を補完する移動床です。

コンストラクションスクリプトで
TimeLineComponentに対して、PlayRateを利用しタイムラインの再生速度を指定しています。
(タイムラインの再生速度指定方法は実は知りませんでした。あるだろうけども)

StartPos GoalPos変数に
・インスタンス編集可能
・3Dヴィジェットを表示
の指定を行うことで、ビューポート内でマウスで編集可能にしています!
(こんな方法知らなかった!!)

移動床(スプライン))
スプラインの上を補完する移動床です。
スプラインコンポーネントをいじることで、
移動ルートを変更することができます。

スプラインはGetLocationAtDistanceAlongSplineノードを利用して
スプラインの指定した距離上の座標を取得することができます。
(個人的には、実は2点間移動床の方が新しい発見がありました)

ジップライン)
BP_Zipline

コンストラクションスクリプトでは
スプラインコンポーネントと開始位置と終了位置に
自動的に接触ボリュームが配置されているようにしています。

このように接触ボリュームがアタッチされます

さらにコンストラクションスクリプトでは
スプラインコンポーネント上にスプラインメッシュコンポーネントを追加しています。
これは最終的な挙動には変わらないのですが、
ジップライン上にケーブルが貼っているように見た目上指定しています。

こんどはこっちの方です。
見た目上のケーブルを作っています。
(キングダムハーツのスノーボードステージの空中を張ってるやつとかこれなのかなぁ)

ターザンロープ)
BP_SwingRope

ロープをつかんだ判定。
ロープの持てる部分にボリュームがあるようにはしていません。
※エリア内に入ったら、ロープのつかめる部分が遠かろうがつかめるようになっています

そして、Tickでは
ボリュームにオーバーラップしてから、エンドオーバーラップするまでの間
プレイヤーのCharacterMovementに対しAddForceで移動させるようにしています。

向きもその移動の方向に合わせています。

ではこのケーブルは何なのか?
ターザンロープとはケーブルに捕まるものではないのだろうか?
そう思う人もいるかと思います。
しかしながら、このケーブルはただの飾りです。見た目です。
※ケーブルなしでも透明なターザンロープにつかまりゲームが実現できる。
そのうえで、見た目としてプレイヤーにつなげているだけのものになります。

ボリューム内に入った時にケーブルをプレイヤーに対してアタッチしています。


そのほかBP_SwingRopeでは、
話した瞬間ふわっと飛ばすとか、こだわりの処理が含まれています。
つまり、無くても動く処理も含まれています。
(なかなかの大作ギミックだ)
ヴィジェットBPの生成)
WBP_InGameHUD

スコアなどのヴィジェットBPはどこで生成するべきか?
ゲームモードで生成しても動くし、プレイヤーのBPで生成しても動く、
多くの参考書ではレベルBPで生成しているものも多くあります。
サンプルでは、
「ゲームモードで生成しています」
スコア表示は、ゲームのルールに関数ものなので
ゲームモードのBPで生成する作りにあるのは適切と思います。

エネミー)
BP_Enemy

まずビヘイビアツリーは使用していません。
ビヘイビアツリーは難しいと思うし、必要なゲームでもないです。
(サンプルが使用していないのだから、今後製作するゲームにおいて、
ビヘイビアツリーは利用しない。というのも重要な選択肢とおもいました。)
敵の視覚に入った判定、
サンプルではボリュームを利用して、敵に見つかったかどうかを判別しています。
(一般的にはレイトレースを利用する場合もあります)

見つかったら、
ルート移動と弾を発射を実行しています。
ルート移動はAIMoveToノードを利用しています。

発射した弾に当たったPCは、BP_Playerで
SetAllBodiesSimulatePhysics、SetCollisionEabledノードを利用しラグドール化しています。
また入力の無効化はPlayerControllerのDisableInputノードを利用しています。

またエネミーからプレイヤーへの攻撃は
当たったらダメージというもの製作しています。
敵死亡時の処理、
StopMovementを利用し移動を停止

死亡演出は少々カワイイ死亡処理を採用しているようで、
頭とボディにわからたエネミーを
物理に任せてバラバラになるようにしてあります。カワイイ

ゴール)
BP_Goal
ゴールBPに接触すると、
SetGlobalTimeDilationノードを利用しスロー演出をいれています。カッコイイ

ヴィジェット
WBP_Result
BackgroundBlueを利用して
背景をぼかすような処理をしています。

実際こんな感じに表示されます。

Spacer
7月14日に放送されたアンリアルクエスト解説編中級・上級によると
https://www.youtube.com/watch?v=xxFZraWma68
こんな風にVerticalBoxとHorisontanBoxにSpacerを組み合わせてキレイにレイアウトを作っていた。

解説編中級・上級の動画を見ていて初めて知ったのがこちら、
デバッグフィルタを指定することで実行中に変数の中身を見れるということでした。
これはとても有益な情報でした。


工事中
UE5:オンラインラーニング(Unreal Engine 5 へのアップグレード)
UE5オンラインラーニング
Unreal Engine 5 へのアップグレード
を受講した際のおぼえ書きです。
https://learn.unrealengine.com/course/3754785
UE4プロジェクトのUE5早期アクセスプロジェクトへの移行方法)
UE5の起動ボタンから、UE5早期アクセスをクリックします。

UpgradeしたいUE4プロジェクトを選択し開く

これで簡単にUE5プロジェクトへ移行できてしまいます。

UE5変更点)
メインツールバーが小さくなりました。
これは何気にうれしいです。
いままでプレイボタンが右端にいっちゃってクリックしづらかった。

ボトムバーができました。
こちらもうれしい、
画面が大きく使えます。

アクターパネルの出し方。
作成 > アクターパネルを配置
でいつものアクターパネルを常に表示することができます。

アクターパネルを常に出さないで利用できるようになりました。
画面を大きくりようできますね。

ワールドセッティング、プロジェクト設定はこちらから
設定>ワールドセッティング
設定>プロジェクト設定

コンテンツブラウザのフィルタ指定
このハンバーガーメニューっぽいのをクリックすることでフィルタ指定できます。
(ハンバーガーメニューではないっ)

新しいサウンドシステム)
新しいサウンドシステム、メタサウンドシステムは
プラグインからMetaSoundを検索し有効にすることで利用できます。

メタサウンドの作り方はこちら

ドキュメント)
ドキュメントはこちら
https://docs.unrealengine.com/5.0/ja/
UE5では色々パネルまわりがすっきりした印象を受けました。
いつも利用している、あのパネルはどうやって出すかを理解できるコースです。
UE4:オンラインラーニング(インディーズ フィルム制作での Unreal Engine)
UE4オンラインラーニング
インディーズ フィルム制作での Unreal Engine
を受講した際のおぼえ書きです。
https://learn.unrealengine.com/course/3748536
シーケンサのに関して)
カットごとのトラックに追加方法
+トラック>ショットトラック
をクリックすることで、カットを編集するトラックを追加することができます。

カメラの追加
カメラアイコンをクリックすることで、
カットごとのカメラアクタを追加することができます。

コンポーネントのトラックの追加方法
ここにDroneLaserコンポーネントを持つBPがあったとします。

シーケンサにアクタを追加した際、デフォルトでTransformトラックのみ生成されており。
DroneLaserコンポーネントは出現していません。
でも大丈夫です。
+トラック>DroneLaser をクリックすることで
そのクラスBPがもつコンポーネントをトラックに追加することができます。

パーティクルトグルトラックの追加方法
DroneLaserトラックの
+トラックをクリックすることで

パーティクルトグルトラックを追加することができます。

このような形でパーティクルのアクティベートをきりかえることができます。

カットの分割
右クリック>編集>分割
をクリックすることでカットを分割できます。

フレームレートの「!」表示
フレームレートが関連するカットと指定が違う場合、
注意表示がでてくれます。

ポストエフェクトのオススメパラメータ)
ボリュームの効果範囲指定
ご存じ、InfiniteExtentで距離制限なく、
ポストエフェクトを適応することができます。

レンズ>Bloom
強度:4.1
しきい値:-1.0
マジックアワーっぽくできます

レンズ>Exposure
露出補正で露出を指定できます

レンズ>ChromaticAberration
フリッジエフェクト

レンズ>LensFlares
強度でレンズフレアを指定できます。

レンズ>ImageEffect
グレイン強度
でノイズをいれることができます。

カラーグレーディング>WhiteBalance
温度、色合いでホワイトバランスを指定できます。

カラーグレーディング>Global
彩度

コントラスト

ガンマ補正

レンダリング機能>GlobalIllumination
こちらはスタティックライトを利用しているときに効果を発揮するパラメータです。

フォントの追加方法
・フォントを適当なサイトから取得し(ttfファイル)解凍する
例:https://fontfree.me/


・コンテンツブラウザから右クリック→インポート

・無事インポートが成功する

・ヴィジェットBPを開き
テキストなどのコントロールの詳細
アピアランス>Fontでフォントを変更できる。

PLANEでシーンに文字を配置するメリット
ヴィジェットBPで画面上に文字を配置することもできますが、
PLANEで直接配置するのも一つの手です。
・ポストエフェクトなどが反映されること(ブルームなど)
・シーケンサで透明度を変更したりすることができること
が理由です。

ムービー再生中に、すこしカメラの向きを変えられるテクニック
リアルタイムにレンダリングされているムービーのため、
あらかじめ決められたカメラの向きから少し変更することができます。
(たしか、昔メタルギアとかZOEとかでみたかもしれません)
・シーケンサを再生したときに変数として覚えておく

・入力があった時に
GetActiveCameraComponentノードを利用し取得し
AddRelativeRotationでカメラを回すことができます。

・無事シーケンサ再生中にカメラを回すことができるようになる

これで没頭感のあるコンテンツがつくれるかもしれませんね!
シーケンサのループ再生
OnFinishedにカスタムイベントをバインドすることで
ループ再生を実現できます。

ラーニングを受けるためだけに、
ものすごく重たいアセットのダウンロードを要するのが非常に手間でした。
後半の外部フォントの導入手順、シーケンサのループ再生、
イベント中にカメラ向きのみ動かくテクニックについては有益な情報でした。
導入に時間がかかった割に学びは少ない印象でした。
UE4:一番手っ取り早いエンジンソースコードの取得方法
僕なりに試行錯誤して、
最短でエンジンソースコードを手に入れる方法を見つけたため、
そのメモ書きです。
※正確な取得方法やPerforceを利用し,
指定バージョンのソースコードにアクセスする方法ではないです
僕なりの試行錯誤手順を明記してあります。
まずは参考にしたお世話になってるヒストリア様のサイト
https://historia.co.jp/archives/231/
こちらも参考にしました。
手順)
・UnrealEngineアカウントとGitHubアカウントの紐づけ
https://www.epicgames.com/account/connections
へアクセスし、
接続>アカウント>GITHUBをクリック
UEとGitHubを紐づけます。

そして登録したメアドにメールが送られてくるので
Joinのリンクから進めると、
UnrealEngineのエンジンソースコードにアクセスできるようになります。
うまくいくとメールが送られてきます。
・Web上からソースコードを取得する
https://github.com/EpicGames/UnrealEngineへアクセスし
Code>DownloadZIPをクリックし取得します。
(紹介するのは一番手っ取り早い方法です。)

・ファイルの解凍
ダウンロードしたUnrealEngine-release.zipを解凍します。
これには超時間がかかります。

・短いパスの場所へ移動
次の工程(Setup.batを実行)の際に
デスクトップで展開するとパスが長くてエラーが出てしまうので、
短いパスの場所へ移動しておきます。

・Setup.batの実行
Setup.batを実行し完了するまで待つ

・GenerateProjectFiles.batの実行
ここで会社などでUE4を利用している方にはおなじみの
GenerateProjectFiles.batを実行します。
でもどういうことかエラーが出てしまいます!!
でも大丈夫!これはエラーログに従えば解決できます。

言われた通り
https://aka.ms/msbuild/developerpacks へアクセス
(自動的に
https://docs.microsoft.com/ja-jp/dotnet/framework/install/guide-for-developers
にリダイレクトされるので)
ログに従い.net Framework 4.6.2 のリンクをクリックするとー

net framework4.6.2 のダウンロードサイトに移動します。
(https://dotnet.microsoft.com/download/dotnet-framework/net462)
DeveloperPackをクリックし
.net framework4.6.2 のDeveloperPackを取得しインストールすれば解決しました。

・再びGenerateProjectFiles.batにチャレンジ
再度GenerateProjectFiles.batを実行すると
無事UE4.slnのソリューションファイルを作成することができました。

・UE4のビルド
ビルドにはかなり時間がかかります。
実行するとエディタが起動します。
※この段階でフォルダ容量が100GBを超えます。
容量が足りないとビルドが通りません。

・プロジェクトの作成
指定したパスにプロジェクトを作成します。

プロジェクトができました。

・プロジェクトのVisualStudioプロジェクトの作成
メニューバー>ファイル>新規C++クラス
を選択し何でもいいからクラスをつくることで
2つ目のVisualStudio(プロジェクトのVisualStudioプロジェクト)
を作ります。
※そして後で無駄に作ったクラスは消しましょう。
少々変な手順ですが、
詳細は
https://learn.unrealengine.com/course/3548019
の動画を参照のこと

無事プロジェクトができました。

・プロジェクトのVisualStudioプロジェクトのビルド
2つ目のVisualStudioプロジェクトをビルドするとー

プロジェクトのソースコードも含んだエディタが起動します。

手っ取り早いとはいえ長かった・・
手っ取り早いには違いないがSSD容量がものすごく圧迫された。
UE4:第15回UE4ぷちコンに応募しました。
今回もヒストリア様で行われている
UE4ぷちコンに応募しました!
https://historia.co.jp/ue4petitcon15
さっそくですができたものはこちら
youtu.be
テーマは"かわる"ということなので
自身を"気体"に変化できるという無敵能力を持った主人公による
潜入ステルスアクションゲームを開発しました。
かわる。なので最初は
変身スーパーヒーローもので!とか思っていましたが・・
変身するにはしますが、細かく変身と解除を繰り返して
ミッションをクリアする作品を制作しました。
ルームBP)
ダンジョンをつくるのが面倒だったのでー
ドロップし、拡縮するだけで自動で壁と床が生成できる部屋BPを作成しました。

やってることとしては、コンストラクションスクリプトで
メッシュコンポーネントを追加し編集の段階で壁や床を作るようにしています。

StaticMeshComponentを追加ノードを利用して編集毎に追加しています。

はたしてUE4では、
こういったコンストラクションスクリプトの使い方で正しいのか?
というとそこは不明。使えるには使えます。
※ライティングのビルドまわりがうまく機能していないかもしれないです。
これはちょっと調べたほうがが良いかもです。
ワープBP)
ワープコリジョンの位置調整に関してはスプラインコンポーネントの始点と終点に
自動でコリジョン位置が調整されるBPを配置することで対処しました。
(これもコンストラクションスクリプトで行っています)

ドロップしてスプラインを編集するとこんな感じ。
(スプラインの編集方法はAltを押しながらエディットポイントを
調整することで自由にカーブをつくれます)

非破壊メッシュ)
オブジェクトの破壊に関しては以前書いた
非破壊メッシュのやりかたのおぼえ書きを参照のこと
UE4:非破壊メッシュのやりかた - とあるゲームプログラマの挑戦と敗北の歴史

演出過多)
あまりにもテーマ感が薄かったので
テーマに沿ってる感をわかるよーにしました。
変身UIを表示、変身時カメラが寄るように修正。などなど

マテリアル)
変身時に固体から気体に対して徐々に変化するマテリアルをつくり
それをフィーチャーした作品にするよていでしたが。
どうせ一瞬だったりするので、残念ながら小さくに収まっている作品になっています。
それにいちいち長い変身演出見せられても飛ばしたくなる。というのもあり


レベルデザイン)
レベルデザインへの挑戦、
マップ設計のようなところが、製作中とてもおもしろかったです。
ダクト、ターゲット、エネミー、ダメージ床、自動発砲装置といった
多様なギミックがうまい具合にかみ合っている仕様でないと、
ゲームとして面白くならないので、ルールづくりみたいなところは結構大事でした。
うーん、ここは気体にならないとダメージを受けてしまうマップ設計)

自動発砲装置にダメージ床でエネミーも・・でもその先にダクトがあるぞ!なマップ設計)

ルートによっては敵との戦闘を回避できるマップ設計)

そして安全なエリアからターゲットを破壊!

ダクトに入ったが最後、ダメージ床なマップ設計)
※これがやりたいためにダクトを通った後は強制変身OFFルールにしました。

ダメージ床怖いけど、勇気を出して飛び込めば先に進めるのでは・・なマップ設計)

いろいろつくったけど、基本的には俯瞰からのカメラ映像なので、
コンパクトにまとまっちゃってる感はある作品だと思います。
PCがカメラに寄っても問題ないゲームデザインであれば
もうちょっとダイナミックな絵ができたかもしれないですね。
なかなかレベルデザイン業務が楽しい開発でした。
二次創作系のネーミングなのでNGっていわれたら、
しれっとタイトルは変えましょう。(内容ちがうし)
開発中はエアーマンが倒せないのBGMが頭の中で流れていました!
UE4:非破壊メッシュのやりかた
非破壊メッシュにかんする
ApexDestructionプラグインを利用した
UE4標準の破壊表現のやり方のおぼえ書きです。

プラグインの有効化
Apex Destructionプラグインを有効にし再起動します

非破壊メッシュの作成
・破壊したいメッシュを右クリック
・非破壊メッシュを作成をクリックする
(図ではSM_TableRoundを破壊する想定です)
・非破壊メッシュウィンドウが表示される
・フラクチャメッシュをクリックし割っておく。
メッシュが細かいと時間がかかります。

・無事スタティックメッシュと同じフォルダにできています。

壊れるアクターBPの作成
・コンテンツブラウザを右クリックし、ブループリントクラスを選択
・Actorのクラスを選択、
・壊す用のアクター(BP_Actor)を作成する

壊れる前のスタティックメッシュの追加
作成したBP(BP_Actor)を開き
・コンポーネントを追加を選択
・StaticMeshコンポーネントを追加
・スタティックメッシュに壊す前のメッシュ(SM_TableRound)を指定

イベントグラフの作成
(図は一定時間後破壊する例)
・DestroyComponentノードで現在のStaticMeshコンポーネントを削除
・Add Componentと入力すると出てくる
クラスごとにコンポーネントを追加ノード を作成する
・Classピンに DestructableComponent を指定し
DestructableComponentを追加ノード に変化させる
・SetDistructibleMeshノードを作成し
NewMeshピンには先ほど作成した非破壊メッシュ(SM_TableRound_DM)を指定
・ApplyDamageノードで一発ダメージを与えて壊すようにする

レベルに配置しプレイすると
一定時間後ごらんのとおり破壊されます。

おしまい。
UE4:オンラインラーニング(ブループリントによるツインスティック シューター)
UE4オンラインラーニング
ブループリントによるツインスティック シューター
を受講した際のおぼえ書きです。
https://learn.unrealengine.com/course/2855684
スカイライトのキューブマップ指定
・ライトの SourceType を SLSSpecifiedCubemap に変更
・一例として Cubemap を HDRI_Epic_Courtyard_Daylight に変更
するとキューブマップを指定することできます。

ちなみにキューブマップを開くと
こんな風なepic本社だったりします。

動的にシーンの輝度調整を無効にする方法
・ポストプロセスボリュームを配置
・レンズ>Exposure の
最小輝度、最大輝度を1.0にすることにより
シーンの明るさが動的でないようにできます。

このコースでは Actor Pawn Character のに関して解説がなされており。
利用された図が非常にわかりやすいです。
Actor - ワールド配置物
+ Pawn - 操作可能なもの
+ Character - 歩行可能なもの、MovementComponentを持っています。
Component - Actorの部品
Controller - PlayerController AIController があり Pawnクラスが持っています
GemeMode - ゲームのルールです。

※動画からパクった図
親クラスの変数の表示方法
・目のマークをクリックし
・継承した変数を表示にチェックを入れることで
親クラス(コースではBaseCharacter)の変数を表示することができます。

SpringArmコンポーネント
SpringArmコンポーネントはカメラを子階層に追加することで、
カメラまでの相対的な距離を指定するコンポーネントです。
・DoCollisionTestのチェックを外すことでコリジョンテストを無効にできます。
・InheritPitch Yaw Roll のチェックを外すことで回転を無効にできます。

使用例として、こんな感じに親子階層を作って利用します。

ProjectileMovementコンポーネント
アクターを発射物としてあつかうための専用コンポーネントです。
IntialSpeedに速度を入力することができます。
こういった簡単な処理は、ついつい自前で製作してしまいそうになりますが、
すでに出来上がっているものがあるのでこちらを利用しましょう。

タグ付けにる判別
プレイヤーが銃などを利用し攻撃した時の
発射物が接触したものがエネミーなのかどうかを判別することがあります。
その際、方法のひとつとして ActorTag を利用し判別することができます。
設定方法)
・クラスのデフォルトを選択
・Tagにタグ名を記述(ここではfriendlyとしています。)

判別方法)
・ActorHasTagノードを利用することで
接触物のアクタータグを判別することができます。

プレイヤーの死亡と再生成の仕方
事前にGameModeクラスに
新しいプレイヤーの生成処理 & 操作キャラのバトンタッチ処理
を作っておく必要があります。
バトンタッチは Possessノードを利用します。
そしてPlayerクラスでは死亡した際に
GameModeクラスに制作した 再生成&バトンタッチ処理 を呼び出すようにし、
自身をDestroyすることでプレイヤーの死亡とリスポーン処理を実現できます。

※ここで重要なのはゲームのルールに関する処理は
GameMode に書くべきということです。
こういった処理はついついレベルBPに書いてしまいがちです。
実際、私はそうしてしまっていることがよくありました。
本コースではGameModeに実装する方向で解説されています。
(エネミー生成のトリガー処理などもGameModeに書くべきです。)
ボックスボリューム内のランダムな座標の取得方法
画像のようにRandomPointInBoundingBoxノードを利用すると
ボリューム内のランダムな位置を楽に取得することができます。

アクターを一定時間後破棄する方法
発射物を一定時間後に自動削除したい場合などに利用します。
・クラスのデフォルトを選択
・アクタ>InitalLifeSpawn
に書きされるまでの時間を指定することで自動的に破棄することができます。
簡単な処理なので意外と自分で作ってしまいそうなところですが、
こういった機能は最初から存在するため利用した方がよいです。

ブレンドスペース
ブレンドペースは複数のアニメーションを
値に応じてブレンドする機能です。
軸の設定方法)
アセット詳細タブの
水平軸の Name Minimum Maximum の値
垂直軸の Name Minimum Maximum の値
をそれぞれ入力することで
ブレンドする際のグラフの軸を指定することができます。

グラフの設定方法)
あとはアセットタブから
グラフ上のポイントごとのモーションを配置していきます。

移動方向とキャラの向きの差分の取り方
・GetVerocityノードを取得しRotationFromXVectorで移動向きを取得
・GetControlRotationからポーン自身の向きを取得
・Deltaノードを利用
すると2角度間の差分を取得することができます。
GetControlRotationで自身の向きを取得できるのは発見でした。

複数の死亡モーションからランダムなものを再生
整数値でのブレンドポーズノードを利用すれば
アニメーションBPで複数のモーションから
ランダムなものを一つ再生することができます。

※ピンが足りないときは
右クリック>ブレンドピンを追加
でピンを増やすことができます。
ソケットの追加方法
スケルトンに対し、武器などをアタッチする際の追加ポイントを
をソケットといい、自由に追加することができます。
・アニメーションシーケンスを開く
・スケルトンタブを選択し
・適当なボーンを右クリック
・ソケットを追加を選択
するとアタッチポイントを追加することができます。

プレビューアセットの指定
さらにデバッグで武器をアタッチさせ確認することができます。
装備中のイメージを確認しやすいので
もしイメージと違ったら、ソケット位置を調整することができます。
・ソケット右クリック
・プレビューアセットを追加を選択
・確認したいアセットをリストから選択する

イメージとちがったらソケット位置を調整しましょう

プレビューして問題ないようなら
ゲーム中ではAttachActorToComponentノードを利用しアタッチします。

アニメーションBPの子ブループリント
アニメーションBPを全キャラ分、
たとえば、人型、剣士人型、武道家人型、魔法使い人型と
共通する部分もあるのに、全部作らなくてはならないのかというと
そうではなく、
アニメーションBPも子ブループリントを作ることができ、
違う部分をオーバーライドすることで量産することができます。
・子ブループリントをひらく
・アニメーションBPを右クリック
・子ブループリントクラスをを作成を選択
でキャラのABPをもとにした
エネミーのABPを作成することができます。

・子ブループリントをひらく
・アセットオーバーライドタブを選択
・差分になる部分の上書き値を設定
この手順で子ブループリントの差分の部分を指定できます。
※この機能は正直しりませんでした。
てっきり全部根性で作るのかと思っていました。

入力を無効化する方法
方法はいくつかありますが、このコースでは
プレイヤーはDisableInputノードを利用し入力を無効化し
エネミーはDetachFromControllerPendingDestroyノードを利用し
コントローラを破棄することで移動を無効化しています。
プレイヤー操作無効化)

エネミーの移動無効化)

フィル指定
ヴィジェットBPのフィル指定にチェックをいれると
のこる領域を埋め尽くすように配置できます。

パッケージTIPS
プロジェクト設定>パッケージ化>圧縮およびクック済みのパッケージを作成
にチェックを入れることでファイルサイズが小さくなります。
プロジェクト設定>パッケージ化>パッケージ化されたビルドに含めるマップのリスト
にパッケージ対象のレベル一覧を作成することができます。


パッケージは周知のとおり
メニューバーのファイル>プロジェクトをパッケージ化
から作成します。

出来たやつ)
youtu.be
このコースでは空のレベルから作成し
最速でシンプルなシューターゲームを作るまでの手順を解説しています。
内容は幅広くC++についての解説も入っているほどです。
講師のテンションが高いです!!
自動輝度調整の無効化、アクタとポーンの関連性、タグ付けにる判別、
ProjectileMovement、操作キャラの変更、ブレンドスペース、アタッチ、
アニメーションBPの子BPの作り方、入力の無効化、ヴィジェットBP
など非常に幅広く学ぶことができます。
ゲームのルールをレベルBPではなくゲームモードに実装しているところは
これまでの私が作ってきた部分を見直す重要な情報と思えました。
またアニメーションBPを継承して使用する方法など
あたしい発見もありました。
UE4:オンラインラーニング(シネマティックショット制作のためのシーケンサートレーニング)
UE4オンラインラーニング
シネマティックショット制作のためのシーケンサートレーニング
を受講した際のおぼえ書きです。
https://learn.unrealengine.com/course/2573344
焦点面をデバッグで表示
カメラデバッグ焦点面の描画にチェックをいれることで
焦点面をデバッグで表示することができます。

そのカットのみの一時的なカメラ生成
シーケンサのカメラマークをクリックすると
そのカットのみスポーンされる
一時的なアクタを生成することができます。

カメラカットの選択方法
カメラカットの+マークをクリック、
新しいバインディングから
有効なカットを追加することができます。

UE4:ImGui導入手順
デバッグ用GUI(ImGui)の導入手順に関するメモです。
ImGuiを導入するとUE4でデバッグ用のウィンドウが楽につくることができます。
とはいっても・・
おかずさんのブログを参考に(いやむしろ8割ぐらいコピって)
自前で試して学習した内容なので正確な情報はそちらを見ましょう。
なんならコードそのまま。
pafuhana1213.hatenablog.com
GuiTestのプロジェクトを作成します。
C++で作成、ここでは例としてプロジェクト名をGuiTestとしています。

ImGuiのソースコードはこちらから取得してきます。
Code>DownloadZIPで取得
https://github.com/segross/UnrealImGui

落としてきたファイルはプロジェクトのあるフォルダに
GuiTest\Plugins\ImGui とフォルダを作成し、
そこに落としてきたファイルをすべて入れます。

いつも通りファイルが追加されたら
GenerateVisualStudioProjectFilesを実行しVisualStudioプロジェクトを更新します。

VisualStudioプロジェクトを起動すると
無事ソースが組み込まれていることを確認できます。

無事ビルドが通るはずなので実行し、
ImGuiプラグインが有効になっていることを確認します。

プレイし ImGui.ToggleDemo を実行することで
ウィンドウを出すことができた。

デフォルトでマウスが効かないようになっているので
ImGui.ToggleInput を実行することでマウスがきくようになります。

いちいちImGui.ToggleInputするのが面倒くさいときの対処手順
・プロジェクト設定を開く
・ImGui>ToggleInput に適当なキーボードショートカットを割り振る
・ImGui>ImGuiInputHandlerClass を ImGuiInputHandler に設定
すると ImGui.ToggleInput をしなくてもよくなります。

ImGuiのデモの表示方法はわかったので、
次に自作のウィンドウの作成方法を試してみました。
プロジェクトのBuild.csファイルを修正し ImGui のモジュールを追加します。
ImGuiTest.Build.cs)
using UnrealBuildTool; public class GuiTest : ModuleRules { public GuiTest(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "ImGui" }); PrivateDependencyModuleNames.AddRange(new string[] { }); } }
ImGuiCommon.h、ImGuiTest.h、ImGuiTest.cpp
ファイルを作成しそれぞれ以下のコードを入力し試してみた。
※参考サイトのコードそのままですが・・

※GenerateVisualStudioProjectFilesを実行はおわすれなく。
ImGuiCommon.h)
#pragma once #ifdef IMGUI_API #define WITH_IMGUI 1 #else #define WITH_IMGUI 0 #endif #if WITH_IMGUI #include <ImGuiModule.h> #include <ImGuiDelegates.h> #include <imgui.h> #endif
ImGuiTest.h)
#pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "ImGuiCommon.h" #include "ImGuiTest.generated.h" UCLASS() class GUITEST_API AImGuiTest : public AActor { GENERATED_BODY() public: AImGuiTest(); virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void Tick(float DeltaTime) override; #if WITH_IMGUI void ImGuiTick(); #endif };
ImGuiTest.cpp)
#include "ImGuiTest.h" AImGuiTest::AImGuiTest() { PrimaryActorTick.bCanEverTick = true; } void AImGuiTest::BeginPlay() { Super::BeginPlay(); #if WITH_IMGUI FImGuiDelegates::OnWorldDebug().AddUObject(this, &AImGuiTest::ImGuiTick); #endif } void AImGuiTest::EndPlay(const EEndPlayReason::Type EndPlayReason) { Super::EndPlay(EndPlayReason); #if WITH_IMGUI FImGuiDelegates::OnWorldDebug().RemoveAll(this); #endif } void AImGuiTest::Tick(float DeltaTime) { Super::Tick(DeltaTime); #if WITH_IMGUI ImGui::Begin("ImGui Debug Order Test"); ImGui::Text("Actor Tick: Actor = '%ls', World = '%ls', CurrentWorld = '%ls'", *GetNameSafe(this), *GetNameSafe(GetWorld()), *GetNameSafe(GWorld)); ImGui::End(); #endif } #if WITH_IMGUI void AImGuiTest::ImGuiTick() { ImGui::Begin("ImGui Debug Order Test"); ImGui::Text("ImGui World Tick: Actor = '%ls', World = '%ls', CurrentWorld = '%ls'", *GetNameSafe(this), *GetNameSafe(GetWorld()), *GetNameSafe(GWorld)); ImGui::End(); } #endif
ビルドがとおり実行すると
ImGuiTestアクターというアセットが作られています。
アクターのスポーンと同時にウィンドウが表示される仕組みになっています。
レベルに配置してプレイすると
無事自作ウィンドウが表示されていることを確認できました。

サンプルのパクり方!
ImGuiの仕様のコツはimgui_demo.cppからパクってくるのがコツです。

適当にコードをコピーするだけでこんなウィンドウを自作することができました。

なおimgui_demo.cppからもってきたソースコードです。
ImGuiTest.h)
#pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "ImGuiCommon.h" #include "ImGuiTest.generated.h" UCLASS() class GUITEST_API AImGuiTest : public AActor { GENERATED_BODY() public: AImGuiTest(); virtual void Tick(float DeltaTime) override; };
ImGuiTest.cpp)
#include "ImGuiTest.h" AImGuiTest::AImGuiTest() { PrimaryActorTick.bCanEverTick = true; } void AImGuiTest::Tick(float DeltaTime) { Super::Tick(DeltaTime); #if WITH_IMGUI if (ImGui::TreeNode("Basic")) { static int clicked = 0; if (ImGui::Button("Button")) clicked++; if (clicked & 1) { ImGui::SameLine(); ImGui::Text("Thanks for clicking me!"); } static bool check = true; ImGui::Checkbox("checkbox", &check); static int e = 0; ImGui::RadioButton("radio a", &e, 0); ImGui::SameLine(); ImGui::RadioButton("radio b", &e, 1); ImGui::SameLine(); ImGui::RadioButton("radio c", &e, 2); // Color buttons, demonstrate using PushID() to add unique identifier in the ID stack, and changing style. for (int i = 0; i < 7; i++) { if (i > 0) ImGui::SameLine(); ImGui::PushID(i); ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(i/7.0f, 0.6f, 0.6f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(i/7.0f, 0.7f, 0.7f)); ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(i/7.0f, 0.8f, 0.8f)); ImGui::Button("Click"); ImGui::PopStyleColor(3); ImGui::PopID(); } // Use AlignTextToFramePadding() to align text baseline to the baseline of framed elements (otherwise a Text+SameLine+Button sequence will have the text a little too high by default) ImGui::AlignTextToFramePadding(); ImGui::Text("Hold to repeat:"); ImGui::SameLine(); // Arrow buttons with Repeater static int counter = 0; float spacing = ImGui::GetStyle().ItemInnerSpacing.x; ImGui::PushButtonRepeat(true); if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; } ImGui::SameLine(0.0f, spacing); if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; } ImGui::PopButtonRepeat(); ImGui::SameLine(); ImGui::Text("%d", counter); ImGui::Text("Hover over me"); if (ImGui::IsItemHovered()) ImGui::SetTooltip("I am a tooltip"); ImGui::SameLine(); ImGui::Text("- or me"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::Text("I am a fancy tooltip"); static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f }; ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr)); ImGui::EndTooltip(); } ImGui::Separator(); ImGui::LabelText("label", "Value"); { // Using the _simplified_ one-liner Combo() api here // See "Combo" section for examples of how to use the more complete BeginCombo()/EndCombo() api. const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" }; static int item_current = 0; ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); ImGui::SameLine(); } { static char str0[128] = "Hello, world!"; ImGui::InputText("input text", str0, IM_ARRAYSIZE(str0)); ImGui::SameLine(); static char str1[128] = ""; ImGui::InputTextWithHint("input text (w/ hint)", "enter text here", str1, IM_ARRAYSIZE(str1)); static int i0 = 123; ImGui::InputInt("input int", &i0); ImGui::SameLine(); static float f0 = 0.001f; ImGui::InputFloat("input float", &f0, 0.01f, 1.0f, "%.3f"); static double d0 = 999999.00000001; ImGui::InputDouble("input double", &d0, 0.01f, 1.0f, "%.8f"); static float f1 = 1.e10f; ImGui::InputFloat("input scientific", &f1, 0.0f, 0.0f, "%e"); ImGui::SameLine(); static float vec4a[4] = { 0.10f, 0.20f, 0.30f, 0.44f }; ImGui::InputFloat3("input float3", vec4a); } { static int i1 = 50, i2 = 42; ImGui::DragInt("drag int", &i1, 1); ImGui::SameLine(); ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%"); static float f1=1.00f, f2=0.0067f; ImGui::DragFloat("drag float", &f1, 0.005f); ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns"); } { static int i1=0; ImGui::SliderInt("slider int", &i1, -1, 3); ImGui::SameLine(); static float f1=0.123f, f2=0.0f; ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f"); ImGui::SliderFloat("slider float (curve)", &f2, -10.0f, 10.0f, "%.4f", 2.0f); static float angle = 0.0f; ImGui::SliderAngle("slider angle", &angle); // Using the format string to display a name instead of an integer. // Here we completely omit '%d' from the format string, so it'll only display a name. // This technique can also be used with DragInt(). enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT }; const char* element_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" }; static int current_element = Element_Fire; const char* current_element_name = (current_element >= 0 && current_element < Element_COUNT) ? element_names[current_element] : "Unknown"; ImGui::SliderInt("slider enum", ¤t_element, 0, Element_COUNT - 1, current_element_name); ImGui::SameLine(); } { static float col1[3] = { 1.0f,0.0f,0.2f }; static float col2[4] = { 0.4f,0.7f,0.0f,0.5f }; ImGui::ColorEdit3("color 1", col1); ImGui::SameLine(); ImGui::ColorEdit4("color 2", col2); } { // List box const char* listbox_items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; static int listbox_item_current = 1; ImGui::ListBox("listbox\n(single select)", &listbox_item_current, listbox_items, IM_ARRAYSIZE(listbox_items), 4); } ImGui::TreePop(); } #endif }
imGuiはとても便利です。
プレイ中UI:ヴィジェットブループリント
プレイ中のデバッグ用UI:ImGui ←☆New
プレイ前のデバッグ用UI:エディタユーティリティヴィジェット
といったところでしょうか。
