初めに
タイトルの通り、「ゆうなま」こと「勇者のくせになまいきだ」を作っていく記事になっています。ゆうなまについては、ここでは特に言いませんので、分からない人は調べて下さい1。
注意点なのですが、私自身UE4についての知識があまりありません。ですので、「おかしいだろ」「こうした方がいいだろ」ポイントが沢山あると思いますが、優しく指摘してあげてください。それと、ブループリントだけで作らず「Unreal C++」も混ぜて作っていきますので、よろしくお願いします2。
この記事は履歴みたいなもので、「苦戦したポイント」「突っ込みたいポイント」「言いたかったポイント」などをピックアップして紹介する感じです。ですが、最初は誰でも直ぐに出来るように手順をチャンと紹介していきます3。
今回の制作自体「UE4のテスト」兼「Unreal C++のテスト」兼「個人制作」です。やっぱり、専門書を見ながら専門書と同じ作業するよりかは、圧倒的に楽しいですからね。やはり、楽しく作業したいですし、ネットの海をさまよいながら作業するのが結構好きなので、こういった形で勉強する事にしました。なので、専門書は手元にありますが、あえて使わず制作していきたいと思います4。その分学習には時間はかかりますが、そこはテストみたいなモノなので気にしないという事にしておきます。
追記:第2回を上げました
環境
- UE4 Ver 4.26.2
- VisualStudio 2019
- Windows10
ゲームを作る前に
ゲームを模倣して作るなら、元となるゲームを触れる環境は必要です。「動画・攻略サイトで十分だろ!」と言いたい気持ちも分かるのですが、残念ながら、それだけでは情報が不十分なので、元となるゲームソフトも購入する必要があります。何故かというと、動画だけだと自分が気になるところが触れないといった事などがあります。更に、攻略サイトは勿論作る上でも必要なのですが、残念ながら?ユーザー視点での情報がほとんどです。つまり、作る側の情報について書かれている事は余りありません。
兎にも角にも、今回はPSPを中古で買って、ソフトも中古で「初代・or2・3D」を購入しました。PSP...懐かしいですね...。古いゲームソフトを買うのはやはり中古が便利です。
今回に限らず、学習には必ず情報をアウトプット出来る物も必要です。私は、Wordを使いメモしていました。勿論、無料のGoogle Documentで十分です。使える環境にあったのでWordを使っているだけです。特に、今回は記事を書く事は決めていたので、なおさら記入していました。
UE4を使って制作する上で
これ以降はメモの内容を簡単にまとめて記入していきます。今回は、最初~モンスターAIのスポーンまでしていく予定です。画像・動画も上げていきますが、これについてはその当時撮った物と、今回の記事の為に撮った物が存在するので注意して下さい。
あと、VisualStudio2019の拡張機能なのですが、UnrealMacroGeneratorを入れておく事を非常にオススメします。というのも、UnrealC++ではUFUNCTION
やUE_LOG
など、特定のマクロを書かなければいけません。ですが、インテリセンスは中身までは反応しないのでとても苦労します。必ずどこかで誤字します。なので、それを選択するだけで、後は補完してくれるのがこの拡張機能です。
ブループリントでの便利機能
作業する前に便利な機能を知っておくと作業効率が上がるので、知っておきましょう。※使うかどうかは別問題です
ショートカットキー
選択ツール
- ノードを Shift + 左クリック
- ノード選択の追加(何度選択しても追加状態になる)
- ノードをCtrl + 左クリック
- ノード選択の切り替え(選択する毎に選択・解除になる)
ナビゲーション
- Ctrl + ズームイン
- 100%以上にズームイン
一般的なコマンド
- F7
- ブループリントをコンパイル
変数のアクション
- Ctrl + 左クリックでD&D
- 変数を取得
- Alt + 左クリックでD&D
- 変数を設定
ノードのアクション
- Ctrl + W
- 選択したノードを複製
- C
- 選択したノードにコメントを追加
ピンのアクション
- Ctrl + 左クリックで別のピンへD&D
- 接続ピンを移動
ショートカットの作成
- B + 左クリック
- ブランチノード出現(IFノード)
- D + 左クリック
- Delay ノード出現
- S + 左クリック
- Sequence ノード出現
- G + 左クリック
- Gate ノード出現
- F + 左クリック
- For-Each Loop ノード出現
- N + 左クリック
- DoN ノード出現
- O + 左クリック
- DoOnce ノード出現
詳細はブループリントエディタ 虎の巻(公式サイト)をみて下さい。
フロー制御
- DoN
- 名前の通りN回実行するノードです
- DoOnce
- これも名前の通り1回のみ実行するノードです
- これは割と使えるノードだと思います。
- Gate
- 名前の通り、常時入力を切り替えて出力するノードです
-
Enter
が常時入力、Open
が出力(Exist
)を開始する合図、Close
が出力を終了する合図です。Toggle
は状態を反転させるものです。 - 使えなさそうなノードに見えますが、入力操作で変数を使わずに長押ししたい時に使えます。
- Sequence
- 実行を分割して順番に実行します。
- ノードを綺麗に書いたり、途中で止めても大丈夫なように実行を分割したりします。
- Switch
- C++の
Switch
と同じ機能ですが、引数のSelection
によって動的に切り替わります。
- C++の
詳細はフロー制御(公式サイト)をみて下さい。
プレイヤーを召喚
プレイヤーの初期位置を設定
まず、起動して最初にカメラが「Player Start」になっているかを確認します。「プレイ > プレイヤーを特別な位置にスポーンする > デフォルトのプレイヤースタート」になっているかを確認します。でないと、カメラの位置が現在位置からスタートしてしまいます。
プレイヤーを設定
ひとまずプレイヤーを召喚します。ブループリントクラスを作成するのですが、必ずPawn
かCharacter
を親クラスにして作成してください。そして、適当なモデルを設定して下さい。
今回は、Character
を親クラスに設定したものを使用します。本当はPawn
で作成して、円柱とか球体でも構わないのですが、それでは寂しいので奮発して購入したモデルを設定しています。
キャラクターの設定は「Mesh(CharacterMesh0)(継承) > メッシュ > Skeletal Mesh」でモデルを設定。同じく「アニメーション > Animation Mode > Use Animation Asset」に設定、「アニメーション > Anim to Play > (任意のアニメーション)」を設定してとりあえず動かします。
次に、ゲームモード用のブループリントクラスを作成します。新規ブループリントクラスを作成する際に、Game Mode Base
を親クラスに設定して作成して下さい。
作成したら直ぐに閉じて、ワールドセッティングを開きます。無い場合は「ウィンドウ > ワールドセッティング」で表示されます。
「ワールドセッティング > Game Mode > ゲームモードオーバーライド」で、作成したゲームモード用ブループリントクラスを設定して下さい。すぐ下に「選択したゲームモード > Default Pawn Class」があるので、そこに作成したキャラクター・ポーン用ブループリントクラスを設定して下さい。
もし、Default Pawn Class
で作成したクラスが表示されないといった場合は、親クラスの設定が間違っています。作成したキャラクタークラスを開き、「クラス設定 > 詳細 > クラスオプション > 親クラス」でPawn
かCharacter
を選択して下さい。
これでとりあえずプレイして下さい。すると、作成したブループリントクラスのキャラクターが召喚されています。が、残念ながらこのままではエディター上のようなカメラ操作が不可能になっています。というのも、ゲーム用のカメラ設定になっている為です。なので、プレイしたらプレイの隣にある「イジェクト」をクリックしてください。「マウスカーソルが無いよー」という人は「Shift + F1」を押せばマウスカーソルが返ってきます。この機能は頻繁に使用するので絶対に覚えておいてください。
とりえあず、これでプレイヤー召喚はできます。が...今回の制作ではプレイヤーとなるキャラクターはいません。それ以外はすべてAIで動くキャラクターになります。ご存知の通り、ユウナマで操作するのはピッケル(つるはし)です。残念ながら「物」です。アニメーションしません。かなしいなぁ~。
BP上での召喚
今度はブループリント上で別のブループリントクラスをスポーンさせる事にします。といっても簡単です。とりあえず簡単に済ませたいので、レベルブループリントを開きます。開き方は「ブループリント > レベルブループリント > レベルブループリントを開く」です。
新しくウィンドウが出るので、BP上でspawnactor
と入力すれば「ゲーム > クラスからアクタをスポーンします」をクリック。
実はUnreal C++上でスポーンしようとした時期もあったんですが、色々とあって、スポーンはBP上でやるべきとなりました。
-
Class
- スポーンしたいBPクラス
-
Spawn Transform
- スポーンしたいトランスフォーム(座標・大きさ・角度)
- ※これはワールド変換行列で出てくる「S・R・T」ですね。UE4では
Location
/Rotation
/Scale
になっています。
-
Collision Handling Override
(以下CHOで略します)- スポーンする条件
-
Return Value
- スポーンしたオブジェクト参照
CHO
についてなんですが結構な曲者で、CHO
を気にせずスポーンしようとすると「スポーンされねぇぇぇ!」といった事態になるので注意が必要です。基本は、Always Spawn, Ignore Collisions
にしておくべきで、必要に感じたら変更するべきですね。意味は「常時スポーンする」なんですが、他には「モノに衝突しない近い場所だが絶対スポーンする」「モノに衝突しない近い場所だが無理ならスポーンしない」「常時スポーンしない」があります。
スポーンアクタはスレッドセーフ?
何回やってもクラッシュレポートだったので調べてみました。すると、スポーンアクタ関数自体はスレッドセーフ、スポーンするアクターによってスレッドセーフかどうかが異なるらしい。例えば、スポーンしようとしているアクターの当たり判定・物理演算などの影響が考えられます。つまり、アクターは「別スレッドで生成するべきではない」ということになります。
レベルブループリントって何者?
さらっと、何気なく使ったレベルブループリントなんですが「これ何者?」と思うはずです。私も最初は思っていました。軽く調べた感じでは、「地形関係や設置関係などを司るブループリント」という感じだと思います。なら、最初に作成したゲームモードのブループリントは何かというと、「ルールを管理するブループリント」になってくるのかな~と思います。「今から始めるUE4極め本⑤ 〜ブループリント入門編〜」で分かり易い画像があるので覗いてみて下さい。
便利な機能
ここで、設定しておくと便利な機能を紹介。
-
エディターを起動する時に常に読み込むマップを指定する
-
ブループリントをコンパイルする度に保存する
BP上での「オブジェクト参照」の真実
少しややこしいのですが、ブループリントの「参照」は、C++では「ポインタ(*
)」で表示されます。なら、C++での「参照(&
)」は、ブループリントではどうなるかというと「リファレンス」になります。ややこしいですね。例えば、C++上で関数を作成した際にアクタのポインタを返すと、ブループリント上では「オブジェクトの参照」に変化しています。
基本的にC++上でのアクタの管理はポインタで扱うと思います。これはUnreal C++では「ガベージコレクション」が採用されているので、間違いかねないUPROPERTY
マクロを設定する事で、UE4へ「この変数はガベージコレクションしてくれよ~」「この変数はブループリント上で使うよ~」という通知がなされます。「ホットリロード」という技術を使って実装されているみたいですね。
Unreal C++でのポリモーフィズム実装
基本的には同じように基底クラスのポインタで管理する事になります。
TSubclassOfについて
UE4には「TSubclassOf」というものがあり、非常に便利で使える機能だと思います。というのも、TSubclassOf<基底クラス>
にしておくと、自動で判断して派生クラスのみを表示します。これが、UClass *
だと候補を全て表示してしまいます。
オブジェクト参照とクラス参照
作成していると、この二つの違いは何だろうとなった事はありませんか?最初に結論を言うと
- オブジェクト参照は「実体」
- クラス参照は「設計図」
です。上記で説明したTSubclassOf
やUClass*
は「クラス参照」で、基底クラスのポインタやクラスのポインタは「オブジェクト参照」になります。なので、スポーンアクタ関数の引数のClass
は「クラス参照」で、戻り値が「オブジェクト参照」になっています。
私自身これらの違いに気づかず、TSubclassOfで変数を持ちポリモーフィズムをやっていました。ただ、意味を知ると基底クラスのポインタでしなければならないですね。意味が違ってくるので。
UE_LOGについて
Unreal C++にはログ出力として、UE_LOG([UE4] UE_LOGについてあれこれ)が存在します。知っておくことは、ログの詳細度だけでOKです。アウトプットログに設定したログが表示されます。表示方法は「ウィンドウ > 一般 > デベロッパーツール > ログ > アウトプットログ」です。1階層深い所にあるので注意です。
- Fatal
- 致命的なエラー:プログラムがストップして、親の顔より見たクラッシュレポートになると思われます。(使ったことがないのは内緒)
- Error
- エラー:赤色で表示されます。かなり使います。
- Warning
- 警告:黄色で表示されます。個人的にはあまり使わないです。
- Log
- ログ:白色で表示されます。他の情報に埋もれやすいです。
C++で関数作成の注意点
関数作成時に注意しなければならないのが「型・引数・戻り値」です。それと、関数のオーバーロードはUFUNCTION
マクロを付けた瞬間にコンパイルエラーを吐くので注意です。つまり、オーバーロードは使えません。
型
ブループリントで対応している型一覧
- bool
- uint8(unsigned char)
- int32/int
- int64/long
- float
などになります。残念ながら、doubleさんは場外です。個人的にC++側で便利と思っているのが、String(FString)
/Vector(FVector)
/Color(FColor)
です。
参考:ブループリント変数
引数
引数に「const
を付けるか付けないか」「ポインタにするかしないか」「参照にするかしないか」で引数になったり、戻り値になったりします。非常にややこしいポイントです。
\ | 通常 | ポインタ(* ) |
参照(& ) |
---|---|---|---|
int・floatなど | 引数 | ー | 戻り値 |
クラス | ー | 引数 | ー |
クラス + ポインタ | 引数 | ー | 戻り値 |
構造体 | 引数 | ー | 戻り値 |
上のグラフは引数自体にconst
を付けていない場合です。const
付けると、流石に全て「引数」に変化します。ですが、基本は、参照(&
)を付けると「戻り値」になると覚えて下さい。上記以外の書き方はコンパイルエラーになるので注意です。
因みに、「クラス」に関しては「Class ~ *&
」という気持ち悪い書き方で、戻り値にする事が可能です。
戻り値
では、上記の2. 引数では、C++関数上での引数を戻り値にする事も出来ます。では「C++上の戻り値との違いは何?」と思うと思います。
- ブループリント上での戻り値の数
- ブループリント上では戻り値の名前
- 勿論、C++上での戻り値もブループリントで対応しているのですが、名前が
Return Value
になってしまいます。 - なので、戻り値が一つしかなくても、あえてC++上では
void
にして、引数で対応する事によってブループリント上での名前をキチンと持たせてやるといった事も可能です。 - その為、基本は引数で対応させることが多くなると思いますが、そうするとC++上で関数を呼び出そうとすると、毎回引数に設定しないといけないのでメンドクサイですね6。
- 勿論、C++上での戻り値もブループリントで対応しているのですが、名前が
C++のSTLについて
実は、C++のSTLは使う事が可能ですが、当たり前ですがブループリント上に直接呼ぶことは不可能です。なので、UnrealC++オンリーの機能と思った方がいいですね。ただ、自作関数をまたいで間接的に使う事は可能です。STL版とUE4版の両方ある場合は、基本的にはUE4版の方を使った方が良いみたいです。
コンテナクラス
これは皆さんご存知の通り、ちゃんとUE4版も存在しています。基本的には便利になった物と考えて構わないともいます。
-
TArray
- 大体これでどうにかなる(
std::vector
を更に便利にしたもの)
- 大体これでどうにかなる(
-
TQueue
- キュー操作特化(
std::queue
)
- キュー操作特化(
-
TMap
- 紛らわしいが
std::unordered_map
と同じ
- 紛らわしいが
-
TBitArray
- 悪名高い
std::vector<bool>
と同じ
- 悪名高い
-
TList
- リストと書いて単方向リスト(
std::forward_list
)
- リストと書いて単方向リスト(
-
TsortedMap
- これが通常のマップ(
std::map
)
- これが通常のマップ(
-
TSet
- 同じく紛らわしいが
std::unordered_set
と同じ
- 同じく紛らわしいが
-
TBinaryHeap
- ほとんど使った事がない
std::priority_queue
- ほとんど使った事がない
-
TArrayView
- 所有権を管理しない配列クラス。(意味合いとしては
std::string_view
)
- 所有権を管理しない配列クラス。(意味合いとしては
参考サイト:Real Unreal Engine C++ 2017-12 (part-4/5)
<algorithm>
系
これも同じようなものが、UE4にもあります。詳細は「Algo(公式サイト)」を見て下さい。
当たり判定について
よく使われる?Line Trace By Channel
関数についてのあれこれです。この関数はいわゆる「ライントレース=線とオブジェクトの判定」の事です。当たった時の判定もデバッグで見る事が可能になっています。
-
Start
- ラインの始点
-
End
- ラインの終点
-
Trace Channel
- 判定を取るチャンネル
- 詳細は後述します
-
Trace Complex
- 普通は無視してOK
- 通常はOFF
-
Actors to Ignore
- 無視したい特定のアクター
-
Draw Debug Type
- デバッグ用の機能
- ちゃんと当たっているかを視覚的に確認できる機能
-
Ignore Self
- 普通は無視してOK
- 通常はON
詳細は「Single Line Trace (レイキャスト) by Channel を使用する」で確認をして下さい。
Trace Channel
について
これは判定を含むチャンネル(グループ)を決定する機能だと思います。つまり、グループ内でライントレースを行う関数という事でもありますね。これを使えば「ここではこのグループだけ判定を取る。別ではこのグループだけ判定を取る。」といった事が可能になります。つまり、軽量化です。
新規チャンネルの設定方法
最初は「Visibillity
=描画されている物体全て」と「Camera
=カメラ内にいる物体全て」の二つしかありませんが、実は新規にチャンネルを追加する事が出来ます。
- 「編集 > プロジェクト設定 > エンジン > コリジョン > Trace Channels > 新規のトレースチャンネル」を選択し、「名前・デフォルト応答」を設定して完了です。デフォルト応答に関しては
Ignore
に設定しておく事をオススメします。というのも、特定のオブジェクトだけ判定をさせたいがほとんどだと思うので、それ以外のオブジェクト全てにIgnore
へ設定するのはメンドクサイですから。 - 判定させたいオブジェクトを選択します。
Mesh
・カプセルコンポーネント・オブジェクトなどです。 - 「詳細 > コリジョン > コリジョンプリセット > Custom」に変更します。
- すると「トレース応答 > (作成したチャンネル)」があるので、それだけオーバーラップかブロックに変更します。
-
Line Trace By Channel
関数を使っている所へ移動し、「Trace Channel
> (作成したチャンネル)」に変更します。
以上です。追加するまで結構長いですが、特に2~4は忘れないように気を付けて下さい。「作成したのに反応しない!」なんて事になりかねません。
次回へ続きます
予想以上に長くなったので次回へと続きます。
あれ?いまだにユウナマを作っている感がないなぁ...。前置きが長くなってしまった...。
-
この記事を開いている時点で、「ゆうなまを知らない人は0%」説を提唱します。 ↩
-
というのも専門学校ではC++を使ってゲームを作っていたプログラマーなので、C++を使っていきたいと考えているからです。 ↩
-
紹介が適当になった場合は作者がめんどくさくなったと思ってください。 ↩
-
Unreal C++自体の専門書が少ない問題もありますが…。 ↩
-
std::pair, std::tuple, 構造体などは無しですよ? ↩
-
DirectX9 の数学ライブラリを思い出しますね。D3DXVec3Crossなどの使いづらさは異常です。やはりDirectX::XMVector3Crossの方が絶対使いやすいです。名前が長いですが...。 ↩