第18回 クラスの基本を学ぼう

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

まずは完成図をご覧ください。
b18-1(画像1)
若干長いように見えますが、中身は実に簡単です。
[Gキーのグラフの流れ]
Gキーを押すとGキーイベントが発生して、これに続くノードが実行されます。GキーイベントはUE4に最初から用意されているイベントなので、カスタムイベントではありません。念の為。 ForLoopが実行されるたびにindexが777と==(等しい)かどうかチェックされます。
⇒ 等しい場合、ブランチのTrueピンにつながっているノードが実行されます。 つまりPrint Stringが実行されてindex(この場合777)が表示されます。Yatta!イベントが呼び出された後に、ループされます。
⇒ 等しくない場合、ブランチのFalseピンにつながっているノードが実行されますが、今回は何もノードはつながっていないので、ループされます。

[Yatta!のグラフの流れ]
Gキーイベントに続くグラフからYatta!イベントが呼び出されると、まず、Print Stringで「やったぜ!」と表示されて、Jump関数が実行されてキャラクターがジャンプします。なお、Jump関数の実行対象(ターゲット)はself(自身)になっていますが、この場合の自分自身とは、このブループリント自身、つまりThirdPersonCharacter自身のことです。つまりキャラクターがジャンプすることになります。
b18-2(画像2)

クラスとは?
クラスは、UE4~ブループリントの基本的な単位なので、頻繁に利用するものなのですが、ここまで「クラスとは何か」という問題は避けてきました。クラスを説明するためには変数や関数を紹介しなければならなかったからです。

今回、ようやくクラスについて勉強することになりますが、クラスの基本が分かれば、作れるものや理解できることが広がります。たとえば、他のアクタとのやり取り(お互いが影響を与え合うなど)する場合です。動画チュートリアルに数々出てくる「参照型」変数についても理解できるようになり、それを通じてさまざまなグラフが組めるようになります。

では、クラスです。私たちがこれから学ぶクラスは、ブループリントクラスとも言います。あるいは単に「ブループリント」とも言います。ですから「ブループリント」には2つの意味があることになります。一つは、ビジュアル的にプログラムできるツールという全般的な意味。「UE4にはブループリントという強力なツールがある」などと使います。もう一つは、これから勉強するブループリントクラスという意味です。

b18-3(画像3)
b18-4(画像4)
これまで利用してきた、キャラクターやMyCubeは、ファイル名を見る限りクラスになっていますね。このように、クラス(ブループリント)を素にしてレベルに配置(具体的にはクラスと書かれたファイルをレベルエディタのビューポートにドラッグします)したものは、インスタンス(またはオブジェクト)と言います。この用語についてはこの後で詳しく学びたいと思います。

さて、ブループリントは、キャラクターやMyCubeのように目に見えるものになることがあり、感覚的にも分かりやすいものです。

では、クラスとは具体的にどのようなものなのでしょうか?クラスとは簡単に言うと、データと機能がセットになっているものです。言い方を変えると、変数とイベントや関数がセットになったものです。これでもまだ、抽象的な言い方ですので、以下の画像をご覧ください。
b18-5(画像5)
b18-6(画像6)
b18-7(画像7)
赤く囲っている部分が機能です。緑の部分がデータです(これまで行ってきた変数や関数、イベントの勉強がここに来て集結してきたような感じですね)。大ざっぱに言えば、クラスとは、自分のもっている機能によって自分のもっているデータを何らかのきっかけで変化させるためのものです。(その機能が発動するタイミングは他のクラスが関係する場合がありますが、それは次回以降に紹介します。)

ここで重要なことがあります。それは、クラスは原則的に独立した存在であるということです (したがって、、クラスから生み出されるインスタンスもそれぞれ独立しています)。どういうことか、次の画像をご覧ください。
b18-8(画像8)
b18-18(画像9)
キャラクターのクラスにもMyCubeクラスにもあえて同じ型/同じ初期値/同じ名前の変数Skillを作ってみました。キャラクターの方はFキーが押されるたびにSkillが-10してオレンジで表示します。10ずつ小さくなっていきます。一方、MyCubeの方は、ゲームが開始されると3秒後に(MyCubeの)Skillを緑で表示します。実際にインスタンスとしてレベルに配置して(今回は2つのクラスとも最初からインスタンス化されています)プレイすると、どのような結果になるでしょうか?Fキーはゲーム開始から3秒以内に押しています。キャラクターで減ったSkillはMyCubeでも減らされて表示されるでしょうか?
b18-10(画像10)
Gキーを4回押したところSkillは思惑通り890 → 880 → 870 → 860 のように減りました。そしてゲーム開始3秒後にはMyCube側で(MyCubeの)Skillを表示しています。それは緑で900と表示されています。これから考えると、キャラクター側のSkillの値の変化がMyCubeのSkillに一切影響を与えていないことになります。先ほど、「クラスが原則的に独立した存在である」と言ったのはこのようなことを言いたかったのです。あるクラス(したがって、そこから作られるインスタンス)のもっているデータやそのデータを操作する機能に、他のクラスは簡単にはアクセスできないのです(このような言語を「オブジェクト指向の言語」と言いますが、興味のある方は下のノート①をご覧ください)。他のクラスの変数などにアクセスする(利用する)には、一定の手続きが必要になります。

