チュートリアル – GameObjectを複製操作する

Tutorial

C#Scriptから以下のようにGameObjectを操作するチュートリアルです。

  • 自分がアタッチされている以外のGameObjectを取得する。
  • 取得したGameObjectのインスタンスを複製する。
  • GameObjectを移動する。
  • GameObjectを回転する。

プロジェクトを作成する

Unity Hubで新規プロジェクトを作成します。

どのバージョンでも構いませんが、ここではUnity 2020.2.5f1でプロジェクトを作成しています。プロジェクト名、保存先はお好きなように入力してください。

レイアウトを変更する

デフォルトのLayoutのままでも大丈夫ですが、ここではSceneとGame windowが見たいのでToolbarの一番右でLayoutをDefaultから[nmxi style]に変更しています。

GameObjectを生成する

Hierarchy windowのコンテキストメニューで[3D Object]-[Sphere]を選択しSphereを生成します。これでシーン上にnameが”Sphere”というGameObjectクラスのインスタンスが生成されます。このSphereをC#Scriptで複製します。

Hierarchy windowのコンテキストメニューで[3D Object]-[Create Empty]を選択し空のGameObjectを生成します。GameObjectクラスのインスタンスは生成されますが、Scene windowでは見えないGameObjectです。C#Scriptをアタッチする用のGameObjectとします。

C#ScriptではSphereを見つけ出し、複製し、複製したものを移動、回転させます。

C#Scriptを生成する

Assetsフォルダの下であればどこでもいいですし、C#Scriptの名前も何でもいいですが、ここでは、Project windowのコンテキストメニューでAssetsフォルダの下にScriptsフォルダを生成しその下にControllという名前のC#Scriptを生成します。

Project windowのAssetsフォルダを選択します。

コンテキストメニューの[Create]-[Folder]でScriptsフォルダを生成します。

Scriptsフォルダを開きます。

コンテキストメニューで[Create]-[C#Script]を生成し名前を”Controll”とします。ファイル名決定後はコンテキストメニューの[Rename]でファイル名を変更できます。

ControllをダブルクリックするとVisual Studioが開きます。他のツールを使っている場合はそれで編集しても大丈夫です。

C#Scriptを編集する

Controll.csを編集します。名前はControll.csでなくても構いませんが、ファイル名とクラス名は同じになるようにしてください。そうしないとGameObjectにアタッチできません。

デフォルトのコードを読む

C#Scriptを生成した直後は次のようなコードになっています。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Controll : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

コードを簡単に説明します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

usingで使用するnamespace(名前空間)を指定します。指定したnamespaceにあるクラスはクラス名だけで使用できるようになります。

GameObjectクラスをコードで使用するときにusing宣言がないと、UnityEngine.GameObjectとnamespaceから指定する必要がありますが、using UnityEngine;を宣言すると、GameObjectだけで使用できます。

public class Controll : MonoBehaviour
{

...(略)...
}

MonoBehaviourクラスから派生したpublicなControllクラスの宣言です。宣言内でメソッドやフィールドを定義できます。

    // Start is called before the first frame update
    void Start()
    {
        
    }

Start()メソッドは初期化を行うメソッドです。

    // Update is called once per frame
    void Update()
    {
        
    }

Update()メソッドはフレーム毎に呼ばれるメソッドです。

コードを編集する

次のように編集します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Controll : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        GameObject target = GameObject.Find("Sphere");
        if (target != null)
        {
            for (int x = -1; x <= 1; ++x)
            {
                for (int y = -1; y <= 1; ++y)
                {
                    for (int z = -1; z <= 1; ++z)
                    {
                        // 複製する
                        GameObject clone = Instantiate(target, this.transform);
                        // 移動する
                        clone.transform.position = new Vector3(x * 1.1f, y * 1.1f, z * 1.1f);
                    }
                }
            }
            // 元のGameObjectは破棄する
            Destroy(target);
        }
    }

    // Update is called once per frame
    void Update()
    {
        transform.Rotate(new Vector3(0.1f, 0.2f, 0.3f));
    }
}

