Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
4
Help us understand the problem. What are the problem?

posted at

updated at

UE4でゆうなまを作りたい 第1回

初めに

 タイトルの通り、「ゆうなま」こと「勇者のくせになまいきだ」を作っていく記事になっています。ゆうなまについては、ここでは特に言いませんので、分からない人は調べて下さい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を使っているだけです。特に、今回は記事を書く事は決めていたので、なおさら記入していました。
bunbougu_memo.png

UE4を使って制作する上で

 これ以降はメモの内容を簡単にまとめて記入していきます。今回は、最初~モンスターAIのスポーンまでしていく予定です。画像・動画も上げていきますが、これについてはその当時撮った物と、今回の記事の為に撮った物が存在するので注意して下さい。
 あと、VisualStudio2019の拡張機能なのですが、UnrealMacroGeneratorを入れておく事を非常にオススメします。というのも、UnrealC++ではUFUNCTIONUE_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回実行するノードです

do_n.png

  • DoOnce
    • これも名前の通り1回のみ実行するノードです
    • これは割と使えるノードだと思います。

DoOnce_Example.png

  • Gate
    • 名前の通り、常時入力を切り替えて出力するノードです
    • Enterが常時入力、Openが出力(Exist)を開始する合図、Closeが出力を終了する合図です。Toggleは状態を反転させるものです。
    • 使えなさそうなノードに見えますが、入力操作で変数を使わずに長押ししたい時に使えます。

Gate_Example.png
※ 活用例(長押し)
長押し.png

  • Sequence
    • 実行を分割して順番に実行します。
    • ノードを綺麗に書いたり、途中で止めても大丈夫なように実行を分割したりします。

Sequence_Example.png
※ 活用例(初回処理)
初回処理.png

  • Switch
    • C++のSwitchと同じ機能ですが、引数のSelectionによって動的に切り替わります。

NewSwitchOnInt.png

 詳細はフロー制御(公式サイト)をみて下さい。

プレイヤーを召喚

プレイヤーの初期位置を設定

 まず、起動して最初にカメラが「Player Start」になっているかを確認します。「プレイ > プレイヤーを特別な位置にスポーンする > デフォルトのプレイヤースタート」になっているかを確認します。でないと、カメラの位置が現在位置からスタートしてしまいます。
デフォルトのプレイヤースタート.png

プレイヤーを設定

 ひとまずプレイヤーを召喚します。ブループリントクラスを作成するのですが、必ずPawnCharacterを親クラスにして作成してください。そして、適当なモデルを設定して下さい。
プレイヤー設定.png

 今回は、Characterを親クラスに設定したものを使用します。本当はPawnで作成して、円柱とか球体でも構わないのですが、それでは寂しいので奮発して購入したモデルを設定しています。
 キャラクターの設定は「Mesh(CharacterMesh0)(継承) > メッシュ > Skeletal Mesh」でモデルを設定。同じく「アニメーション > Animation Mode > Use Animation Asset」に設定、「アニメーション > Anim to Play > (任意のアニメーション)」を設定してとりあえず動かします。
キャラクター設定.png
 次に、ゲームモード用のブループリントクラスを作成します。新規ブループリントクラスを作成する際に、Game Mode Baseを親クラスに設定して作成して下さい。
ゲームモード設定.png
 作成したら直ぐに閉じて、ワールドセッティングを開きます。無い場合は「ウィンドウ > ワールドセッティング」で表示されます。
ワールドセッティングがない場合.png
 「ワールドセッティング > Game Mode > ゲームモードオーバーライド」で、作成したゲームモード用ブループリントクラスを設定して下さい。すぐ下に「選択したゲームモード > Default Pawn Class」があるので、そこに作成したキャラクター・ポーン用ブループリントクラスを設定して下さい。
ワールドセッティング設定.png
 もし、Default Pawn Classで作成したクラスが表示されないといった場合は、親クラスの設定が間違っています。作成したキャラクタークラスを開き、「クラス設定 > 詳細 > クラスオプション > 親クラス」でPawnCharacterを選択して下さい。
キャラクターの親クラス設定.png
 これでとりあえずプレイして下さい。すると、作成したブループリントクラスのキャラクターが召喚されています。が、残念ながらこのままではエディター上のようなカメラ操作が不可能になっています。というのも、ゲーム用のカメラ設定になっている為です。なので、プレイしたらプレイの隣にある「イジェクト」をクリックしてください。「マウスカーソルが無いよー」という人は「Shift + F1」を押せばマウスカーソルが返ってきます。この機能は頻繁に使用するので絶対に覚えておいてください。
