[Unity] 入門講座 #01 : GameObject と Component の本質的な関係

はじめに

Unity入門講座、第二回。

個人的に、プログラミング経験はあり仕事でも簡単なJavaのコードを書いてスマホアプリを書いたことがあったり、JavaScriptは全くの初心者でしたが、Three.jsで一ヵ月アプリ開発した経験をベースにUintyを学ぶ講座になります。

初心者向けでない可能性があるのでご了承ください。

前回の記事。

Three.jsの記事:

GameObject と Component の関係とは何か

“クラスを書いただけでは Unity では何も起きない理由” を解き明かす回。 C# の知識を持った人が Unity を触ったときにぶつかる「class 書いたのに何も起きないじゃん」を整理する。

1. GameObject は「ただの箱」である

Unity を触り始めた直後、多くの人がまず誤解するのがここだ。 GameObject 自体は、何もしない。

GameObject が最初から持っているものは、かなり限定されている。

  • 名前
  • 位置(Position)
  • 回転(Rotation)
  • 拡縮(Scale)

これだけを見ると「いや、それだけで画面に出てるし動いてるじゃん」と感じるが、 それはすでに Component が付いているから だ。


GameObject は「キャラクター」でも「敵」でも「弾」でもない。 それらはすべて 役割を与えられた結果 にすぎない。

Unity における GameObject の正体は、

Component を載せるための土台

これに尽きる。


たとえば、Scene に新しく GameObject を作った直後を思い出してほしい。

  • 見た目はない
  • 動かない
  • 当たり判定もない
  • 何の処理も走らない

それでも GameObject は存在している。 何もできない状態で、ちゃんと存在している。

この時点で GameObject は「空の箱」だ。


では、ゲームとして意味を持つのはいつか。 答えは単純で、

  • 描画する Component を付けたとき
  • 動かす Component を付けたとき
  • 判定を行う Component を付けたとき

その瞬間から、GameObject は役割を持ち始める。

Unity では、 「このオブジェクトは何者か」は GameObject では決まらない。 付いている Component の集合で決まる。


ここで重要なのは、 Unity が「クラス中心」ではなく「構成中心」で設計されている点だ。

多くのプログラムでは、

  • クラスがあって
  • そのクラスのインスタンスが振る舞いを持つ

という流れになる。

Unity は違う。

  • GameObject が先にあり
  • そこに Component を足していく

この違いが、 「class を書いたのに何も起きない」 「new してないのに動いてる」 という違和感の正体になる。


専門用語で言えば、これは “Entity に Component を組み合わせて振る舞いを定義する設計” だが、 今は名前を覚える必要はない。

大事なのは一つだけ。

GameObject は中身を持たない。 中身はすべて Component が決める。

この前提を頭に入れた瞬間、 Unity の構造は一気に読みやすくなる。

2. Component がクラスの代わりに“振る舞い”を担当する

C# に慣れていると、ついこう考えてしまう。

クラスを書けば、その機能がそこにある

Unity では、この感覚がそのまま通用しない。


Unity における class は、 「動作そのもの」ではなく、コンポーネントを作るための設計書 だ。

スクリプトを書いて保存した瞬間、 そのクラスがゲーム世界で何かをし始めるわけではない。 Scene にも影響は出ないし、勝手に処理が走ることもない。

なぜなら、そのクラスはまだ どの GameObject にも属していないから だ。


Unity で実際に動いているのは、クラスそのものではない。

  • GameObject にアタッチされた
  • Component として存在している
  • 実体を持ったインスタンス

この条件を満たしたものだけが、 ゲーム世界の中で「存在しているもの」として扱われる。

クラスはあくまで型。 動くのは、アタッチされたコンポーネントのインスタンス だ。


ここで、よくある疑問が一つ浮かぶ。

じゃあ new してインスタンスを作ればいいのでは?

Unity では、それでは不十分になる。

new で作ったインスタンスは、 Unity の管理下に置かれていない。 Scene にも属さず、GameObject とも結びつかない。

