new GameObject()から作ってみよう ― UnityのComponentはどう組み合わさるのか
UnityでGameObjectを扱っていると、画面に見えているオブジェクトが最初から「完成したひとつの部品」であるように感じることがあります。
たとえば、ゲームの中にある四角い物体には、
- 画面に表示される
- 当たり判定がある
- 重力で落下する
といった機能があります。
一見すると、これらすべてが「四角い物体」というひとつの部品に入っているように見えます。
しかしUnityでは、これらの機能をComponentとして分け、それらを組み合わせてGameObjectを作るという考え方が基本です。
今回は、あえて
new GameObject()
から始めて、必要なComponentをひとつずつ追加してみます。
- 1. 1. 今回使うSpriteを用意する
- 2. 2. まずは空のGameObjectを作る
- 3. 3. SpriteRendererを追加する
- 4. 4. SpriteRendererを付けただけでは表示されない
- 5. 5. Spriteを設定する
- 6. 6. 当たり判定を追加する
- 7. 7. Rigidbody2Dを追加する
- 8. 8. それぞれのComponentには役割がある
- 9. 9. 「落下する四角形」というクラスを作ったわけではない
- 10. 10.
new GameObject()は完成品を作っているわけではない - 11. 11. WinFormsのButtonと比べてみる
- 12. 12. なぜComponentを組み合わせるのか
- 13. 13. 足し算で考えると分かりやすい
- 14. 14. まとめ
- 15. 関連記事
1. 今回使うSpriteを用意する
今回は2Dの四角いオブジェクトを作ります。
まず、四角形のSprite画像を1枚用意して、Unityのプロジェクトに入れておきます。
たとえば次のように配置します。
この記事の目的はSprite画像の作り方ではなく、
GameObjectにComponentを追加して、機能を組み合わせていく仕組みを理解すること
です。
そのため、今回はSprite画像はあらかじめ用意してあるものとして進めます。
2. まずは空のGameObjectを作る
最初に、次のスクリプトを作ります。
using UnityEngine;
public class ObjectMaker : MonoBehaviour
{
void Start()
{
GameObject obj = new GameObject("FallingObject");
}
}
new GameObject()によって、新しいGameObjectが作られます。
このスクリプトを適当なGameObjectに付けて実行してみましょう。
Hierarchyを見ると、
というGameObjectが作られていることが確認できます。
ところが、Gameビューには何も表示されません。
なぜでしょうか。
作ったGameObjectをInspectorで見ると、最初から次のComponentが付いています。
new GameObject()でGameObjectを作ると、Transformは自動的に付いています。
しかし、まだ画面に表示するための機能はありません。
つまり、
GameObjectは存在しているけれど、見た目がない
という状態です。
3. SpriteRendererを追加する
2D画像を画面に表示するためには、SpriteRendererが必要です。
そこで、GameObjectにSpriteRendererを追加してみます。
GameObject obj = new GameObject("FallingObject");
obj.AddComponent<SpriteRenderer>();
これでGameObjectの構成は次のようになります。
では、これで四角形が表示されるでしょうか。
実行してみると、まだ何も表示されません。
4. SpriteRendererを付けただけでは表示されない
ここが重要です。
SpriteRendererは、
Spriteを画面に描画するためのComponent
です。
しかし今の状態では、
何を描画するのか
がまだ決まっていません。
たとえるなら、
は用意できたけれど、
が渡されていない状態です。
Componentを追加したからといって、それだけですべての機能が完成するとは限りません。
5. Spriteを設定する
そこで、先ほど用意したBox.pngをSpriteRendererに設定します。
まず、スクリプトに次のフィールドを追加します。
[SerializeField]
private Sprite boxSprite;
次に、SpriteRendererを取得し、そのspriteに設定します。
SpriteRenderer spriteRenderer = obj.AddComponent<SpriteRenderer>();
spriteRenderer.sprite = boxSprite;
ここまでのコードは次のようになります。
using UnityEngine;
public class ObjectMaker : MonoBehaviour
{
[SerializeField]
private Sprite boxSprite;
void Start()
{
GameObject obj = new GameObject("FallingObject");
SpriteRenderer spriteRenderer = obj.AddComponent<SpriteRenderer>();
spriteRenderer.sprite = boxSprite;
}
}
Unityに戻ると、InspectorにBox Spriteという欄が表示されます。
そこへ、用意したBox.pngを設定します。
イメージとしては次のようになります。
実行すると、今度は四角形が画面に表示されます。
GameObjectの構成は次のようになりました。
ここで、
GameObjectそのものに見た目があるわけではない
という点に注目してください。
SpriteRendererというComponentが、設定されたSpriteを描画しています。
6. 当たり判定を追加する
次に、この四角形に当たり判定を付けます。
2Dの四角形なので、BoxCollider2Dを追加します。
obj.AddComponent<BoxCollider2D>();
構成は次のようになります。
これで、このGameObjectは四角形の当たり判定を持つようになりました。
しかし、まだ重力では落ちません。
なぜでしょうか。
BoxCollider2Dの役割は、あくまで当たり判定を作ることだからです。
当たり判定と、物理的に動くことは別の機能です。
7. Rigidbody2Dを追加する
重力の影響を受けて動くようにするには、Rigidbody2Dを追加します。
obj.AddComponent<Rigidbody2D>();
さらに、最初の位置を少し上にしておきます。
obj.transform.position = new Vector3(0, 3, 0);
完成したコードは次のようになります。
using UnityEngine;
public class ObjectMaker : MonoBehaviour
{
[SerializeField]
private Sprite boxSprite;
void Start()
{
GameObject obj = new GameObject("FallingObject");
SpriteRenderer spriteRenderer = obj.AddComponent<SpriteRenderer>();
spriteRenderer.sprite = boxSprite;
obj.AddComponent<BoxCollider2D>();
obj.AddComponent<Rigidbody2D>();
obj.transform.position = new Vector3(0, 3, 0);
}
}
実行すると、四角形が上から落下します。
最終的なGameObjectの構成は次のようになります。
8. それぞれのComponentには役割がある
今回使ったComponentを整理してみましょう。
| Component | 役割 |
|---|---|
| Transform | 位置・回転・大きさを管理する |
| SpriteRenderer | Spriteを画面に表示する |
| BoxCollider2D | 四角形の当たり判定を作る |
| Rigidbody2D | 重力や物理運動を扱う |
大切なのは、
ひとつのComponentですべてを行っているわけではない
ということです。
たとえば、
だけなら表示はできますが、重力では落ちません。
だけなら物理運動はできますが、見た目はありません。
だけなら当たり判定はありますが、自動的に落下するわけではありません。
それぞれが別々の役割を担当しています。
9. 「落下する四角形」というクラスを作ったわけではない
今回作ったものを見ると、
FallingObjectという「落下する四角形」を作った
と考えたくなるかもしれません。
しかし実際には、
を組み合わせただけです。
つまり、
によって、
になったわけです。
この考え方は、Unityを理解するうえで非常に重要です。
10. new GameObject()は完成品を作っているわけではない
C#を学んでいると、
new GameObject()
というコードを見て、
GameObjectという完成したオブジェクトを作っている
ように感じるかもしれません。
しかしUnityでは、
GameObject obj = new GameObject();
は、
Componentを取り付けるための土台を作った
と考えると分かりやすくなります。
最初は、
だけです。
そこへ、
obj.AddComponent<SpriteRenderer>();
obj.AddComponent<BoxCollider2D>();
obj.AddComponent<Rigidbody2D>();
と機能を追加していきます。
つまり、
という流れです。
11. WinFormsのButtonと比べてみる
ここで、WinFormsと比較してみます。
WinFormsでは、ボタンを作るときに次のように書けます。
Button button = new Button();
Buttonというクラスそのものが、ボタンとして必要な多くの機能を持っています。
イメージとしては、
です。
一方、Unityで
GameObject obj = new GameObject();
とした場合は、まだ土台に近い状態です。
Unityでは、完成した部品をひとつ作るというより、必要な機能を組み合わせて作るという考え方が強く使われています。
詳しくは、WinFormsのButtonからUnityのGameObjectへ ― newとComponentの違いを比べてみようで解説しています。
12. なぜComponentを組み合わせるのか
では、なぜUnityはこのような仕組みなのでしょうか。
たとえば、
という「落下する四角形専用クラス」を作ることも考えられます。
しかしゲームを作っていると、必要な機能の組み合わせはさまざまです。
たとえば、
- 表示はするが、当たり判定はいらない
- 当たり判定はあるが、重力はいらない
- 重力は必要だが、四角形ではなく別のSpriteを使いたい
- 音を鳴らしたい
- アニメーションさせたい
- 独自のスクリプトを動かしたい
といった違いがあります。
もし組み合わせごとに専用クラスを作っていくと、クラスの種類がどんどん増えてしまいます。
そこでUnityでは、
といった機能をComponentとして分けておき、必要なものを組み合わせられるようになっています。
13. 足し算で考えると分かりやすい
UnityのGameObjectは、次のように「足し算」で考えると分かりやすくなります。
さらに、
さらに、
つまりUnityでは、
必要な機能を後から足していく
という考え方がよく使われます。
これは、継承だけでクラスを作り分ける方法とは違う考え方で、コンポジション(組み合わせ)と呼ばれます。詳しくは、継承の次に学びたい「コンポジション」― 継承より組み合わせを考えるで解説しています。
14. まとめ
今回は、
GameObject obj = new GameObject();
という空に近いGameObjectから始めました。
最初は、
だけでした。
そこへ、
obj.AddComponent<SpriteRenderer>();
obj.AddComponent<BoxCollider2D>();
obj.AddComponent<Rigidbody2D>();
とComponentを追加しました。
最終的には、
となりました。
そして、それぞれのComponentが、
という別々の役割を担当しています。
Unityでは、
完成した巨大なクラスをひとつ作るのではなく、GameObjectに必要なComponentを組み合わせて機能を作っていく
という考え方が基本になっています。
これからnew GameObject()を見るときは、
完成したオブジェクトができた
ではなく、
Componentを追加するための土台ができた
と考えてみてください。
UnityのGameObjectとComponentの関係が、少し見えやすくなるはずです。
関連記事
- GameObject と Transform … オブジェクトの配置と操作
- Unity におけるオブジェクトの考え方 … シーン・GameObject・コンポーネント
- GameObject クラス … Instantiate・Destroy・Find・SetActive
- 継承の次に学びたい「コンポジション」 … 継承より組み合わせを考える
- Unity 入門シリーズ … シリーズの目次








ディスカッション
コメント一覧
まだ、コメントがありません