Unity の Hierarchy ビューでは、ゲームオブジェクトを木構造(ツリー構造)で管理できます。ある GameObject を別の GameObject の「子」にすることで、位置・回転・スケールの継承や、グループとしての一括管理が可能になります。
このページを読み終えると、以下のことができるようになります。
transform.parent と transform.SetParent() で親子関係を操作できるtransform.childCount・GetChild()・Find() で子オブジェクトを扱えるUnity の Hierarchy ビューでは、ゲームオブジェクトの左端にある ▶ をクリックすると「子オブジェクト」が展開されます。
1
2
3
4
5
6
Stage
Player
Items ← 親オブジェクト
├─ Item(Clone) ← 子オブジェクト
├─ Item(Clone)
└─ Item(Clone)
子は親の座標系を引き継ぎます。親を移動・回転させると、子もそれに追従して動きます。これを使うと関連するオブジェクトをグループとして一括操作できます。
エディターで親子関係を設定するには、Hierarchy ビューで子にしたいオブジェクトを親オブジェクトの上にドラッグ & ドロップします。
Transform.parent — このオブジェクトの親 Transform を取得または設定します。親がない場合(ルートオブジェクト)は null を返します。
書式:parent プロパティ
1
public Transform parent { get; set; }
1
2
3
4
if (transform.parent != null)
{
Debug.Log("親の名前: " + transform.parent.name);
}
Transform.SetParent() — 親 Transform を設定します。
書式:SetParent メソッド
1
2
public void SetParent(Transform parent);
public void SetParent(Transform parent, bool worldPositionStays);
| パラメータ | 説明 |
|---|---|
parent |
設定する親 Transform。null を指定するとルートに移動する |
worldPositionStays |
true(既定)でワールド座標を維持したまま親子を変更する。false でローカル座標が維持される |
1
2
3
4
5
// itemContainer を親にする(ワールド座標位置は維持)
transform.SetParent(itemContainer);
// 親をなくしてルートオブジェクトに移動する
transform.SetParent(null);
Unity の Transform には2種類の座標系があります。
| プロパティ | 説明 |
|---|---|
transform.position |
ワールド座標(シーン全体の原点を基準) |
transform.localPosition |
ローカル座標(親オブジェクトの位置を基準) |
transform.rotation |
ワールド回転 |
transform.localRotation |
ローカル回転(親からの相対) |
transform.localScale |
ローカルスケール(親スケールへの乗算) |
position / rotation / localScale は Transform ページ で解説済みです。このページでは親子関係に関わる local 系プロパティに注目します。
Transform.localPosition — 親オブジェクトを基準にしたローカル座標を取得または設定します。
書式:localPosition プロパティ
1
public Vector3 localPosition { get; set; }
Transform.localRotation — 親を基準にしたローカル回転を取得または設定します。
書式:localRotation プロパティ
1
public Quaternion localRotation { get; set; }
親オブジェクトの position.x が 3 で、子の localPosition.x が 1 の場合、子のワールド座標での X は 4 になります。
1
2
3
4
5
6
7
8
// ワールド座標(シーン全体での絶対位置)
Debug.Log(transform.position);
// ローカル座標(親を基準にした相対位置)
Debug.Log(transform.localPosition);
// 親の真上に配置(ローカル座標で Y=1 に移動)
transform.localPosition = new Vector3(0, 1, 0);
💡 ポイント: 「親を基準にどこに置くか」を制御したい場合は
localPositionを使います。「シーン全体でどこにあるか」を調べたい場合はpositionを使います。
親(Sun)が自転すると、子(Planet)がその周りを公転します。Planet の localPosition は常に (3, 0, 0)(Sun から見て右)で変わりませんが、position(ワールド座標)は Sun の回転に伴って毎フレーム変化します。
シーンの準備
Sun、Scale を (2, 2, 2) にするSun に SunRotator スクリプトを作成してアタッチするPlanet はスクリプト内で生成します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// SunRotator.cs — Sun にアタッチ
using UnityEngine;
public class SunRotator : MonoBehaviour
{
private Transform _planet;
private void Start()
{
// Planet を立方体で生成して Sun の子にする
var planetObj = GameObject.CreatePrimitive(PrimitiveType.Cube);
planetObj.name = "Planet";
_planet = planetObj.transform;
_planet.SetParent(transform);
_planet.localPosition = new Vector3(3, 0, 0);
}
private void Update()
{
// Sun を Y 軸周りに自転させる
transform.Rotate(0, 30f * Time.deltaTime, 0, Space.World);
// ローカル座標とワールド座標を並べて出力する
Debug.Log($"localPosition: {_planet.localPosition} | world position: {_planet.position}");
}
}
実行すると、Console ビューで localPosition は (3, 0, 0) のまま変化しないのに対し、position が毎フレーム異なる値になることを確認できます。立方体を使っているので、Sun の自転に対して Planet が追従して回っている様子も Scene ビューで見やすくなっています。
Transform.childCount — 直下の子オブジェクトの数を返します。
書式:childCount プロパティ
1
public int childCount { get; }
Transform.GetChild() — インデックスで子 Transform を取得します。
書式:GetChild メソッド
1
public Transform GetChild(int index);
| パラメータ | 説明 |
|---|---|
index |
取得する子のインデックス(0 から childCount - 1 まで) |
1
2
3
4
5
6
7
Debug.Log(transform.childCount); // 直下の子の数を出力
for (var i = 0; i < transform.childCount; i++)
{
var child = transform.GetChild(i);
Debug.Log(child.name);
}
Transform.Find() — 名前で直下の子(または子孫)を検索します。見つからない場合は null を返します。
書式:Find メソッド
1
public Transform Find(string name);
| パラメータ | 説明 |
|---|---|
name |
検索する名前。/ 区切りで子孫パスを指定できる(例: "Group/Item") |
1
2
3
4
5
var target = transform.Find("Item(Clone)");
if (target != null)
{
Destroy(target.gameObject);
}
⚠️
Find()は直下の子のみ検索します(孫は含まれません)。孫を検索するにはパス区切り/を使います。
Instantiate() に親 Transform を渡すと、生成と同時に子として配置できます。
書式:Instantiate メソッド(親指定)
1
public static Object Instantiate(Object original, Transform parent);
| パラメータ | 説明 |
|---|---|
original |
複製元のオブジェクト |
parent |
生成したオブジェクトの親になる Transform |
1
2
// このオブジェクト(Spawner)の子としてアイテムを生成する
var item = Instantiate(_original, transform);
子として生成することで、transform.childCount を「現在シーンに存在する数」として使えます。これを使うと、出現上限のチェックが簡潔に書けます。
1
2
3
4
5
6
7
8
private const int MaxItems = 5;
private void TrySpawn()
{
if (transform.childCount >= MaxItems) return; // 上限に達したらスキップ
Instantiate(_original, transform);
Debug.Log($"現在のアイテム数: {transform.childCount}");
}
アイテムが Destroy() で破棄されると、その分だけ childCount が減るため、「シーンに何個あるか」を別途カウントする必要がありません。
transform.position はワールド座標、transform.localPosition は親からの相対座標transform.SetParent() でスクリプトから親子関係を変更できるtransform.childCount と GetChild() で子オブジェクトを数えたり取得できるInstantiate(original, parent) で生成と同時に親子関係を設定できるposition が (5, 0, 0) のとき、子の localPosition が (1, 0, 0) だとワールド座標はどこになりますか?transform.childCount が減るのはどんな場合ですか?transform.Find("Enemy") が null を返す場合、どのような原因が考えられますか?(6, 0, 0)(親の位置 + 子のローカル位置)。Destroy() で破棄されたとき、または SetParent() で別の親に移動したとき。チュートリアル: スポナー では、Instantiate() と親子関係を組み合わせて、一定間隔でオブジェクトをスポーンするスポナーを実装します。