カメラのイジェクト.png
 とりえあず、これでプレイヤー召喚はできます。が...今回の制作ではプレイヤーとなるキャラクターはいません。それ以外はすべてAIで動くキャラクターになります。ご存知の通り、ユウナマで操作するのはピッケル(つるはし)です。残念ながら「物」です。アニメーションしません。かなしいなぁ~。

BP上での召喚

 今度はブループリント上で別のブループリントクラスをスポーンさせる事にします。といっても簡単です。とりあえず簡単に済ませたいので、レベルブループリントを開きます。開き方は「ブループリント > レベルブループリント > レベルブループリントを開く」です。
レベルブループリントを開く.png
 新しくウィンドウが出るので、BP上でspawnactorと入力すれば「ゲーム > クラスからアクタをスポーンします」をクリック。
スポーンアクタ.png
 実は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にしておくべきで、必要に感じたら変更するべきですね。意味は「常時スポーンする」なんですが、他には「モノに衝突しない近い場所だが絶対スポーンする」「モノに衝突しない近い場所だが無理ならスポーンしない」「常時スポーンしない」があります。
BP スポーンアクタ.png

スポーンアクタはスレッドセーフ?

 何回やってもクラッシュレポートだったので調べてみました。すると、スポーンアクタ関数自体はスレッドセーフ、スポーンするアクターによってスレッドセーフかどうかが異なるらしい。例えば、スポーンしようとしているアクターの当たり判定・物理演算などの影響が考えられます。つまり、アクターは「別スレッドで生成するべきではない」ということになります。

レベルブループリントって何者?

 さらっと、何気なく使ったレベルブループリントなんですが「これ何者?」と思うはずです。私も最初は思っていました。軽く調べた感じでは、「地形関係や設置関係などを司るブループリント」という感じだと思います。なら、最初に作成したゲームモードのブループリントは何かというと、「ルールを管理するブループリント」になってくるのかな~と思います。「今から始めるUE4極め本⑤ 〜ブループリント入門編〜」で分かり易い画像があるので覗いてみて下さい。

便利な機能

 ここで、設定しておくと便利な機能を紹介。

  • エディターを起動する時に常に読み込むマップを指定する

    • 「マップって何者?」という人は、UE4での「マップ」は「シーン」の事だと思ってください。例)ゲームシーン=ゲームマップ
    • 「編集 > プロジェクト設定 > プロジェクト >マップ&モード > Default Maps > エディタのスタートアップマップ」で作成したマップを設定して下さい。
    • こうすると、エディタを起動して設定したマップが最初に読み込まれます。下にある「ゲームのデフォルトマップ」はゲームを起動際に一番最初に読み込まれるマップになっています。 スタートアップマップ.png
  • ブループリントをコンパイルする度に保存する

    • 正直、最初からONになって欲しい機能ですが、残念ながら初期状態ではOFFなので設定しておくことをお勧めします。
    • ブループリント画面を開き「コンパイル > コンパイル時に保存 > 常に保存する」で設定出来ます。 コンパイル時に保存.png

BP上での「オブジェクト参照」の真実

 少しややこしいのですが、ブループリントの「参照」は、C++では「ポインタ(*)」で表示されます。なら、C++での「参照(&)」は、ブループリントではどうなるかというと「リファレンス」になります。ややこしいですね。例えば、C++上で関数を作成した際にアクタのポインタを返すと、ブループリント上では「オブジェクトの参照」に変化しています。
 基本的にC++上でのアクタの管理はポインタで扱うと思います。これはUnreal C++では「ガベージコレクション」が採用されているので、間違いかねないUPROPERTYマクロを設定する事で、UE4へ「この変数はガベージコレクションしてくれよ~」「この変数はブループリント上で使うよ~」という通知がなされます。「ホットリロード」という技術を使って実装されているみたいですね。
UE4へ通知.png

Unreal C++でのポリモーフィズム実装

 基本的には同じように基底クラスのポインタで管理する事になります。

TSubclassOfについて

 UE4には「TSubclassOf」というものがあり、非常に便利で使える機能だと思います。というのも、TSubclassOf<基底クラス>にしておくと、自動で判断して派生クラスのみを表示します。これが、UClass *だと候補を全て表示してしまいます。
TSubclassOf-UClass.png

オブジェクト参照とクラス参照

 作成していると、この二つの違いは何だろうとなった事はありませんか?最初に結論を言うと

  • オブジェクト参照は「実体」
  • クラス参照は「設計図」