コードを説明します。

GameObject target = GameObject.Find("Sphere");

GameObjectクラスのFindという静的メソッドで”Sphere”という名前のGameObjectを検索します。見つかったGameObjectのインスタンスをtargetという名前のローカル変数に設定します。”Sphere”という名前はHierarchyにある名前と一致する必要があります。Hierarchyで名前を変更した場合はその名前にしてください。

GameObject clone = Instantiate(target, this.transform);

Monobehaviourの基底クラスはBehaviourクラス、その基底クラスがComponentクラス、そのまた基底クラスがObjectクラスです。基底クラスのpublic及びprotectedメソッドはメソッド名だけで呼び出すことができます。InstantiateはObjectのメソッドです。Visual Studio上で”Instantiate”の上にマウスを持っていくとどのクラスのメソッドがわかります。第一引数でコピー元のインスタンスを指定します。第二引数で親のTransformを指定します。ここでは自分のtransformを指定しています。

コードだけみると、Controller C#Scriptインスタンス自身のtransformを操作しているように見えますが、基底クラスのComponentクラスのメソッドやプロパティではgameObjectへ移譲することで、MonoBehaviourから派生したクラスが、あたかもGameObject自身であるかのように振舞えるようにしています。便利になっていますが、ここを理解しないと混乱する元になります。

public class Component : Object
{
...
	public Component GetComponent(Type type)
	{
		return this.gameObject.GetComponent(type);
	}
...
	public string tag
	{
		get
		{
			return this.gameObject.tag;
		}
		set
		{
			this.gameObject.tag = value;
		}
	}
clone.transform.position = new Vector3(x * 1.1f, y * 1.1f, z * 1.1f);

複製したGameObjectのインスタンスの座標を変更します。

for (int x = -1; x <= 1; ++x)
{
    for (int y = -1; y <= 1; ++y)
    {
        for (int z = -1; z <= 1; ++z)
        {
            // 複製する
            GameObject clone = Instantiate(target, this.transform);
            // 移動する
            clone.transform.position = new Vector3(x * 1.1f, y * 1.1f, z * 1.1f);
        }
    }
}

xを-1、0、1、yやzも-1、0、1に変更し3x3x3の27個のGameObjectの複製を作り、座標をx,y,zに移動します。間にちょっと空間を作るために1.1倍しています。

Destroy(target);

複製して不要になったので元の”Sphere”GameObjectインスタンスを破壊します。

void Update()
{
    transform.Rotate(new Vector3(0.1f, 0.2f, 0.3f));
}

フレーム毎にちょっとずつ回転させます。親を回転させることで子も一緒に回転します。

編集後にCtrol-Sや保存アイコン等で保存します。

C#Scriptをアタッチする

Unity Editorに戻りControll C#ProjectをHierarchy上のGameObjectにアタッチします。アタッチすることでControll C#ScriptはGameObjectのコンポーネントとして登録されます。アタッチする方法はいくつかあります。

  • Project上のC#ScriptのControllをHierarchy上のGameObjectにドラッグ&ドロップする。
  • Hierarchy上のGameObjectを選択し、Inspector上にControll C#Scriptをドラッグ&ドロップする。
  • Hierarchy上のGameObjectを選択し、Inspectorの[Add Component]でControll C#Scriptを選択する。

Playする

上記はツールバーの中央にあるボタンです。左からPlay、Pause、Stepです。Play(再生)中にPlayボタンを押すとPlayを終了します。

Cubeに変えてみる

Cubeでもやってみましょう。

Hierarchyの[+]あるいはコンテキストメニューで[3D Object]-[Cube]を選択しCube GameObjectを生成します。

HierarchyでSphereを選択し、Inspector windowでSphereの左側のチェックボックスを外して非アクティブにします。

Controll C#Scriptの”Sphere”を”Cube”に変えて保存します。

Playボタンを押します。

コメント