(動画チュートリアル関連) 変数の型で Reference とはどのようなものですか?

動画チュートリアルで使われる変数の型 (type) には、「Object type」(オブジェクト型) とか「Reference type」 (参照型) がよく出てきますが、これらはどのようなものなのでしょうか?

:arrow_forward:関連する動画チュートリアル

[Blueprint Essentials-2-Variable Types][2]

簡単に言いますと、たとえば、キャラクターなどのデータを利用したい場合、そのキャラクターのデータがどこにあるのか教えてくれるのが Reference type (参照型) の変数です。ですから、キャラクターのデータを利用する時は、まず、この参照型の変数を作って、それを使ってキャラクターのデータにアクセスすることになります。より詳しくは以下のようになりますが、それが理解できなければ参照型の変数を使えないということはありませんのでご安心を。

「変数とは、値を入れる箱である」という説明がよく聞かれますので、これに沿って説明してみたいと思います。

まず「型」とは、箱のサイズや箱の中の仕切りの有無 (あれば Rotator 型のように箱の中に複数の値をセットで入れられる) などを数種類用意することによって、ユーザー (とコンピュータ) がさまざまなデータを効率よく利用できるようにした一種の形式です。たとえば、Integer (整数) 型には整数の値を入れる箱の型であり、Boolean (ブール) 型には true (正しい) か false (正しくない) を入れる箱の型です。

下図は、ゲーム開始と同時に (Begin Play イベント)、 TestInt という Interger 型の変数に 201 という値 (整数) を入れ、TestString という String (文字列) 型の変数には「痛いです!」という値 (文字列) を入れています。そして、浮遊しているドーナツとキャラクターがぶつかった時に (ActorBeginOverlap イベント)、TestInt と TestString の値を表示 (Print String 関数) しようとしています。結果は当然それら変数に入っている値 (201 と 「痛いです!」) が表示されます。(なお、TestInt と Print String 関数の間にあるノードは、整数値を文字列に変換するためのノードです。)

では、Reference type (参照型) でも同じようなことを行うとどうなるでしょうか?下図では、ゲーム開始時に (Begin Play イベント) プレイヤーキャラクターを取得して (Get Player Character 関数)、CharacterRef という Reference type (参照型) 変数にそれを入れています (Set している)。そして、浮遊しているドーナツとキャラクターがぶつかった時に (ActorBeginOverlap イベント)、CharacterRef の中身を表示 (Print String 関数) しようとしています。ただし、変数 CharacterRef と Print String 関数をつなげようとすると下図のように、Get Display Name (表示用名前を取得) 関数が強制的に割り込んできます。そして、これを実行すると、ThirdPersonCharacter という文字列が表示されます。これが、「表示用名前」なのでしょう。(蛇足ながらこの表示名は、アウトライナーの表示名 (青枠部分) と同じです。)

これは、どういうことなのでしょうか?Reference type (参照型) の CharacterRef には、ThirdPersonCharacter という表示名が入っているということ ではありません 。もしそうであるならば、Get Display Name 関数は必要がないはずです。せいぜい、先の TestInt と Print String 関数の間にあるノードのようなものがあればよいはずです。つまり、Reference type (参照型) の CharacterRef 変数の中身は表示できませんでした。むしろ、CharacterRef 変数の中身を利用して、このオブジェクトの表示名を取得して表示したということになります。

Reference type (参照型) のCharacterRef 変数の中身には、参照が入っています。「参照」とは、あるデータが入っている箱 (メモリ) の番地です。この例では、CharacterRef 変数には、キャラクターのデータがメモリ上のどこにあるか (=どの箱に入っているのか) を教えてくれる番地が入っています。キャラクターのデータそのものは入っていません。(ですから Get Player Character 関数は、キャラクターそのものではなく、キャラクターのデータが入っているメモリの参照を取得しています。)

以上のことを模式化すると次のようになります。

上図では、メモリのある領域にキャラクターのさまざまなデータが入っています。そして、その番地が 00000032 だとします。この時、キャラクターのデータにアクセスするには、この番地を頼りにします (ある学校にアクセスするにはその学校の番地が必要であるのと同様に)。そして、00000032 という値を別の変数 (変数名は CharacterRef) に保管しておけば、この値は扱いやすくなります。一々 00000032 を覚えていなくても、CharacterRef という名前さえ覚えておけば、キャラクターのデータにアクセスできるからです。このようにあるデータにアクセスするための番地を保存できる型を参照型といいます。(なお、この CharacterRef という変数にも当然番地がついています。それは上図では 00005546 なのですが、この番地をブループリント ユーザーが直接操作、使用することはありません)。

ところで、なぜ、CharacterRef 変数に「キャラクターのデータそのもの」を入れないで、参照 (番地) を入れるのでしょうか?キャラクターのデータは多数あります。たとえば、トランスレーション (位置) や ローテーション (回転)、スケルトン、関連付けられているアニメーション、コリジョン、マテリアル、最大歩行速度 etc etc とにかく多数あります (たとえば、詳細パネルをご覧ください)。それらをすべて 1 つの変数に入れるのは非効率です。たとえば、主に「最大歩行速度」だけが必要なのに、その他のデータも必ず変数に入れるのであれば、無駄にメモリが消費されてしまいます。読み込むにもその分余計な時間がかかるでしょう。

であれば、いっそ CharacterRef 変数には、それらのデータが入っているメモリの位置だけを入れて、それを頼りに「最大歩行速度」にアクセスしたほうが合理的です。そして、CharacterRef 変数を表示する場合は、表示名を表示することにしているのです。その場合ももちろん参照 (番地) を頼りにして Get Display Name 関数が表示名を取得しています。

下図は、参照 (番地) を利用して、最大歩行速度を変更したり、キャラクターを空中に打ち上げています。最大歩行速度は Max Walk Speed で変更できますが、その場合も CharacterRef 変数 (中身は参照) が使われています。これを頼りに、Character Movement コンポーネントを経由してキャラクターの Max Walk Speed というデータにアクセスしているのが分かります。キャラクターを空中に打ち上げる場合は、Launch Character (キャラクターを打ち上げる) 関数を使っていますが、やはり CharacterRef 変数が接続されています (頼りにされています)。

まとめると、参照型の変数は、オブジェクト (アクタ、ポーン、キャラクターなど) の豊富なデータや機能に (要領よく) アクセスするための窓口と簡単に考えておいていいと思います。

なお、C/C++ を学んでブループリントに入ってこられた方には、ブループリントの参照型はポインタであると考えていただければいいと思います。(C/C++ を学ばなければブループリントは使えないということは決してありません)。

オブジェクト型と参照型の関係ですが、型の 1 つにオブジェクト型があり、オブジェクト型の 1 つに参照型がある、ということになります。

:arrow_forward:関連する UE4 ドキュメンテーション

[『ブループリントの変数』][6]