第17回 カスタムイベントを作ってみよう

前回の振り返り問題
(再掲) キャラクターが何かにぶつかった時に、そのHPが10ずつ減るようなグラフを組んでみましょう。キャラクターのHPはInteger型の変数にして適当な名前を付けてください。

前回は予めUE4に用意されているイベントを使ってみる勉強でした。振り返り問題も既に用意されているイベントHitを使います。このイベントはあるアクタが別のアクタにぶつかると発動して、このイベントHitにつながるノード群を実行するのでした。

HP_CharacterというInteger型変数を一つ作成しておき、デフォルト値を300にしています。仕組みは、キャラクターが何かにぶつかると、HP_Characterから10を引いた結果が、セットノードによってHP_Characterに格納される、というこれまで何回も行ってきたようなものです。
b17-1(画像1)
これを実行すると、次のようにキャラクターが壁に当たるたびに10ずつ減って行きます。
b17-2(画像2)
ただし、次のようにコリジョンプリセットをOverlapAll(すべてと重なる)にすると、衝突しないことになるので、HP_Characterも減りません。
b17-3(画像3)
b17-4(画像4)
コリジョンプリセットをDefaultに戻すと、ちゃんとHP_Characterも減るようになります。
b17-5(画像5)

カスタムイベントの基本
さて、今回のテーマであるカスタムのイベントです。動画チュートリアルにはちょくちょくカスタムイベントが出てきますので一通り基本は会得しておきたいものです。また、AnswerHubなどではよく「関数とカスタムイベントの違いは何か」という質問を見かけますが、その違いについても基本をしっかり押さえていきたいと思います。

カスタムイベントは、前回のイベント(UE4にあらかじめ備わっているイベント)と同じように、呼び出されて、それに続くノード群が実行されます。(このあたりは関数と同じです。)

では、まず、簡単なカスタムイベントを実際に作ってみましょう。Helloを表示するだけの簡単なものです。
b17-6(画像6)
上のように右クリックメニューの検索欄にcustom eventと入れて、「カスタムイベントを追加」を選択します。カスタムイベントに適当な名前を付けます(HelloHyoujiとしました)。
b17-7(画像7)
Helloを表示するだけなので、Print String関数を接続します。
b17-8(画像8)
最後に、ゲーム開始と同時にこのイベントが発生するようにします。そのためには、BeginPlayイベントに、HelloHyoujiの呼び出しノードを接続します
b17-9(画像9)
HelloHyoujiの呼び出しノードは、右クリックしてhelloなどと検索すると出てきます。「関数呼び出し」という項に入っていますが、厳密には関数ではありません。ただし、関数が、関数本体と関数呼び出しのノードが別になっているように、イベントもイベント本体とイベント呼び出しノードに分かれています。
b17-10(画像10)

以上が簡単なカスタムイベントの作り方です。ほとんど関数の作成と変わりません。では、関数との違いはどこにあるのでしょうか?

カスタムイベントと関数の違い
違いを学ぶ前に、関数を使って同じこと(ゲームが始まると関数が呼び出されてHelloが表示される)を実現してみます。まず、関数本体を作ります。名前はHelloHyoujiKansuとしました。
b17-11(画像11)
単にPrint Stringがつながっているのは、HelloHyoujiイベントの時とまったく同じです。では、イベントグラフでこの関数を呼び出してみます。
b17-12(画像12)
上の画像にあるように、「関数呼び出し」の項目にHelloHyoujiKansuが入っていますので、これをクリックします。
b17-13(画像13)
実行結果は次のようになります。
b17-14(画像14)
これはHelloHyoujiイベントでもまったく同じ結果となります。

では、カスタムイベントと関数はどこが違うのでしょうか?
一つは、カスタムイベントは返り値を返せないということがあります。これだけだったら、関数は返り値を返すことも返さないことも両方できるのですから、カスタムイベントは必要ないということになります。しかし、関数にはできないことがあります。それは、わざと処理を遅れさせるような機能(Delay関数など)が使えないということです。Delay関数は指定した秒数だけ処理をストップさせる(待たせる)ものであり、イベントには使えます。

イベントと関数が異なるのは、表面的には上のようになります。しかし、その本質はかなり違います。それをこれから説明したいと思います。

まず次のCryというイベントをご覧ください。
b17-15-2(画像15)
さっそく、Delayが使われていますね。このイベントはゲーム開始するとすぐに呼び出されます。単に「しくしく」と表示されるだけのごく簡単なものです。では、実際にプレイするとどのようになるか予想してみましょう。

(誤解例)「ゲームが開始するとまずCryが呼び出されるので、Delayが実行され4秒待たされる。その後「しくしく」と表示されてイベントBeginPlayに帰り、「BeginPlay側」が表示される。」
実際にプレイすると次のようになります。
b17-16-3(画像16)
表示は下のほうが古く、上のほうが新しいので、まず「BeginPlay側」が表示されてから「しくしく」と表示されていることが分かります。つまり、BeginPlay側はCry側の実行完了を待たずに勝手に処理が進んでいることが分かります。「あるイベントが他のイベントに従属していて、部品のように振る舞い、その処理が終わると元のイベントに帰っていく」ということはありません。イベントはお互いに独立した存在なのです。

このような独立した一連の処理のことをスレッドなどと呼びます。2つのスレッドはお互いに影響されることなく、我が道を行く的に勝手に処理を進めていきます。イベントはスレッドを作ります。

では、関数はどのようになるでしょうか?次のような関数版のCryを作ってみます。
b17-17-2(画像17)
b17-18-2(画像18)
さっそく実行してみると、次のようになります。
b17-16-2(画像19)
まず「しくしく(関数バージョン)」が表示されてから「BeginPlay側」が表示されているのが分かります。つまり、関数はあくまでも部品であり、必ず元に(この場合BeginPlay側)に帰ることになります。(なお、BeginPlay側よりも時間がかかるように関数を組んでも、やはり「しくしく(関数バージョン)」が先に表示されます。時間がかかるので先に「BeginPlay側」が表示される、というようなことはありません。)

今回は、関数と(カスタムの)イベントにはまったく異なる側面があることも学びました。

【ノート】
① スレッド
掲示板や質問サイトなどでもよく使われる言葉ですね。スレッドとは、独立したひと続きのものに対してよく使われます。独立しているので、他のスレッドの投稿から干渉を受けたり、他のスレッドの投稿を結果を待ったりもしません。それぞれのスレッドは勝手に進んでいきます。ブループリントでもそうです。スレッドとは、ひと続きの処理(今回の場合、たとえば、DelayからPrint Stringまでの処理)であり、他の処理から独立しているため、他のスレッドの処理を待ったりしません。その一連の処理が済むと消滅します。そのようにコンピュータが扱ってくれます。

【まとめ】
① イベントは独立した大きな流れ(スレッド)だが、関数は大きな流れ(スレッド)に従属した部品である。
② (だから) イベントは返り値を返さない。(そもそも独立しているため関数のように「(本体に)返る(返す)」という発想がない。ただし、引数は取れる。)
③ イベントと関数は結果的に同じことを実現できる場合がある。(画像11~13)
④ 関数の中ではDelayなどの待ち関係の機能が使えない。

振り返り問題
ThirdPersonCharacterブループリントで、Gキーを押したら0~999のループを回して、777になったらその数字を表示し、さらに、キャラクターが「やったぜ!」と言ってジャンプするYatta! イベント(カスタムイベント)を発動させてください。ジャンプさせるはJump関数を使ってください。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする