さて、ある程度基本的なプログラムが書けるようになってきたところで、もうちょっと実用的な事を覚えてみましょう。
↑の動画でも解説していますので、ぜひご活用ください。
この記事は本のように順を追って解説しています。この記事は途中のページになります。
この記事を見ていて、現在の状況がわからない場合や忘れてしまった事などが出てきたら↓のリンクから目次ページへ飛べますので立ち戻って見てください。
<インスタンスとは>
このサイトではオブジェクト指向を「設計図」と「実体」という風に例えています。
インスタンスというのはこの「実体」に当たるものです。
class(設計図)を元にしてインスタンス(実体)を作成し、様々な実体を扱う事によってゲームは構成されます。
実体になるという事はメモリに乗るという事です。
ところで、実体になっただけでは「そこにあるだけ」ですので、プログラムから制御したり、操作したい時には実体にアクセスしなければいけません。
インスタンスにアクセスするために、インスタンスを”捕まえる”必要があります。
このように実体をとらえて使用できるようにする事を「インスタンスを取得する」と言います。
今までの解説ではUnityが自動でインスタンスを取得してくれていましたが、今回は自分でclassのインスタンスを作ったり、取得したりしたいと思います。
<GetComponent>
コンポーネントのインスタンスについて
さて、以前の解説ではスクリプトをインスペクターウィンドウにドラッグ&ドロップでインスタンス化させていました。
↑のようにスクリプトをゲームオブジェクトに貼っつけるとこのスクリプトはコンポーネントとしてくっつき、実体化(インスタンス化)した状態になります。
ところで以前の解説でCubeを右側に移動させていました。
この時、特に何もしていないにも関わらずtransformという変数が使え、変数の中に勝手に中身が入っていました。
これはUnityが全部自動でやってくれていた感じですが、このtransformには一体何のインスタンスが入っていたかと言うと↓コレですね。
Uniyがtransformという変数を用意して、自動でTransformというコンポーネントのインスタンスを取得して変数の中に入れていてくれたわけです。
このようにコンポーネントのインスタンスを取得することによってそれにアクセスして使えるようになります。
transform.position += Vector3.right;
↑はコンポーネントにアクセスして操作していたわけですね。
今回はtransformのようにコンポーネントを自分で取得してみようと思います。
コンポーネントのインスタンスを取得しよう
まずは以前のようにCubeを作成してください。よくわからない方はこちらから
さて、今現在、同じゲームオブジェクト内にくっついているコンポーネントでBox Colliderというものがあると思いますが、これを捕まえてみようと思います。
↑のように書いてみてください。そして、Cubeにこのスクリプトをくっつけてください。
BoxCollider box = null;
でBoxCollider型の変数boxを定義しています。
コンポーネントと同じ名前なのでわかりやすいですね。コンポーネントはclassでもあるので、型として定義する事ができます。
classを型にできるのはここで解説しています。
そして nullというものを代入しています。
これは何かというと「何もない」という意味です。
以前変数を箱と例えていましたから、この場合空(カラ)とも言えます。
そして、Debug.Logでboxの中身を表示させています。
box = GetComponent<BoxCollider>();
これはゲームオブジェクトについているコンポーネントを取得する命令です。
↑のように書いた場合、このスクリプトがくっついているゲームオブジェクトのコンポーネントを取得する事ができます。
この命令はMonoBehaviourを継承しているため使えます。< >の中に取得したいコンポーネントの型を指定します。
同じコンポーネントがいくつもついているとどれを取ってくるのかわからないので同じコンポーネントを同じゲームオブジェクトにいくつもつけるのはやめておいたほうがいいかもしれません。どれを取ってくるかは端末次第になるので自分はうまく動いていていても違うPCとかだと動かなくなる危険性があります。
さて、これを実行してみると
最初Nullで何も入っていなかったのが、GetComponentで中身が入っていることがわかります。
これでboxの中にインスタンスを入れることができたのでboxからBoxColliderのコンポーネントにアクセスすることができます。
<GameObject.Find>
ゲームオブジェクトのインスタンスを取得しよう
さて、↑の例ではスクリプトを貼っつけたゲームオブジェクトのコンポーネントのインスタンスしか取ってこれませんでした。
ちなみにインスタンスは実体であるので、何もコンポーネントだけがインスタンスを持つわけではありません。
ゲームオブジェクトにも実体(インスタンス)があります。
では他のゲームオブジェクトのインスタンスを取得してみましょう。
↑のように書いてみてください。
削除していなければシーン上にDirectional Lightというゲームオブジェクトがいると思うのでそれを捕まえてみます。
GetComponentの時と同じように空の変数を用意します。GameObjectとなっていますね。
ゲームオブジェクトもclassから実体化されているので型として持つ事ができます。
gと言う名前は適当です。
そして
g = GameObject.Find(ゲームオブジェクトの名前);
で指定した名前のゲームオブジェクトのインスタンスを取得する事ができます。
これで実行すると↑のようにちゃんと変数の中に入っているのがわかります。
ちなみに、DirectionalLightという風にスペースを入れないと失敗します。名前での指定の際はスペースまでちゃんと合わせましょう
別のゲームオブジェクトについているコンポーネントのインスタンスを取得しよう
さて、別のゲームオブジェクトをインスタンスを取得できたということは、そのゲームオブジェクトについているコンポーネントのインスタンスも取得する事ができます。
Directional LightにはLightというコンポーネントがついていると思いますが、これのインスタンスを取得してみましょう。
すでにDirectional Lightを捕まえて変数gの中に突っ込んでいるので
g.GetComponent<Light>();
これでDirectional LightについているLightを捕まえることができます。
GetComponentは自身についているコンポーネントを捕まえる命令なのですが、「g.(ドット)」とすることによって、変数gにあるインスタンス(実体)にアクセスし、その中のGetComponentを呼んでいます。
gはGameObjectのインスタンスを格納しているので、「g.」はゲームオブジェクトのインスタンスにアクセスしている感じになります。
これにより「自身」にあたるのはCubeではなくDirectional Lightということになります。C#では「インスタンス.(ドット)」とすることでその実体の中身にアクセスすることができます。
例外とか色々ありますが、今は↑の認識でいいかなと思います。
指定した名前のゲームオブジェクトのインスタンスを取得し、アクセスすることによって、そのゲームオブジェクトについているコンポーネントのインスタンスにもアクセスできるようになるわけです。
さて、これによりシーン上に存在するどのゲームオブジェクトのコンポーネントでもアクセス可能になりました。
色々なことができるようになりそうです。
<new>
さて、↑ではゲームオブジェクトとかコンポーネントとかUnityの機能で既に実体化しているインスタンスを捕まえていましたが、インスタンスは自分で作ることもできます。
さて↑のように書いてみてください。
Vector3と言うのはx,y,zの3つの数字を扱える構造体になっています。構造体はクラスとよく似たものになります。詳しくは後程解説します。
using UnityEngine;としているので最初からUnityが用意してくれている型を使用する事ができます。
Cubeを動かすときにも使用していましたね。
transform.position += Vector3.right;
↑はちょっと特別な使い方をしていますが、今回は普通のやり方をします。
Vector3にもnullを代入したいところなんですが、Vector3はnull非許容型といって、nullが入れることができないので、いきなりインスタンスをぶち込みます。
Vector3 v = new Vector3();
この部分ですね。
new 型名();
とすることでその型のインスタンスを作成することができます。
Vector3というのはコンポーネントではないので、ゲームオブジェクトにくっつけてインスタンス化することができません。このようにコンポーネントではない設計図はnewしてあげることによって実体を得るわけです。
(コンポーネントはclassだけど、classはコンポーネントとは限らない)
このように設計図のインスタンスを作成することによってその機能を使う事ができるようになります。
まぁ、今は様々な便利な機能を実体化して使う事ができるんだと覚えておいてください。
自分で作成したclassのインスタンスも作成する事もできます。
<NullReferenceException>
さて、インスタンスの取得とインスタンスの作成をやったわけですが、なんらかのエラーや失敗でうまくいかないことがあります。
例えば、↑で解説した、GameObject.Findでスペースを有無を間違えたスクリプトを書いてみます
これを実行すると↓のようなエラーが発生します。
これは、GameObject.Findでゲームオブジェクトが見つからないとnullが返ってくるからです。ゲームオブジェクト名を間違えているからエラーというわけではありません。
次の
l = g.GetComponent<Light>();
でエラーが起きています。
これは何故起きるかというと、ゲームオブジェクトが見つからなかったので、変数gにはnullが入っています。
「g.」の部分が何もないカラっぽのものをアクセスしようとしているのでエラーが起きています。
このように、NullReferenceExceptionはカラっぽのものにアクセスしようとすると起きるエラーです。とてもよく見ると思うので覚えておきましょう。
ちなみに、GetComponentで指定した型のコンポーネントがなかった場合もnullが返ってきます。
<まとめ>
さて、今回はインスタンスを取得したり、作ったりする方法について解説しました。色々なものを操作する上でインスタンスを理解しておくのは重要なので覚えておいてください。