この記事では、コンポーネントにアクセスするための方法を説明します。コンポーネントはゲームオブジェクトの性質を決めるものです。Unityにおけるゲーム制作の基本はコンポーネントの設定をプレイヤーのキー入力に対して操作することです。これにより、プレイヤーキャラクターの移動などのアクションが実現されます。
Unityプログラミング講座一覧はこちら
Transformコンポーネントにアクセスする
Transformはすべてのゲームオブジェクトが持っているコンポーネントであり、使用頻度も高いため、簡単にアクセスできるようになっています。具体的にはtransform
と打つだけでアクセスできます。
大文字と小文字は区別されるので、間違えないようにしましょう。小文字で始まるtransform
が自分自身のTransformコンポーネントを表します。
位置を変更する
何か処理をしたい場合にはドット.
を打って使用したい機能を指定します。例えば、位置を(1, 0, 0)に変更するスクリプトは以下のようになります。
using UnityEngine;
class ChangePosition : MonoBehaviour
{
void Start()
{
// Transformコンポーネントにアクセスして位置を変える
transform.position = new Vector3(1f, 0f, 0f);
}
}
※前にも述べたように、コンポーネントとスクリプトのファイル名は同じにし、ゲームオブジェクトにアタッチしてください。
position
に代入できるのはデータ型がVector3
の変数です。Vector3
は3次元ベクトルを表す型で座標などに用いられます。Vector3
型は内部にfloat型の変数x, y, z
を持ちます。新しくVector3
型のデータを作成する場合はnew Vector3(x, y, z)
のように書きます。
// (1, 2.5, 3)のベクトルを作成して変数vecに代入
Vector3 vec = new Vector3(1f, 2.5f, 3f);
必要なデータ型を調べるには?
スクリプトを書くのにVisual Studioを使用している場合にはマウスを合わせると確認できます。例えば、positionの場所にマウスを合わせると、次のように表示されます。
Vector3 Transform.position {get; set;}
ポップアップの最初に書かれているVector3がデータ型になります。(get; set;というのは読み書き可能かどうかを表していて、getが書かれていたら読取可能、setが書かれていたら書込可能という意味です。)
キー入力に対応する
上記の例ではStart
メソッドで座標を変更しているため、ゲーム開始と同時に位置が変更された後は何も起こりません。せっかくですから、ボタンを押すたびに位置が変わるコンポーネントを書いてみましょう。(キー入力については前回の記事を見てください。)
クリックするたびにx座標が1増える自作コンポーネントは以下のように書けます。
using UnityEngine;
class ChangePosition : MonoBehaviour
{
void Update()
{
// 左クリックが押されたら処理を行う
if (Input.GetKeyDown(KeyCode.Mouse0))
{
// 現在位置を変数posに代入
Vector3 pos = transform.position;
// 変数posのxの値を1増やす
pos.x += 1f;
// 変数posをTransformコンポーネントのpositionに代入
transform.position = pos;
}
}
}
「動けばよい」だったらこれでも良いのですが、実行速度を気にする場合には注意点があります。transform
は裏側で「コンポーネントを検索してアクセスする」という処理をしているので、何度も使用する場合はtransform
で取得したものを変数に代入して保持しておくのが良いです。こうすることで、「検索する」行為を行わずに何度もアクセスできます。
(このように、取得や計算に時間のかかる処理を何度も行わないで済むように、一度得られた結果を記憶しておくことをキャッシュする、などと言います。日常で例えるなら、九九とかでしょうか。9×9の計算に9を9回足すのは時間が掛かるので、皆さん9×9=81って覚えているでしょう?)
using UnityEngine;
class ChangePosition : MonoBehaviour
{
// Transform型の変数
Transform myTransform;
void Start()
{
// 変数に代入してキャッシュする
myTransform = transform;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
// transformを使わずに変数myTransformを使用
Vector3 pos = myTransform.position;
pos.x += 1f;
myTransform.position = pos;
}
}
}
GetComponentでコンポーネントにアクセスする
Transformコンポーネント以外にアクセスする場合にはGetComponent
メソッドを使用します。以下の形で使用することが多いと思います。
コンポーネント名 変数名 = GetComponent<コンポーネント名>();
※<>
の意味が気になる人は「C# ジェネリック」で調べてみましょう。内容的には中級者以上な気がします。
Transformコンポーネントにアクセスする
小文字で始まるtranform
でもアクセスできますが、当然GetComponent
を用いてもアクセスできます。というより、小文字のtransform
は内部でGetComponent
を呼び出しているので、実質同じです。
上記のスクリプトのStartメソッドの部分をGetComponent
で書くとこうなります。
...
void Start()
{
// GetComponentメソッドでTransformコンポーネントを取得
myTransform = GetComponent<Transform>();
}
...
Rendererコンポーネントにアクセスする
描画を行うRendererコンポーネントにアクセスして、マテリアルを変更してみます。
using UnityEngine;
class ChangeMaterial : MonoBehaviour
{
// Rendererコンポーネントを保持するための変数
Renderer myRenderer;
void Start()
{
// Rendererコンポーネントにアクセスして変数に代入
myRenderer = GetComponent<Renderer>();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
// Rendererに設定されているマテリアルの色を変更する
myRenderer.material.color = new Color(1f, 0f, 0f);
}
}
}
Rendererコンポーネントに設定されているマテリアルはmaterial
によってアクセス可能です。ここでは、色を変更するために、material
の設定の一つであるcolor
にアクセスしています。color
に代入できるのはColor
型のデータなので、Vector3型と同様にnew Color(r, g, b)
と書いて色を指定しています。(r, g, bは色の三原色である赤、緑、青の成分で、0から1のfloat値で指定します。)
自作コンポーネントにアクセスする
GetComponentは好きなコンポーネントにアクセスすることができるメソッドです。ということは当然、スクリプトを書いて作成した自作コンポーネントにもアクセスができます。
実際に試してみましょう。はじめに、変数countの値が0以下になったらRendererコンポーネントの機能をOFFにするCountDownコンポーネントを作成してみます。コンポーネントの機能をOFFにするにはenabled
の値をfalse
に設定することで実現できます。
using UnityEngine;
class CountDown : MonoBehaviour
{
// カウントダウン用の変数
public int count = 3; // 外部からアクセスできるようにpublicをつける
Renderer myRenderer;
void Start()
{
myRenderer = GetComponent<Renderer>();
}
void Update()
{
if(count <= 0)
{
// Rendererコンポーネントの機能をOFFにする
myRenderer.enabled = false;
}
}
}
これだけでは、countの値が変更されることがないため、Rendererの機能がOFFになることはありません。そこで、CountDownコンポーネントにアクセスしてcountの値を変えるコンポーネントを作成します。
using UnityEngine;
public class ChangeCount : MonoBehaviour
{
// CountDownコンポーネントを保持するための変数を用意
CountDown countDown;
void Start()
{
// CountDownコンポーネントにアクセスして変数に代入
countDown = GetComponent<CountDown>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
// CountDownコンポーネントのcountの値を1減らす
countDown.count--;
}
}
}
作成した2つのコンポーネントを同じゲームオブジェクトにアタッチしてください。
同じゲームオブジェクトにアタッチしていない場合には、CountDownコンポーネントが見つからないため、エラーが起こります。
NullReferenceException
は存在しないものにアクセスしようとした場合に起こるエラーです。非常に良く見るエラーなので、気をつけましょう。
コンポーネントを2つに分ける意味は?
自作コンポーネントを2つ作成してアクセスする方法を書きましたが、現段階ではわざわざ2つのプログラムファイルに分ける意味(メリット)がわからないかもしれません。
プログラムを複数のファイルに分ける利点は「分類して扱いやすくすること」にあります。例えば、学校で授業を受けるときには国語の授業なら国語のノート、算数の授業なら算数のノートというようにノートを変えるはずです。もし、課目ごとに分けずに1つのノートにすべての板書を写したとしたらどうなるでしょうか。あとで見返すときに、目当ての科目がどのページにあるかわからず、混乱するでしょう。プログラムでも同様です。機能ごとに分けたほうが整理やチェックが楽になります。
良いことは他にもあります。それは使いまわしが可能になることです。部品を取って変えるかのように、機能ごとに分かれたプログラムを組み合わせて様々な機能が実現できるようになります。
実際、Unityが用意しているコンポーネントも位置や大きさを担当するTransform、描画を担当するRenderer、衝突判定を担当するColliderなど機能ごとに分かれて作られています。このおかげで、似たような処理を何度も書かずに済むのです。
まとめ
この記事ではコンポーネントにアクセスする方法を学びました。コンポーネントに自由にアクセスできるようになれば、あとはコンポーネントの機能を操作してやるだけでゲームらしい動きが実現できるようになります。
ここまでくれば、Unityの基本的な考え方は身に着けたといっても過言ではありません。あとは実際のゲーム制作を通して、必要なコンポーネントの機能を少しずつ学ぶだけです。
Unityプログラミング講座一覧はこちら