タイトル: ゲームオブジェクト(Game Object)
SEOタイトル: Unity GameObject (ゲームオブジェクト) 完全ガイド
| この記事の要点 |
|
GameObject とは
Unity の GameObject は、Hierarchy ウィンドウに表示される全てのオブジェクトの基底クラスです。プレイヤー、敵、カメラ、ライト、UI ボタン、効果音発生源、空のゲームオブジェクト — 全て GameObject インスタンスです。
GameObject 単体は空の箱に過ぎません。座標 (Transform) を持ち、そこに Component を追加することで初めて意味を持ちます。
GameObject と Component の関係
GameObject "Player"
├── Transform ← 必須。位置・回転・スケール
├── MeshFilter ← 描画する形状
├── MeshRenderer ← 描画するマテリアル
├── BoxCollider ← 当たり判定
├── Rigidbody ← 物理演算
├── AudioSource ← 音再生
├── Animator ← アニメーション
└── PlayerController (Script) ← 自作スクリプト
Unity はComposition over Inheritanceのフィロソフィー: 1 つの巨大なクラスを継承するのではなく、機能ごとの小さな Component を組み合わせて GameObject を作ります。
Transform は必須 Component
GameObject から削除できない唯一の Component。3D 空間における位置 / 回転 / スケールを持ちます:
// 位置・回転・スケール
transform.position = new Vector3(0, 1, 0);
transform.rotation = Quaternion.Euler(0, 90, 0);
transform.localScale = new Vector3(2, 2, 2);
// ローカル座標 (親に対する相対位置)
transform.localPosition = Vector3.zero;
transform.localRotation = Quaternion.identity;
// 親子関係
transform.SetParent(otherGameObject.transform); // 親を変える
transform.parent = otherGameObject.transform; // 同上 (旧 API)
transform.DetachChildren(); // 全子を切り離す
// 子オブジェクトのアクセス
foreach (Transform child in transform) { ... }
Transform t = transform.GetChild(0);
Transform t = transform.Find("Sword"); // 名前検索
// 移動 (時間と無関係)
transform.Translate(Vector3.forward * 0.1f);
// Time.deltaTime と組み合わせて FPS 非依存
transform.position += Vector3.forward * speed * Time.deltaTime;
GameObject の生成と削除
// Prefab から複製生成
public GameObject enemyPrefab;
GameObject enemy = Instantiate(enemyPrefab, spawnPos, Quaternion.identity);
// 親子付きで生成
Instantiate(enemyPrefab, parentTransform);
// 動的に空のオブジェクト生成
GameObject go = new GameObject("MyObject");
go.AddComponent<Rigidbody>();
go.AddComponent<BoxCollider>();
go.tag = "Enemy";
go.layer = LayerMask.NameToLayer("Enemy");
// 削除
Destroy(enemy); // 次フレームで削除
Destroy(enemy, 5f); // 5 秒後に削除
DestroyImmediate(enemy); // 即削除 (Editor のみ推奨)
// シーンを跨いで生存させる
DontDestroyOnLoad(go);
GameObject の有効化 / 無効化
削除せず非表示にする定番手段。Component の処理も止まる:
// 無効化 (子も含めて Update / Render が止まる)
gameObject.SetActive(false);
// 再有効化
gameObject.SetActive(true);
// 状態確認
if (gameObject.activeSelf) { ... } // 自身の active 状態
if (gameObject.activeInHierarchy) { ... } // 親も含めた最終状態
// 個別 Component だけ無効化
GetComponent<Renderer>().enabled = false; // 見えなくするだけ
GetComponent<Collider>().enabled = false; // 当たり判定だけ消す
GetComponent<MonoBehaviour>().enabled = false; // Update を止める
Component のアクセスと操作
// Component を取得
Rigidbody rb = GetComponent<Rigidbody>();
if (rb != null) rb.AddForce(Vector3.up * 10);
// TryGetComponent (null チェック不要、Unity 2019.2+ で高速)
if (TryGetComponent<Rigidbody>(out var rb)) {
rb.AddForce(Vector3.up * 10);
}
// 子から検索
Animator anim = GetComponentInChildren<Animator>();
// 親から検索
Canvas canvas = GetComponentInParent<Canvas>();
// 全 Component
Component[] all = GetComponents<Component>();
// 動的追加 / 削除
Rigidbody added = gameObject.AddComponent<Rigidbody>();
Destroy(GetComponent<BoxCollider>());
Tag と Layer
大量の GameObject から特定種類を識別するための仕組み。Tag は文字列、Layer はビット (32 種類まで):
// Tag (文字列分類)
gameObject.tag = "Enemy";
if (other.CompareTag("Player")) { ... } // 比較は CompareTag が高速
// Layer (ビット分類、衝突マスクなどで使う)
gameObject.layer = LayerMask.NameToLayer("Enemy");
int mask = LayerMask.GetMask("Player", "Enemy");
Physics.Raycast(origin, dir, out hit, 100f, mask);
// LayerMask + Physics.IgnoreLayerCollision で当たり判定の有無を制御
Physics.IgnoreLayerCollision(8, 9, true);
GameObject の検索
// 名前で検索 (遅い、Start で一度だけ推奨)
GameObject p = GameObject.Find("Player");
// Tag で検索
GameObject p = GameObject.FindWithTag("Player");
GameObject[] enemies = GameObject.FindGameObjectsWithTag("Enemy");
// 型で検索 (Unity 2023+: FindFirstObjectByType / FindObjectsByType を推奨)
PlayerController pc = FindFirstObjectByType<PlayerController>();
PlayerController[] all = FindObjectsByType<PlayerController>(FindObjectsSortMode.None);
// ❌ 旧 API (Unity 2023 で非推奨)
FindObjectOfType<PlayerController>();
FindObjectsOfType<PlayerController>();
Prefab との関係
Prefab は GameObject のテンプレート。Project ウィンドウに保存され、シーン内に何度も Instantiate できます:
- Hierarchy の GameObject を Project ウィンドウへドラッグ → Prefab 化
- Prefab を編集すると、全インスタンスに変更が反映される
- インスタンス側の変更は override として保持
- Prefab Variant でテンプレートの派生を作成可能
- Nested Prefab で Prefab の中に Prefab を入れられる
Singleton GameObject パターン
ゲーム全体で 1 つだけ存在するマネージャ用パターン:
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }
void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
}
public int score;
public void AddScore(int amount) { score += amount; }
}
// どこからでも
GameManager.Instance.AddScore(10);
ECS (Unity DOTS) との比較
Unity の伝統的 GameObject + MonoBehaviour は柔軟ですが、数千 〜 数万体を処理すると CPU/GC が辛くなります。Unity DOTS (Data-Oriented Technology Stack) の ECS はその解決策:
| 項目 | GameObject + Component | ECS (Entity Component System) |
|---|---|---|
| 主体 | GameObject (オブジェクト指向) | Entity (ID のみ、データなし) |
| データ | Component 内に混在 | 純粋データの Component (struct) |
| 処理 | 各 Component の Update | System が一括処理 |
| 得意 | 少数の凝った挙動 | 大量同種オブジェクト |
| 難易度 | 低 (Unity 標準) | 高 (DOTS 学習必要) |
FAQ
Q: Find() は遅いと聞くが?
A: シーン内の全 GameObject を線形探索するので遅い。Start() で 1 回だけ呼んでキャッシュするか、Inspector の public GameObject でドラッグ参照を推奨。
Q: GameObject を delete するのと SetActive(false) はどう違う?
A: Destroy はメモリ解放 + GC 対象、SetActive(false) は単に非表示 + 処理停止。再利用する弾丸・敵にはObject Pooling + SetActive がお得。
Q: GameObject の名前を実行時に変えていい?
A: 可能 (gameObject.name = "Foo") ですが、名前で Find している箇所が壊れます。識別は Tag / Layer / 参照キャッシュを推奨。