その結果、

  • Update は呼ばれない
  • Inspector にも表示されない
  • ライフサイクル管理もされない

存在はしているが、世界に参加していない状態 になる。


Unity において、

  • 「このオブジェクトは動く」
  • 「このオブジェクトは描画される」
  • 「このオブジェクトは当たり判定を持つ」

こうした性質は、 どの Component がアタッチされているか で決まる。

GameObject にアタッチされた瞬間、 そのクラスは初めて意味を持つ。


だからこそ、

クラスを書いたのに何も起きない

という現象が起こる。

それは失敗でも不具合でもない。 Unity にとっては 正しい挙動 だ。

クラスは機能ではない。 Component になって、GameObject に組み込まれて初めて機能になる。

この考え方を受け入れられるかどうかが、 Unity を理解できるかどうかの最初の分かれ目になる。

3. なぜ“アタッチ”という手順が必要なのか

ここまで読んで、ほぼ確実に浮かんでいる疑問がある。

なぜわざわざ「アタッチ」なんて手順を踏ませるのか コードで全部完結させればいいのでは?

Unity がこの設計を選んだ理由は、かなりはっきりしている。


Unity は 「どの GameObject が、どの機能を持つか」を コードではなく構成として決める エンジンだ。

GameObject は土台で、 Component は後から載せる部品。

この組み合わせを 宣言的に定義する ことで、 オブジェクトの役割を作っていく。


もしすべてをコードで完結させるとどうなるか。

  • new する
  • 参照を保持する
  • 破棄タイミングを管理する
  • 実行順を制御する

これらを、すべて自分で書くことになる。

Unity は、そこを開発者にやらせない。


アタッチされた Component は、 Unity の管理下に入る。

  • いつ生成され
  • いつ初期化され
  • いつ Update が呼ばれ
  • いつ破棄されるか

これらはすべて Unity が責任を持って処理する。

だから開発者は、

  • どう動くか
  • どんな役割か

だけを書けばいい。


GameObject をレゴブロックの土台だとすると、 Component は後から差し込めるブロックだ。

  • 動くブロック
  • 描画するブロック
  • 判定するブロック

組み合わせを変えれば、 同じ土台から全く違う役割が生まれる。

この柔軟性が、 アタッチという手順の正体だ。


前回触れた

new していないのに動いている

という現象も、ここで説明がつく。

new しているのは Unity。 呼び出しているのも Unity。

開発者は 「この GameObject にはこの Component を使う」 と宣言しているだけだ。


アタッチとは、 処理を呼び出す行為ではない。

「このオブジェクトは、こういう構成です」 と Unity に伝えるための手続き だ。

この前提を理解すると、 Unity の設計は不思議でも不親切でもなく、 かなり合理的なものに見えてくる。

4. なぜ Inspector が存在するのか

4. なぜ Inspector が存在するのか

Inspector は、見た目だけを見ると 「コンポーネントの設定値をいじるための UI」 に見える。

だが Unity において Inspector は、 補助的な画面ではない。

設計の中核に組み込まれた操作系 だ。


Inspector が扱っているのは、 コードではなく GameObject の状態そのもの だ。

  • どの Component が付いているか
  • それぞれがどんな値を持っているか
  • 今この Scene でどう構成されているか

これらを 直接編集できる唯一の入口 が Inspector になる。


もし、すべての値をコードに直書きしたらどうなるか。

  • 数値を変えるたびにスクリプトを書き換える
  • 保存して
  • 再コンパイルして
  • 実行し直す

これは、試行錯誤が前提のゲーム開発と致命的に相性が悪い。

Inspector は、そのために存在している。


Inspector に値を出すという行為は、 「楽をするため」ではない。

パラメータを設計として切り出す という意味を持つ。

  • 移動速度
  • 攻撃力
  • クールタイム
  • 判定サイズ

これらをコードから分離することで、

  • 動作ロジックはコードに
  • 調整は Inspector に

という役割分担が成立する。


