初めに
この記事はUnrealEngineで初めてプログラミング・ビジュアルスクリプトに触れた人に向けたものとなります。既にUE4・UE5でBPをある程度触っている方にはほとんど参考になりません。
またC++全くわかってない勢が今後の自分のような人の為書いているので、独自解釈などが入っている可能性があります。なにか間違いがあればご連絡ください。
基礎知識として
猫でもわかるUE4を使ったゲーム開発超初級編
1 https://youtu.be/ztv4OPc_o6g まずはプロジェクトを作ってUE4エディタを触ってみよう!
2 https://youtu.be/JrQh1lVrEjM Blueprintをさわってみよう
3 https://youtu.be/Wd8Akctzhbc コリジョンを使ってコインを拾ってみよう!
までをなんとなく理解していることを前提としています。
環境:UE5.0.2
目次
ノード紹介
Tick/Print String
Sequence
MultiGate
変数
・Boolean
・Integer, Flote
・Name,String,Text
・Vector,Rotation,Transform
CastとGet Actor Of Class
Tick/Print string
Tickは1fpsにつき一回呼び出されるイベントになります。
fpsはUE5ですとしたのコンソールコマンドに stat fps と入力することで確認できます。
(プレビューの右上にこのような表示が出ます)
大体1秒間に16回処理が実行されているということになります。
Print Stringは実行される度にIn Stringの文字列を画面に表示するものになります。
デフォルトではHelloと入っていますが、文字を打ち換えたり、左側のピンクのピンに変数などを入れることによって色々なものを表示させることができます。デバッグでめちゃめちゃ使います。
開発のみ の▽を押すと詳細設定を出すことができます。
パラメータ | 内容 |
---|---|
Print to Screen | スクリーンに表示するか |
Print to Log | アウトプットログに表示するか |
Text Color | テキストの色 |
Duration | 表示する秒数 |
Keyは中の文字列を設定することによってPrintstringをTickで表示した時に一つの文字列を更新し続けるように設定できる?用です。
プレイ結果
何かのパラメータなどをデバッグするときに便利かもしれません
Sequence
シーケンスは通常1つずつしか繋げられないノードを枝分かれさせられるノードです。すべてのピンが同時に実行されます。
右下の ピンを追加 で枝分かれの数を増やすことができます。
プレイするとと3つのPrintstringが実行される処理を組んでみました。
実行するとこのような結果になります。
Then0から実行されていくようです。
注意点として、実行順が先のところにDestroyActor等アクターを消したりする処理を書いて後の方にDestroyActorするアクターに関する処理(ダメージ処理・エフェクト等)を書いたりすると、対象のアクターが無い、などのエラーが出る原因になります。
必ずDestroyActorなどの破壊的処理は最後に書きましょう。
MultiGate
マルチゲートはシーケンスと同じく実行結果を枝分かれさせられるノードになります。
違う点としては、右の出力ピンが同時に実行されるのではなく、一度実行されるごとにOut0、Out1、Out2…というふうにピンが変更されていく(一回の実行につき一つのピンしか実行されない)というところです。
同じく ピンを追加 で出力ピンを増やすことができます。
パラメータ | 内容 |
---|---|
Reset | 実行済みのピンを非実行状態に戻す |
Is Random | ピンの出力順をランダムにする |
Loop | 全てのピンが実行されたあと、リセットして再び実行 |
Start Index | スタートするピンを指定できる |
プレイ結果
ランダムをTrueにした場合
(見えにくいです1 0 2の順番で実行されています)
ループをTrueにした場合
ループとランダムを両方Trueにした場合は102.021.120のようにすべてのピンが表示されてからループするようになります。
また、Start Indexで1以上の数値を指定すると、120と実行されます。
そこにランダムを足すと102.120のように指定した数字以外がランダムに表示されます。
ループを足すと12.012.012…という実行結果になります。
ランダムとループを両方Trueにすると120.102.102…のように指定した数字が最初に実行され、残りのピンがランダムに実行、すべて実行されるとまた指定した数字から…というふうになります。
完全に表示をランダムにしたい場合は
このように完全にどれか実行される度にResetですべて非実行にしてしまうことで121100212010…みたいな感じのランダムにすることができます。(これは例であってサイコロのようなものを作りたいのであればランダムな数値を指定した範囲で出してくれるノードがあります(後述))
これを応用すると話しかけると一方的にしゃべり続けるNPC的な物が初心者でも作れたりします。
変数
これがちょこっとわかるとかなりできることが広がります。もうゲーム制作においてありとあらゆるものが変数で管理されているといっても過言ではありません。
基本的な使い方は、
画面左下の変数というところをクリックして新しい変数を作ります。
右側の詳細パネルで名前と型を変更できます。
変数は最初は基本的に数値系は0、テキスト系はNoneか空白が入っていますが、コンパイルした後出てくる右側の詳細パネルの下の欄のデフォルト値というものを設定することによって初期の値を変更することができます。(HPという変数を作ってデフォルトを100にしたり、等)
基本的に使うのはこの二つで上のものが Get (変数名)で変数の中身を出力するもの、Set(変数名)で変数の中身を入力、変更できます。ノード自体は右クリックで検索からget/set(変数名)と検索するか、左側の変数のところからD&Dすることで出すことができます。
変数には型というものがあり、型同士で変換できたりできなかったりします。この記事では特によく使うもののみ紹介していきます。
Boolean
TureかFalseを返す変数です。ざっくりいうと今このコリジョンに入っているか?みたいな判定の時に使います。
ブランチ(Branch)ノードとセットで使うことが多いです。
ブランチノードはこのように左下にBooleanの入力ピンがついています。ここに先ほどのGet~の方のBooleanを繋げると、TrueかFalseかによって出力先が変わります。(繋げなくても左下のチェックボックスにチェックを入れるとTure、空だとFalseが出力されます。)
Booleanによく使うノードとしては上のようなものがあります。
左側は論理演算と言ってboolean動詞を比較して、真ん中に書いてある文字の条件に当てはまった時にTrueを返す、というものがあります。
2つのBooleanがorやand等の条件に当てはまればTrueを返すというものです。
右は条件式でInteger(整数),Integer64(Integerより大きな整数を使える),flote(浮動点少数)を左側に入れることができます。上下の数字を比べた時<や==等の条件に当てはまればTrueを返すというものです。
ピンを追加 が書いてあるものは追加すると左側の入力ピンが増えます。
これを使うとギャルゲのようなものを作る時、「このキャラの好感度がいくつ以上でかつこのイベントとイベントとイベントをクリアして且つこのイベントに進んでいない時に発生する~~」みたいなものが作れます。
Integer,Flote
Integer,Floteはどちらも数字を扱う変数です。
Integerは整数、Floteは浮動点少数。(雑に言うなら小数点以下を扱えるのがFloteと覚えておけばいいです)
Integer64はIntegerより大きい桁の数字を扱える整数の変数になります。(初心者のうちはほとんど使うことはないので紹介しません)
Floteは後に紹介するVectorに掛けたり、数学的な計算に使ったりと使い所がかなり多いです。
Integer,Floteによく使うノードとしては上のようなものがあります。
左は一般的な四則演算になります。ピンを追加で左側の入力ピンを増やすことができます。
剰余算以外は上下にIntegerとfloteをどちらでも入れることができます。(Flote + Integerのように違う変数同士でもできます)
右側はランダムな数字を出すノードになります。
上で書いた完全にランダムな数字を出すノードがこれになります。
Random ~~~~ In Rangeが使用回数がとても高く、Min(最小値)からMax(最大値)の間の数字を返すものになります。正確では困る物(敵AIのAimなど)やダメージに使うことが良くあります。
Random Floteは0~1の間の数値を返すものになるので二点間を移動するものの移動の割合などに使ったりします。
Random Integerは0からMax-1の数字をランダムに返すものになります。(あんまり使ったことはないです)
他にも三角関数や円周率、内積を出してくれるノードがあるのですが、数学弱者なので割愛させて頂きます。(説明できないので…)
BooleanとIntegerを組み合わせてありそうなBPを組んでみる
この二つの変数を使った例として「範囲内に入るとHPが回復する」というBPを組んでみます。
BPを作ってビューポートからBoxCollisionを出します。
特に今回範囲を示すためのものを出したりしないのでわかりやすくするために右側の詳細からHidden in Gameを切っておきます。こうすることでプレイ中もコリジョンの枠が表示されるようになります。
イベントグラフに移動してBPを書いていきます。
BoxCollisionに入ったイベントと出たイベントを追加していきます。
イベントはイベントグラフに移動し、左上のコンポーネントタブを右クリックしイベントを追加にカーソルを合わせると、追加できるイベントが表示されます。そこからOnComponentBegenOverlapとOnComponentEndOverlapを追加します。追加はコンポーネントタブからBoxCollisionを選択した時に出る右側の詳細タブからも追加することができます。
今BoxCollionに入っているか?という判定をするためにBooleanを追加します。(名前は回復とかわかりやすいようにしておきます。)
続いてBP_ThirdPersonCharactorを開いて、プレイヤーにHPの変数をIntegerで追加します。
結果わかりやすいようにTickで数字を表示してくれるようにしました。
一回コンパイルをして、右側の詳細タブからデフォルト値を1にしておきましょう。
回復のBPの方に戻ってBPを組んでいきます。
BegenOverlapのノードのOtherActorからOverlapしてるものの情報を取ります。CastノードをOtherActorから繋げて、OverlapしてきたものがBP_ThirdPersonCharactorがあるかどうか確認します。(Castについては後に解説)BP_ThirdPersonCharactorがあったらオブジェクト変数というものに昇格(これでこのBP内でBegenOverlapが起こった後はBP_ThirdPersonCharactorの情報を取り出せる変数ノードを置けるようになります)します。
先ほど作ったBooleanをSetで配置し、Trueにします。
次にEndOverlapからもCastをだし、出ていったのがBP_ThirdPersonCharactorか確認します。BP_ThirdPersonCharactorであったらBooleanをSetで配置しFalseにします。これでBP_ThirdPersonCharactorがBocCollisionに入ったらBooleanがTrueになり、出ていったらFalseになります。
最後にTickを持ってきます。まず、ブランチを出してBooleanがTrueである(BP_ThirdPersonCharactorが入っている)か確認します。Falseだった場合この時点で処理が終了します。Trueであったら、次にHPがいくつかどうか判定します。
先ほど作ったBP_ThirdPersonCharactorの変数からコードを伸ばして「get(変数名)」と打つと、BP_ThirdPersonCharactorの中にあるHPの変数を参照することができます。
持ってきたHPの変数を条件式に入れます。
HPの変数<100という式を組むので、HPの変数からコードを伸ばし<を入力して条件式を出します。
上にHPの変数を繋げて、下の四角に100と入力しましょう。
新しいブランチノードを出して条件式の出力のBooleanを繋げます。先ほどのコリジョン内にいるかどうか確認するブランチのTrue側からノードを伸ばし繋げます。もしHPが100以上だったら回復イベントは起きないので(やらなくてもきちんと動きますが)Falseの先にSetでコリジョン内の判定Booleanを出して、Falseにしておきましょう。
ではHPが100以下だった時の処理を書きます。
BP_ThirdPersonCharactorの変数を持ってきてHPの変数をgetで出します。そこから加算ノードを出してHPの変数を上に繋げます。下の四角には1を入れます。
次にもう一度BP_ThirdPersonCharactorを出して今度はSetでHPの変数出します。Integernoのピンに先ほどの加算ノードの出力ピンを繋げ、HPの数字を判定するブランチのTrueとHPの変数のSetノードを繋げます。
コンパイルして保存し、BPをマップ上に配置しましょう。
左上のPrintstringにご注目。
Name,String,Text
Name,String,Textは文字に対応した変数です。
筆者もいまいちよくわかっていないのでざっくりとした解説になります。
詳しく説明してくださっているとんこつ様のブログ
https://shuntaendo.hatenablog.com/entry/2017/07/04/045214
Nameは文字通り、名前を指定する変数になります。
BPからboneの名前などを取りたい時に使うのがこの型です。他にもデータテーブル等扱うようになるとちょいちょい出てきます。
StringはPrintstringで使われている変数になります。
Stringは唯一BPで文字を足したり合わせたりできるらしく、主にデバッグ関連で使うことが多いです。
TextはUI等画面に表示される文字列として使われる変数です。PrintTextというノードでPrintstringと同じように画面に出したりすることができます。
(ほぼ使用用途はUI)
Vector,Rotation,Transform
Vector,Rotation,Transformは「どこで」を示す変数になります。
各変数ごとの特徴
・Vector
Vectorはx,y,z軸を使って位置やサイズを表したものになります。
位置とスケールによく使います。たまに速度とかにも。
四則演算を使うことができ、Vector同士での計算も、VectorとFlote,Integerとの計算もできます。
移動系に使うことがかなり多め。
猫でもわかる~の2のように往復する足場を作ったりできます。
・Rotation
RotationはX,y,zを軸としてどれだけ回転しているかを表したものになります。
Rotaionは四則演算ノードのうち乗算しか使用できず、且つFlote,Integerとしかできません。
代わりにRotationには専用の[Combine Rotators]というRotation専用の加算ノードがあります。
また、[Find Look at Rotation]という非常に便利なノードがあります。StartとTargetにVectorを入れると、StartのVectorのものがTargetの方向を向くのに何度回ればいいか、というのを計算してくれるというものです。
例えばStartにNPCのVector、TargetにプレイヤーのVectorを入れると、イベントが発生したタイミングでNPCがプレイヤーの方向を向く、みたいなノードを組むことができます。
・Transform
Transformは、Location(Vector),Rotation,Scale(Vector)の3つを合わせたノードになります。
Transformは直接四則演算をしたりすることができず、[Break Transform]というノードを使って3つに分解することで、計算することができます。
逆に3つの変数からTransformにしたい時はMake Transformで合成することもできます。
また、いろいろなノードでTransformの入力・出力ピンがある時、Transformのピンを右クリックして「構造体ピンを分割」を選べば分解することができます。
また、VectorやRotationも同じようにFloteまで分解することができます。
この3つの変数によく使うノードになります。
BPやコンポーネントのWolrd上(レベル上)のVector,Rotation,Transformの位置を取って来たり位置を変更するものです。
左側のGet Actor~,Set Actor~はBP全体を対象としたものになり、何も入っていない時はSelfと表示されこのノードが置いてあるBP自体が対象となります。他のBPをCastしたときの右側のピンやBegenOverlapなどから出ているOtherActorのピンを繋げることで繋げたピンに含まれているBPの位置をGetしたりSetすることができます。
右側のGet World~,Set World~はBP内に含まれているコンポーネント(StaticMashやSketalMesh、Collisionなど)のワールド上での位置を取得するものになります。
左側のノードとの違いですが前提として、ゲーム内には大きく二つの座標があります。1つがレベルが広がっているWolrdの座標です。そしてもう一つがBPのビューポート内でのローカル座標になります。
左側のノードはBPのローカル座標0.0.0がワールドにおいてどこにあるか?を取る者になります。
対して右側のノードはローカル座標1.2.3とかにあるものがワールドでどこにあるか?というものになるので「BPのワールド座標+コンポーネントのローカル座標」を足した数値になります。
(ちょっとわかりにくいけどこんな感じです)
Set~ノードのパラメーター解説
パラメーター | 内容 |
---|---|
ターゲット | Setする対象 |
New~ | 新しくSetする数値 |
Sweep | 新しい地点までスイープして移動。途中で何かのコリジョンに当たった時停止するかどうか |
Teleport | 新しい地点にテレポートする。その地点に出現する感じ? |
SweepとTeleportの検証
上から 変更なし、Sweep、Teleportになります。
CastとGetActorOfClass
・Cast
Castは、左側のObjectピンに入力されたObject(ActorやPlayerPown等)がCastoto~の後に続くものと一致しているか?というのを判断するノードになります。
OverlapやHitイベントノードについているOther Actorから繋げることが多いです。このノードを繋げることによって、Other Actorの中のObjectの変数などを編集することができます。また、「カスタムイベント」というBP内で作成した独自のイベントを呼び出すこともできます。
左のObjectノードに繋げないとエラーが出ます。
・Get Actor Of Class
Get Actor Of Classは左下の「クラスを選択」で選んだクラスのobjectの情報が右のReturnValueから出力されます。
これによりCastでは必要だったOther Actor等の外部からのObject情報が無くても選択したクラスの変数などが編集できます。
(このようにCastが無くてもBP_ThirdPersonCharactorの変数を持ってこれます)
この2つのノードは大変便利なのですが、「参照連鎖」というものが起こってしまいます。
筆者が過去に作ったプロジェクトのプレイヤーBPなのですが、参照が恐ろしいことになっています。
これは左側のBPの情報を真ん中のBPがとっていて、真ん中のBPの情報を左側がとっているという感じなのですが、めちゃめちゃプロジェクトが重くなります。
右側のBPがロードされたときに真ん中と左側のノードがすべてロードされるような状態なので、プレイを押した瞬間5秒くらいフリーズしたりします。(筆者のパソコンが低スぺなのもありますが)
ので、初心者のうちは便利に使って良いですが、慣れてきたら参照連鎖を断つやり方をするようにしましょう。
一番わかりやすい方法としては「ブループリントインターフェース」というものがあります。
詳しい解説はこの記事ではしませんが、簡単に言うとCastなどで受け渡ししていたメッセージや数値を送ったり受け取ったりする専用のBPになります。
こんな感じで集約されるので、参照連鎖が広がることを避けることができます。
今すぐ知りたいという方へおすすめの動画です。
終わりに
初心者の心を失う前に書いてみました。
どれも自分がゲームを作り始めてた頃知りたかったものになります。(過去の自分に記事を投げたい)
余りにも長文なのでここで一区切りとしていますが、〆切が過ぎ去った後にSpawnActor系とかDamageとかDestroyActorとかdelayとかも書きたいですね。
ここまでお読みいただき、ありがとうございました。