この記事では、ゲームオブジェクトを子要素にしても位置や回転、スケールが変わらないようにする方法を解説します。
この前、Instantiate()
で生成したゲームオブジェクトをあるゲームオブジェクトの子要素にしたら位置や回転、スケールが勝手に変更され、想定通りの配置にならなかった。
その時のコードは以下のような感じです。
[SerializeField]
private GameObject prefab;
private void Awake()
{
Transform child = Instantiate(prefab).transform;
// 親を変更
child.parent = gameObject.transform;
}
それでは、なぜ想定通りの配置にならなかったのか原因と解決策を見ていきましょう!
先程のコードでは、子要素のparent
に直で親を代入していました。
child.parent = gameObject.transform;
parentに直接親を代入するとワールド空間を保ったまま子要素にしてしまいます。
つまりは、子要素にするゲームオブジェクトに設定されている位置や回転、スケールになるように親のトランスフォームから相対的に計算された値が渡されるようになっています。
そのような理由から想定外の配置になってしまうことがあります。
ワールド空間ではなくローカル空間を基準に子要素にすることでトランスフォームを変更することなく親を設定することができます。
ローカル空間を基準に子要素にするには、Transform.SetParent()
を使います。
public void SetParent (Transform p);
public void SetParent (Transform parent, bool worldPositionStays);
このメソッドは、第一引数で指定したトランスフォームを親として設定できます。また、第二引数にtrue
を指定することでワールド空間を保ったまま子要素にすることができます。
ローカル空間を基準に子要素にしたい場合は、第二引数に false を指定します。ちなみに、第二引数が省略された場合は、ワールド空間を保ちます。
ということで最初のコードは、以下のように書き直すことで位置やスケールを変更されずに子要素にすることができます。
[SerializeField]
private GameObject prefab;
private void Awake()
{
Transform child = Instantiate(prefab).transform;
// 親を変更
child.SetParent(gameObject.transform, false);
}
簡単ですね!