【UE4】C++でExecuteConsoleCommand実行関数ライブラリBP作ってみた
目次
- 目次
- C++で書こうと思ったきっかけ
- C++(UE4)は友達! 怖くないよ!
- staticでselfピンを無くす
- ExecuteConsoleCommandはどこにある?
- WorldContextObjectとは
- メタデータ指定子
- 出来た!
C++で書こうと思ったきっかけ
UE4 のブループリントしばらく使った後にC++ソースコードを書いた時「楽っ!軽っ!早っ!」ってなる。プログラム構築の速さと書きやすさで。BPは便利だけど「ちょっとした計算やプログラム」という場合においてはむしろ時間リソースを食う。エディタが重くなったらなおさら時間かかる#UE4
— 空母に似た形の艦船 イセミト (@isemito_niko) 2017年12月12日
つまるところ↑ツイートの通りなのですが、おおまかな処理等を構築する時にはBPは非常に有効です。しかし計算やループ(forではなく値の)処理を構築する場合はBPだと時間がかかる上に、見た目ブロック状のものが画面いっぱいになりそれらを繋ぐ線で埋まるので管理が難しくなってしまいます。
そして今回の場合はExecuteConsoleCommandをC++で実行させたいと思いました。
というのも、ExecuteConsoleCommandでゲームのクオリティ設定を行いたかったのですが、設定分ExecuteConsoleCommandノードがどんどん伸びていき、線も増えていき、コマンドの管理も時間がかかり始めていた、という背景があります。
というわけで書いてみました。ちなみにUE4でのC++は初です。
C++(UE4)は友達! 怖くないよ!
ガッ
というわけでいきなり噛みつかれました。
まず、当たり前といえば当たり前ですが初見でUE4での書き方が全くわからない。
とりあえず関数ライブラリを作り、Blueprint Function Libraryを親としてC++ファイルを作成
開いてみると...
[SystemFunctionLibrary.h]
[CalcFunctionLibrary.cpp]
ギリギリギリ...
色々調べてみてこちらの記事が見つかりましたので参考に進めていきます。
staticでselfピンを無くす
静的になるので当然ですが、staticにするとselfピンがなくなり、オブジェクトを渡す必要がなくなります。
例えば、
こう記述すれば...
「◯- ターゲット[self]」というピンが表示されますが、
こう記述すれば、
selfピンが消えます。
おっじゃあstatic付けてExecuteConsoleCommand実行するC++コードを書けば良いんだなと思い検索かけてみた所、
このポストにて
こう記述すれば実行できるよ! という情報がありました。
これでC++で ExecuteConsoleCommandを実行しましょう。
怖くない...怖くない...
ガッ
まだ駄目です。
なぜなら、
「GetWorld()」はconst修飾であり、sttaic関数内で使用できません。
「 じゃあconst付ければ使える..?」
と思いきやそうするともちろんstaticは外さなければならず故にselfピンが表示されてしまいます。
ExecuteConsoleCommandはどこにある?
ここで、そもそもExecuteConsoleCommandはどのソースコードにあるのか?
それを参考に書けば良いのではないか?
自力で探してみたものの見つからなかったのでAnswerHubにて質問した所、
ExecuteConsoleCommandと同等の機能をC++で実装したい - UE4 AnswerHub
「KismetSystemLibrary.h」にありました。
...あれ?
書いてあったああああああああああ!!!!
なるほど。
ともあれ、これでExecuteConsoleCommandを直接呼び出すことが可能になりました。
WorldContextObjectとは
ExecuteConsoleCommandを直接呼び出す方法はわかりましたが、今度は見覚えのない言葉が出てきました。
WorldContextObjectとは一体?
まず、WorldContextObjectの型はUObjectであり、これはUE4内全てのオブジェクトの親クラスになるものです。そして、
[C++] WorldContextObject Parameter - UE4 AnswerHub
にて回答者様がおっしゃっているとおり、WorldContectObjectはつまり「GetWorld()」を持つオブジェクトを指す。つまりWorldContectObject(UObject)経由で「GetWorld()」を呼び出しているということになるようです。
そしてExecuteConsoleCommandは渡されたWorldContextObjectからPlayerControllerを取得し、ConsoleCommandを実行しています。
[ExecuteConsoleCommand関数 中身]
メタデータ指定子
では、肝心のWorldContextObjectにはどうやって値を渡せば良いのか?
それは、「メタデータ指定子(meta)」と呼ばれるものを使用します。
上サイト内の「関数メタデータ指定子」に
WorldContext="Parameter"
BlueprintCallable 関数によって使用され、オペレーションが起こるワールドをどのパラメータが決めるかを示します。
という説明があります。
つまりこの場合「どのパラメータが決めるか」というのは「WorldContextObject」であり、故に「"Parameter"」の箇所には「WorldContextObject」を割り当てます。そうすることで、オペレーションが起こるワールドはWorldContextObjectが持つことを示すことになるのかもしれません(勉強不足でまだ完全には理解できていません)。
出来た!
ともあれ、これでstaticしつつExecuteConsoleCommandを呼び出すことが出来るようになりました。
最終的なコードは以下になります。
最初に述べたとおりゲームのクオリティ設定が元々の目的だったのでクオリティ設定のコードになっています。
[SystemFunctionLibrary.h]
[SystemFunctionLibrary.cpp]
【UE4】4.18以降での被破壊メッシュの作成方法
目次
4.18から仕様が少し変わったようです
「被破壊メッシュ作りたいなー」と思い、メッシュを右クリックして「被破壊メッシュを作成」を探していた所...
...ない
無いんです。どこにも。そこで検索かけてみました。しかし...
こことか
物理-Destructible Mesh - UE4 Document@com04
このサイトを見ても、右クリックから生成していました。
そこで、ご存知UE4AnswerHubにて質問してみた所...
4.18からプラグインになった
被破壊メッシュを作ることが出来ない - UE4 AnswerHub
回答者様の情報によると、どうやら4.18から被破壊メッシュは「ApexDestructablePlugin」なるプラグインとなり、デフォルトでOFFになっているそうです。
そこで、エディタの「編集 > Plugins」にて検索かけてみた所...
ありました。これです。
これにチェックを入れると従来通り非破壊メッシュを右クリックから生成することが出来るようになりました!
まとめ
非破壊メッシュは4.18から「ApexDestructablePlugin」プラグイン化。
エディタの「編集 > Plugins」にて「APex」と検索で出て来るのでチェックを入れる。
で使用可能。
【UE4】大量のフラグが存在する場合の管理方法
目次
大量のフラグ変数は死の予兆
『フラグ』:ゲーム制作には無くてはならない存在
ですよね?
しかしゲームの規模が大きくなるに従って使用したいフラグも増えていき、管理する量が多くなっていき...
こんなことに...(ヒィッ
まだ少ないので良い(良くない)ですが、これが20,30と仮に増えていった場合のことは考えたくありません...。
UE4AnswerHub神
UE4ならではの解決策がないか質問してみました。
大量のフラグが存在する場合の管理方法 - UE4 AnswerHub
『Set』!? なんぞ!!!
回答者様に教えていただいた以下サイトによると、
というものがあり、
データの中に何があって何がないかというのを管理するために使う物
だそうです。
Addで追加。Unionで合成。Contains Itemで存在確認。 等々なかなか便利そうです。
要は、
ある型の複数の値を1つの変数として扱う物
ざっくりしたイメージでこんな感じだと思います。
使ってみました
実際に使用してみた所(enum値を用意して使用しています)、
ア...アァ...(神を拝む姿勢
これ↓が、
こう↓
すっごいスッキリ!!
しかもアニメーション遷移の情報を今まで取ってた(依存関係強すぎ)のが不要になったおかげで依存関係を弱くすることが出来ました。
皆も使おう「Set」!
ちなみに
UE4にはBitmaskという仕組みがあり、Bit演算でフラグ管理することも出来ます。
今回私はまだ使用したことなかったSetを用いました。
Bit演算に関しては過去記事にて公開していますので参考までに。
まとめ
「Set」と呼ばれる変数で一括管理できる。
余談
「UE4 Set」と検索しても出てこないので苦労する
【UE4】PlayerController削除の仕方と注意すべきこと
目次
削除したくなった理由
マルチプレイ対応ゲームを実際に制作してみて、「CreatePlayer」にて生成したプレイヤーをあの世に葬り去りたいという欲が生まれてきました。
調べても情報が出てこなかったので質問してみました。
PlayerControllerを削除したい - UE4 AnswerHub
上記回答によると「RemovePlayer」を使用することでプレイヤーをコントローラ毎削除することが出来るようです。
生成したPlayerControllerは確保しろ!
しかし、単にRemovePlayerを使用しても、何故かPlayerControllerが削除されないという事案が発生しました。
「取得に時間がかかっているのか?」「-1指定でCreatePlayerしているのが悪いのか?」等の方法を試しても解決に至らなかったので、再び質問してみた所...
RemovePlayerでPlayerControllerが削除されない - UE4 AnswerHub
回答によると、
PlayerControllerのNetRoleが"ROLE_Authority"が以外だった場合はPlayerControllerが削除されない可能性があります。
別レベルで作成されたPlayerControllerはNetRoleが違うものが設定されている可能性もあります。特にOpenLevelでパーシスタントレベルを変更した際にはご注意ください。
という事で、 どうやらPlayerControllerの持つ情報により取得が意図する状態で行えていないことが原因のようでした。
しかし!
回答者様の検証BPでも行っていますが、CreatePlayerで生成したPlayerControllerを配列内に格納し、RemovePlayer時に取り出しています。
私も同じように予め配列内に確保しておき、RemovePlayerをしてみた所、何の問題もなく正常に全てのPlayerControllerを削除することが出来ました!
つまり、
「GetPlayerControllerで取得できないのなら初めから確保しておけば無問題」
ということでした。
よくよく考えてみれば、後で削除などの操作を行うものを逐一再取得とか非効率といいますか、無駄と言いますか。初めから手元に持っておけばよかったんですね。
まとめ
CreatePlayerで生成したPlayerControllerは確保しておき、RemovePlayerで削除しよう!
【UE4】スキル使用時等の複数のアニメーションを単一のステートで管理する方法
目次
はじめに
UE4にはアニメーションをステートマシンで遷移させる仕組みがありますが、この機能をそのまま使用して複数のアニメーションを管理しようとした場合、あっちこっちに遷移の線が伸びてしまって管理しにくくなります。
複数アニメーションを使用する場面は多々ありますが、これらをたった1つのステートで管理できる方法があります。
以下ではgyazoによる動画を貼っていますがデフォルトでループ再生にならないため、右クリックから「コントロールを表示」で手動で再び再生させる必要があります(ループにチェックを入れればなお良し)。
アニメーションシーケンスに渡すアニメーションを変数化
通常、ステート内にアニメーションステートを追加する場合、以下のようにアニメーションアセットをD&Dして追加すると思いますが(検索かけたり等とか)、
この時、ステート内の「再生◯◯」というノードに渡すアニメーションは変数化することが出来ます。
その方法は、まずステート内に移動し、「再生◯◯」ノードの詳細にある「(As pin) Sequence」にチェックを入れるだけです。
こうすることで再生させるアニメーションを直接指定させることが出来るようになりました。
あとはこのピンから線を伸ばして変数を作成します。
後は、プレイヤー等の外部から「何のアニメーションを再生させるか」を引数として持つ関数を作成して呼び出せるようにしておけば、ステートを複数作成しなくても単一のステートアニメーションとして動作させることが出来ます(型はAnimSequenceBase)。
どう使うか
私の場合は、事前にデータベース化しておいた各Perk(スキル)情報にPerk使用時に再生させたいアニメーションを格納しておき、使用時にアニメーションBPに情報を渡す、という手法をとっています。
これを、解釈が間違っていなければ「アフォーダンス指向」と呼ぶそうです。
以下のサイトの情報を参考にしました。
まとめ
以下のような複数のアニメーションを...
アフォーダンス指向でこんなにスッキリさせることが出来た!
Unreal Engine 4 Fukuoka 勉強会(第一回)で登壇してきました
7/1に開催されたこちら
の勉強会に、UE4ぷちコン用ゲームを制作する際に用いた技術の解説を行いました。
内容は「インターフェース」と「イベントディスパッチャー」です。
個人的にも少し分かりづらかった内容だったので復習出来て登壇する側としてもすごくためになりました。
発表資料はSlideShareにあげていますので、参考になれば幸いです。
複数のフラグを1つの変数のみで管理する
目次
はじめに
先日、ある場でプログラミングにおける「フラグ」の扱いについて学ばせていただいたことがあったので、自分の中での復習として、またこの記事を見てくれた読者の方の学習の一助となればと思います。プログラミングに達者な方は「え?そんなの当たり前でしょ?今更?」な話になるかもしれません。ブログタイトルが如し。
フラグとは?
まず、フラグ(flag, 旗)とは何なのかという話ですが、これは単に「〇〇を満たしているか否か」であると考えて行きます。つまり「ONかOFFか」です。
フラグ情報は一つに
今までの私はフラグの管理を以下のように定義、使用していました。
bool flagA; //int の場合もあり
bool flagB;
bool flagC;
...
しかしこれは必要になった分だけ変数が作られるため非常に非効率であり、管理しにくくなります。定義した変数だけで何十行も使用するなど、余程のことでもない限り避けるべきでしょう(私も人のことを言えた義理ではありませんが...)。
そこで、この対策としてどうするかと言いますと「全フラグを一つにまとめてしまう」事です。具体的には、
unsigned int flags;
の一行で大体のフラグ情報は事足りるようになります。何故かは順を追って説明していきます。
bool[] flags; //intの場合もあり
これでも可能ですが、使用するたびに配列要素の検索・アクセスというオーバーヘッド(ざっくり言えば余分な処理のこと)が発生するため、すっきりするかと言うと怪しくもあります。
[フラグ] = [ON or OFF] = [2通り] = [0 or 1]
冒頭で、フラグ情報はONかOFFで考えると述べました。つまり、1つのフラグ情報の持つパターンはON,OFFの2パターンしかないのです。そこで、それらフラグを「0 or 1」で考えてみることにします。つまり、一つのフラグは
OFF:0 / ON:1
となるわけです。
0と非0
ここで余談ですが、boolも内部的には「0 or 1」で処理されています。しかし正しくは「0 or 非0」で処理されています(boolに限らず)。ここで「非0」と言ったのは、「0でない時『正』とみなされる」からです。プログラム本等でwhileを用いたループ処理のコードで、
while(1){ 略 }
というのを見たことないでしょうか。これは「非0」が「正」であるという仕組みを利用しているのです。その為「1が正である」と勘違いされがち(私もそうでした)なのかもしれませんが、実際は「0以外が正である」というのが正しい認識と言えると思います。
その為、bool値をインクリメントした場合、その時点で0ではなくなるため、ifで処理したとき「正」とみなされます。しかし逆に、デクリメントした場合は「偽」とみなされる保証はありません。なぜならば、「非0」が「正」となるため、値が「0」でない可能性もあるからです。
参考:bool (C++)
フラグの2進数化
さて、フラグを「0 or 1」にすることでどのようなメリットがあるのでしょうか。それは「フラグ情報を2進数化することができる」ということに尽きるでしょう。
2進数とは、0と1の集まりです。
つまり、例えば「生きているか(aliveFlag)」「移動しているか(moveFlag)」「回転しているか(rotateFlag)」「ジャンプしているか(jumpFlag)」等といった情報を、
aliveFlag, moveFlag, rotateFlag, jumpFlag
↓
true, false, false, true
↓
1, 0, 0, 1
↓
1001
と置き換えることができるのです。
「1001(2進数)」は整数になおすと「9」です。4つのフラグ情報がたったこれだけになります。整数にできるということはint変数に格納することができます。これが、フラグの2進数化の魅力と言えるでしょう(実際にはマイナス情報はいらないので、符号情報を消すunsingedを付けます)。
フラグ情報へのアクセス
フラグ情報を整数にする仕組みはわかりましたが、ではフラグ情報の追加や、整数からフラグ情報へのアクセスはどのように行うのでしょうか。
ここで「ビット演算」を用います。
ビット演算についてはこの(複雑な演算子)サイトがわかりやすいかと。
フラグの作成(フラグを立てる)
フラグをまとめるには、もちろん1つ1つのフラグ情報が必要です。では、そのフラグ情報を作成するにはどうするかというと「ビットシフト」という仕組みを用います。具体的には、
1 << n
で作成します。これは「1」、つまり「0001」という基本のビット情報を「指定整数値分左にずらした」ビット情報を作成するということになります。つまり、前項での「生きているか(aliveFlag)」「移動しているか(moveFlag)」「回転しているか(rotateFlag)」「ジャンプしているか(jumpFlag)」といった情報を例にとると、
1 << 0
であれば、「0001」つまり「jumpFlag」をtrueにし、
1 << 1
であれば、「0010」つまり「rotateFlag」をtrueにすると言った感じで情報を作成できます。
フラグの格納
フラグ情報の作成はできるようになりましたが、では、肝心の「情報を1つにまとめる」にはどうすればよいでしょうか。
ここでビットの「OR演算」というものを使用します。
例えば、以下のような情報があるとします、
1 << 0 => jumpFlagをtrue1 << 3 => aliveFlagをtrue
これら情報をunsigned int 型変数「flags」に格納するには、
flags = 0;flags |= 1 << 0;
flags |= 1 << 3;
と記述することで各情報を合成し、以下のような流れで格納させることができます。
1. 0000 //flagsを0で初期化(本来はunsigned int なので32個の0がある)
2. 0001 //1 << 0情報(jumpFlagをtrue)を合成
3. 1001 //1 << 3情報(aliveFlagをtrue)を合成
フラグの比較
では、実際に作成したフラグ情報の中に、あるフラグが立っているかどうかを確認するにはどうすればよいでしょうか。
ここでビットの「AND演算」というものを使用します。
例えば、先ほど作成した変数flagsに格納されている値があるとすると、
flags & 1 << 0 //0001となるflags & 1 << 1 //0000となる
flags & 1 << 2 //0000となるflags & 1 << 3 //1000となる
となります。
あとはこれらをif文内で用いればよいわけです。
しかし注意すべき点として、if文の条件式では0か非0かで判断するとは言っても「0以外の値を無条件に受け入れる」というわけではないので、
if(flags & 1 << 3)
ではなく、
if((flags & 1 << 3) != 0)
等と言うようにきちんと書いてやる必要があります。
(補足)
C++では「 if(flags & 1 << 3)」でも通るようです。
とはいえ関数の返り値をintではなく「bool」にしてると言った場合にはやはり必要となります。
フラグの削除(フラグを折る)
既に存在するフラグ情報から、任意のフラグを折りたい場合はどのようにすればよいでしょうか。
フラグを折る場合は、複数の演算子を組み合わせる必要があります。具体的には、
flags &= ~(1 << 3)
とすれば、以下のような流れで指定したフラグの情報を0(false)にすることが可能となります。
・flags //元フラグ 1001・1 << 3 //折りたいフラグ 1000
1. ~(1 << 3) //折りたいフラグの反転 01112. flags &= ~(1 << 3) //AND演算(1001 & 0111) 0001
まとめ
ビット演算によるフラグの管理の方法をまとめました。
自分自身、最近になるまで演算の方法をよく知りませんでしたので良い勉強になりました。過去の自分のソースコードをぶん殴る機会も出てきそうですね。
また、今回の記事では通しでunsigned int型を使用していましたが、フラグ情報が32個もいらないという場合はもっとビット数の少ない変数で管理するとメモリの節約にもなるかと思われます。
どの型がどのくらいのサイズなのかはここで見れます(1バイト = 8ビット)。