この構造があるから、 エンジニア以外の人間も開発に参加できる。

  • 数値を触る
  • 組み合わせを変える
  • その場で結果を見る

Unity が「ツール主導のゲームエンジン」と言われる理由は、 まさにここにある。


もう一つ重要なのは、 Component を付け替えるという行為自体が、Inspector 操作を前提にしている 点だ。

  • このオブジェクトは今は動かない
  • 判定だけ欲しい
  • 表示だけしたい

こうした変更を、 コードを書き換えずに行える。

これは 「処理を呼び出す」発想ではなく、 構成を差し替える 発想だからこそ成立する。


Inspector は設定画面ではない。

GameObject と Component の関係を、 人間が直接編集できるための操作層 だ。

これを単なる UI と捉えている限り、 Unity の設計思想は見えてこない。

5. “class だけでは意味がない” の真意

ここまでの流れの集大成になるポイントだ。 Unity を理解するとき、この発想の転換が最も重要になる。


Unity では、クラスを書いても何も起きない。 これは「ミスだから動かない」わけではなく、

“クラス単体には存在価値がない”

という Unity の設計そのものだ。


GameObject と結びつかない限り “世界に出てこない”

クラスを書いた瞬間は、ただのファイルにすぎない。

  • GameObject にアタッチされていない
  • Scene に配置されていない
  • Unity によって生成されていない

この状態では、コードは世界のどこにも所属していない。

だから何も起きないし、イベントも呼ばれない。


new しても Unity はそのインスタンスを知らない

new すれば C# 的にはインスタンスは生まれる。 だが Unity はそれを 管理対象として扱わない。

  • Update は呼ばれない
  • Start も Awake も走らない
  • Inspector にも出ない
  • シーンにも存在しない

生まれてはいるが、 Unity の“世界”には存在していないオブジェクトだ。


class は用途ではなく “部品” として書く

C# のクラスは「用途を持ったモジュール」として書くが、 Unity のクラスは「GameObject に載せる部品」として書く。

  • 部品の設計図(class)を書く
  • 土台(GameObject)に取り付ける
  • Unity がライフサイクルを管理し始める

この流れを踏んで初めて、 クラスが「機能」としての意味を持つ。


設置されて初めて動き始める

スクリプトを作った時点では、 何も“始まっていない”。

アタッチされた瞬間に初めて、 Unity はそれを

  • 生成し
  • 初期化し
  • イベントループに参加させる

ここで初めて、 作ったクラスがゲーム世界で動き始める。


Unity の開発では、 「クラスを書く→動く」ではなく、 「クラスを書く→配置する→Unity が動かす」という構造になる。

この仕組みを理解していると、 MonoBehaviour の本質も、Update が呼ばれる理由も、 すべて筋が通って見えてくる。


6. 次回(MonoBehaviour)へ自然につなぐ導線

ここまでで、 GameObject と Component の関係は見えてきた。

  • GameObject は箱
  • Component が振る舞い
  • class は部品の設計書
  • アタッチされて初めて世界に参加する

ただし、ここで一つだけ まだ説明していない重要な条件が残っている。


Component として振る舞うためには、 ただのクラスでは足りない。

Unity のイベントループに参加するには、 満たすべき「資格」がある。

それが MonoBehaviour を継承していること だ。


Update、Start、Awake といったメソッドは、 C# の通常の意味では どこからも呼ばれていない。

それでも毎フレーム確実に実行されるのは、 Unity が

  • このクラスは MonoBehaviour である
  • このインスタンスは GameObject にアタッチされている

という条件を満たしたものだけを、 イベントループの対象として扱う からだ。


ここで初めて、

  • なぜ Update という名前なのか
  • なぜ override しないのか
  • なぜ自分で呼ばなくても動くのか

という疑問が、一つの線でつながり始める。


次回は、 MonoBehaviour は何者なのか を正面から扱う。

継承の意味、 イベントループへの参加条件、 Update が呼ばれる本当の理由。

Unity が「普通の C# プログラムではない」と言われる理由を、 もう一段深いところから解体していく。