こんにちは、ともくんのゲーム作り部屋にようこそ!
このページでは、
「SetParentメソッドの使い方が知りたい!」
「Transform.parentと何が違うの?」
というお悩みの方に向けた内容となっています。
Unityでは、ゲームの実行中でもオブジェクトの親を指定して変更できるSetParentというメソッドがあります。
このSetParentメソッドは、Transformコンポーネントで定義されているもので、引数に親のTransformを指定することで、親子関係を変更することができます。
Transform.parentの変数でも親を指定することができますが、大きな違いとしてSetParentメソッドはオブジェクトのワールド空間の情報を保持するかどうかを指定することができます。
そこで、このページでは、Unityで親オブジェクトを指定することができるTransformのSetParentメソッドについて、仕組みや使い方、またTransform.parentで指定する場合との違いについてまとめていきます。
SetParentメソッドの使い方
それでは早速、SetParentメソッドの使い方について紹介していきます。
なお、Unityでの親子関係の仕組みについては、以下の記事でもまとめていますので、そちらも参考にしてみてください。
引数に親オブジェクトを指定して使う
SetParentメソッドで親オブジェクトを指定する場合は、子となるTransformコンポーネントを使って、以下のように記述して使います。
Transform.SetParent(parent, worldPositionStays);parent:親にするオブジェクト(Transform型)
worldPositionStays:ワールド空間における情報を保持するかどうか(bool型)
第一引数で、親にしたいオブジェクトをTransform型で指定してあげます。
第二引数は、オブジェクトのワールド空間における座標や回転、スケールを保持するかどうかをbool型で指定し、省略するとtrueになります。
この第二引数の部分は、後ほどの項目で詳しく説明していきます。
例えば、ゲーム内で以下のようにSquareとCircleのオブジェクトをそれぞれ配置していたとします。

そして、Circleのオブジェクトに以下のスクリプトを紐づけてあげます。
using UnityEngine;
public class CircleController : MonoBehaviour
{
public Transform square; // SquareのTransformを取得する変数を宣言
void Start()
{
transform.SetParent(square); // 親にSquareを指定する処理
}
}5行目でTransform型の変数をpublicで宣言していて、インスペクターウィンドウからSquareのオブジェクトを入れておきます。

そして、Startメソッド内の9行目で、SetParentメソッドを使って、Squareを親オブジェクトとする処理を記述しています。
これでゲームを実行してみると、

ゲーム画面の表示は変わっていませんが、ヒエラルキーウィンドウではSquareが親オブジェクトとなり、その中にCircleが入っているのが分かります。
このように、SetParentメソッドを使うことで、ゲーム実行中でも親子関係を変更させることができます。
Transform.parentとの違い
親を指定するのにSetParentメソッドを使いましたが、実は同じことをTransform.parentという変数を使って作ることができます。
using UnityEngine;
public class CircleController : MonoBehaviour
{
public Transform square; // SquareのTransformを取得する変数を宣言
void Start()
{
transform.parent = square; // 親をSquareにする処理
}
}9行目でTransform.parentの右辺に、SquareのTransformを代入しています。

すると先ほどと同じく、Squareを親のオブジェクトと指定することができます。
このTransform.parentとSetParentメソッドとの違いとして、SetParentメソッドでは前述の通り、第二引数でワールド空間における情報を保持するかどうかの設定を行うことができます。
言葉だけだと複雑なので、実際にUnity上で試してみましょう。
例えば、赤と黄の2つのSquareを配置して、最初は赤色のSquareを親としてCircleのオブジェクトを以下のように配置しておきます。

そして、Circleオブジェクトに以下のスクリプトをアタッチしておきます。
using UnityEngine;
public class CircleController : MonoBehaviour
{
public Transform yellowSquare; // 黄色のSquareのTransformを取得する変数
void Start()
{
transform.SetParent(yellowSquare, true); // ワールド座標を保持する設定
}
}9行目で、SetParentメソッドを使って、黄色のSquareを親として指定し、第二引数をtrueにしておきます。
これでゲームを実行してみると、

黄色のSquareが親オブジェクトになっているのが分かります。
注目すべき点として、親となるオブジェクトが変わっても、Circleのオブジェクトのワールド空間における座標位置は変わっていないのが分かると思います。
なお、Transform.parentで親を指定した場合も、このSetParentの第二引数をtrueにした時と同じ状況になります。
次に、先ほどのスクリプトのSetParentメソッドの第二引数をfalseに変更してみます。
using UnityEngine;
public class CircleController : MonoBehaviour
{
public Transform yellowSquare; // 黄色のSquareのTransformを取得する変数
void Start()
{
transform.SetParent(yellowSquare, false); // ワールド座標を保持しない設定
}
}これでもう一度実行すると、