です。上記で説明したTSubclassOfUClass*は「クラス参照」で、基底クラスのポインタやクラスのポインタは「オブジェクト参照」になります。なので、スポーンアクタ関数の引数のClassは「クラス参照」で、戻り値が「オブジェクト参照」になっています。
 私自身これらの違いに気づかず、TSubclassOfで変数を持ちポリモーフィズムをやっていました。ただ、意味を知ると基底クラスのポインタでしなければならないですね。意味が違ってくるので。

UE_LOGについて

 Unreal C++にはログ出力として、UE_LOG([UE4] UE_LOGについてあれこれ)が存在します。知っておくことは、ログの詳細度だけでOKです。アウトプットログに設定したログが表示されます。表示方法は「ウィンドウ > 一般 > デベロッパーツール > ログ > アウトプットログ」です。1階層深い所にあるので注意です。
アウトプットログ.png

  • 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 ~ *&」という気持ち悪い書き方で、戻り値にする事が可能です。
関数.png

戻り値

 では、上記の2. 引数では、C++関数上での引数を戻り値にする事も出来ます。では「C++上の戻り値との違いは何?」と思うと思います。

  • ブループリント上での戻り値の数
    • 当たり前ですが、普通は関数の戻り値は1つです5。ですが、ブループリント上では複数個の戻り値が設定出来ますよね?それの実装は上記の2. 引数によって実装されています。
  • ブループリント上では戻り値の名前
    • 勿論、C++上での戻り値もブループリントで対応しているのですが、名前がReturn Valueになってしまいます。
    • なので、戻り値が一つしかなくても、あえてC++上ではvoidにして、引数で対応する事によってブループリント上での名前をキチンと持たせてやるといった事も可能です。
    • その為、基本は引数で対応させることが多くなると思いますが、そうするとC++上で関数を呼び出そうとすると、毎回引数に設定しないといけないのでメンドクサイですね6

関数 戻り値.png

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
    • TArrayのサイズ変更を除いたバージョン。(≒std::array

参考サイト: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

LineTraceByChannel.png

 詳細は「Single Line Trace (レイキャスト) by Channel を使用する」で確認をして下さい。

Trace Channelについて

 これは判定を含むチャンネル(グループ)を決定する機能だと思います。つまり、グループ内でライントレースを行う関数という事でもありますね。これを使えば「ここではこのグループだけ判定を取る。別ではこのグループだけ判定を取る。」といった事が可能になります。つまり、軽量化です。

新規チャンネルの設定方法

 最初は「Visibillity=描画されている物体全て」と「Camera=カメラ内にいる物体全て」の二つしかありませんが、実は新規にチャンネルを追加する事が出来ます。

  1. 「編集 > プロジェクト設定 > エンジン > コリジョン > Trace Channels > 新規のトレースチャンネル」を選択し、「名前・デフォルト応答」を設定して完了です。デフォルト応答に関してはIgnoreに設定しておく事をオススメします。というのも、特定のオブジェクトだけ判定をさせたいがほとんどだと思うので、それ以外のオブジェクト全てにIgnoreへ設定するのはメンドクサイですから。
  2. 判定させたいオブジェクトを選択します。Mesh・カプセルコンポーネント・オブジェクトなどです。
  3. 「詳細 > コリジョン > コリジョンプリセット > Custom」に変更します。
  4. すると「トレース応答 > (作成したチャンネル)」があるので、それだけオーバーラップかブロックに変更します。
  5. Line Trace By Channel関数を使っている所へ移動し、「Trace Channel > (作成したチャンネル)」に変更します。 チャンネルの新規作成.png コリジョン チャンネル設定.png

 以上です。追加するまで結構長いですが、特に2~4は忘れないように気を付けて下さい。「作成したのに反応しない!」なんて事になりかねません。

次回へ続きます

 予想以上に長くなったので次回へと続きます。

あれ?いまだにユウナマを作っている感がないなぁ...。前置きが長くなってしまった...。


  1. この記事を開いている時点で、「ゆうなまを知らない人は0%」説を提唱します。 

  2. というのも専門学校ではC++を使ってゲームを作っていたプログラマーなので、C++を使っていきたいと考えているからです。 

  3. 紹介が適当になった場合は作者がめんどくさくなったと思ってください。 

  4. Unreal C++自体の専門書が少ない問題もありますが…。 

  5. std::pair, std::tuple, 構造体などは無しですよ? 

  6. DirectX9 の数学ライブラリを思い出しますね。D3DXVec3Crossなどの使いづらさは異常です。やはりDirectX::XMVector3Crossの方が絶対使いやすいです。名前が長いですが...。 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
4
Help us understand the problem. What are the problem?