クラスからいくつでも作れるインスタンス
ここで、クラスとインスタンスの関係をもう少しだけ踏み込んで学んでみたいと思います。

すでにご存知のように、コンテンツ ブラウザにおいてあるクラスをレベルにドラッグすると、そのクラスのインスタンス(オブジェクト)をレベルに配置できるのでしたね。
b18-11(画像11)
b18-12(画像12)
さて、「インスタンス」(instance)とは日本語で「例」という意味です。つまりあるクラスが具体例としてレベルに置かれる、という感覚なのでしょうね。ところでクラスからインスタンス(オブジェクト)が作られるのですから、クラスは設計図みたいなものだとよく言われます。あるいは、たい焼きを作る型にも喩えられます(出来上がったたい焼きがインスタンスです)。設計図は英語にするとBlueprintなので、ちょっと納得です。

1つのクラスからは複数のインスタンスを作って置くことが可能です。
b18-13(画像13)
さらに、次のようにそれぞれのインスタンスが持っているデータを変更することによって、インスタンスそれぞれに個性をもたせることができます。
b18-14(画像14)
あるインスタンスがもつデータ(この場合、「拡大縮小」のzの値)を変更しても、他のインスタンスに影響はまったくありません。やはり、インスタンスも、原則として他のインスタンスに影響を受けない独立した存在なのです。

さてここで、オブジェクトという用語についても少し。先ほどから「インスタンス(オブジェクト)」という書き方を何回かしてきました。これは、両方の用語が実際に動画チュートリアルや公式のドキュメントなどで使用されるためです。

オブジェクト(object)の意味は「物」です。オブジェクトには、メモリに格納されたデータという広い意味があります。公式のドキュメントには、「オブジェクトはクラスのインスタンスである」と書かれていますが、エディタではクラスそのものもオブジェクトとして表現されていますので、次のように覚えておくのがよいでしょう。
クラス(オブジェクト) → インスタンス(オブジェクト)
つまり、クラスもオブジェクトであり、クラスからできるものであるインスタンスもオブジェクトである、というように。

これでオブジェクト型とかクラス型の変数について勉強できる基盤ができました。次回またステップアップです。

【ノート】
オブジェクト指向
「オブジェクト指向プログラミング」とか「オブジェクト指向の言語」という言葉を聞かれたことがあるかもしれませんが、ブループリントのようにオブジェクト(インスタンス)が独立してデータと機能をもち、オブジェクトどうしが独立しながらも通信しあって何らかの動作(ゲームプレイなど)を形作るやり方、考え方をオブジェクト指向と言います。そして、これは私見なのですが、ゲームのプログラム(ブループリントを含めて)こそオブジェクト指向がすっきり理解しやすいものはないと思います。ゲームは物や人が単位となって動きまわるのですから。

更に言うならば、キャラクターにはHPやMPというデータがあって、そのデータは何らかの条件下で変化させる機能を自らもっているのですから、オブジェクト指向はゲームにとってごく自然に、むしろ、これ以外にぴったりくる形式のものはあまり考えられません。

デスクワークのためのツールを作るような他の分野のプログラムだと、なかなかこうはいきません。ゲームのように目に見える形でオブジェクトが表現されることがそれほど多くはないからです。

元々、オブジェクト指向は、プログラムの規模が大きくなるにつれ、たとえば、ある変数が長いプログラムの至る所に存在するようになると、バグ(プログラムのミス、欠陥)が出ても、どこでその変数の値が変更されているのかすらすぐには分からなくなるような状況を避けるために考え出された仕組みだと言われています。ですから、独立した変数をもつクラス、オブジェクトがあれば、その中で変数をしっかり管理し、他のクラスから簡単には変更できないようにすると、先ほどのような問題は生じづらくなります。

オブジェクト指向の特徴は他にも、拡張(継承)といった機能があります。これはブループリントでも取り入れられていて、最初にクラスを作る時に、次のように聞かれましたね。
b18-15(画像15)
「親クラスを選択」というのは、「どのクラスに基いてあなたの新たなクラスを作りますか?」と聞いています。最初から自分ですべて作るよりも、必要な変数と機能がそろっているクラスを利用して自分で変数や機能を追加したり改変したりすることを「拡張」と言います。もう既にこの「初めて覚える UE4」でも行ってきた作業ですが、いずれ少し掘り下げることが出てくると思います。

【振り返り問題】
以前に作成した「このアクタにHitしたらこのアクタのHPが増える」というグラフを利用して、複数のインスタンスが独立したHP_Cubeをもっていることを確認してください。
b18-16(画像16)

シェアする

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

フォローする