親のオブジェクトが変わるだけでなく、Circleのオブジェクトの座標位置も変わっているのが分かります。
これは、SetParentの第二引数がfalseになったことで、Circleのオブジェクトのワールド座標が保持されなくなり、ローカル空間における座標(親からの相対的な座標)が使われているからです。
そして、親オブジェクトの座標位置も変わったことで、Circleオブジェクトのワールド空間における位置も変更されています。
このように、Transform.parentで指定する場合はワールド空間における情報が保持されることになりますが、SetParentメソッドを使った場合は、第二引数をfalseにすることで、ワールド空間における情報を破棄することができます。
UI要素を新たに生成する場合に便利
SetParentメソッドは、先ほどのようにワールド空間における座標や向き、スケールを保持させないようにできるので、例えばボタンなどUI要素をゲームの途中で新たに生成させるような場合に便利です。
なぜなら、UI要素は親にCanvasコンポーネントを必ず持つ必要があり、かつUI空間のローカル座標における相対的な位置やスケール、向きなどを制御することになるからです。
例えば、以下のようにキャラクターの下部に、HPを表すゲージをUIのImageを使って配置しておきます。

そして、このキャラクターを複製した際、HPゲージも新たに生成して表示させるという処理を作ってみます。
まず、キャラクターのオブジェクトを移動させる処理として、以下のスクリプトをアタッチしておきます。
using UnityEngine;
public class WolfController : MonoBehaviour
{
void Update()
{
transform.Translate(0.01f, 0, 0); // オブジェクトを右に移動させる処理
}
}次に、UIのImageで配置したHPゲージに、以下のスクリプトをアタッチしておきます。
using UnityEngine;
public class GaugeController : MonoBehaviour
{
Transform wolf; // オブジェクトを取得する変数
Vector3 offset = new Vector3(0, -2.0f, 0);
void Update()
{
if (transform.position != wolf.position + offset)
{
transform.position = wolf.position + offset; // オブジェクトに合わせて移動させる処理
}
}
// 複製したオブジェクトを取得するメソッド
public void GetWolf(GameObject obj)
{
wolf = obj.transform;
}
}17行目で、複製されたキャラクターのオブジェクトを受け取るメソッドを定義していて、ここで渡されたオブジェクトの動きに合わせて、12行目で移動する処理を記述しています。
また、キャラクターのオブジェクトとHPゲージのオブジェクトは、どちらもPrefab化しておきます。
あとは、オブジェクトとHPゲージを複製する処理を作りたいので、空オブジェクトを作成して、以下のスクリプトをアタッチしておきます。
using UnityEngine;
public class WolfGenerator : MonoBehaviour
{
public Transform canvas; // UI要素の親となるCanvasのTransform
public GameObject wolf; // 複製するキャラクターのオブジェクト
public GameObject hpGauge; // 複製するHPゲージのUIオブジェクト
float delta;
void Update()
{
delta += Time.deltaTime;
// 2秒経過した場合
if (delta > 2.0f)
{
GameObject cloneWolf = Instantiate(wolf); // キャラクターのオブジェクトを生成する
GameObject cloneHpGauge = Instantiate(hpGauge); // HPゲージのUIオブジェクトを生成する
cloneHpGauge.transform.SetParent(canvas, false); // 生成したHPゲージをCanvasの子要素として配置する
cloneHpGauge.GetComponent<GaugeController>().GetWolf(cloneWolf); // 複製したオブジェクトを渡す処理
delta = 0;
}
}
}まず、17行目でInstantiateメソッドを使って、Prefab化したオブジェクトを複製する処理を行っています。
そして、18行目で同じくInstantiateメソッドで、HPゲージを複製する処理を行います。
ただ、このHPゲージのオブジェクトはUI要素となるため、19行目でSetParentメソッドを使ってCanvasオブジェクトの配下になるように指定しています。
この時、SetParentメソッドの第二引数は、必ず「false」を指定しておきます。
あとは、20行目でHPゲージのクラスで定義したメソッドを使って、複製したオブジェクトを渡す処理を行っています。
これでゲームを実行してみると、

2秒毎にキャラクターが複製されるのに合わせて、HPゲージも複製されて一緒に移動できているのが分かります。
ちなみに、19行目のSetParentの第二引数を「true」にしてしまうと、以下のようにUI表示が大きく崩れてしまうため、注意しておきましょう。

まとめ
このページでは、Unityで親オブジェクトを指定できるSetParentメソッドについて、使い方や仕組み、またTransform.parentで指定する場合の違いをまとめていきましたが、いかがでしたでしょうか?
SetParentメソッドは、Transformコンポーネントで定義されていて、スクリプトから親を指定することができるメソッドです。
SetParentメソッドを使う際は、第一引数に親のTransformを指定して、第二引数にワールド空間の情報を保持するかどうかをbool型で指定してあげます。
特に、UI要素などはUI空間のローカル座標で位置を指定することになるので、SetParentメソッドが使われることが多いです。
最後までお読みいただきまして、ありがとうございました!






コメント