コンポーネントでゲームオブジェクトを操る

Unityでは、ゲームオブジェクトがゲームの主人公になります。コンポーネントは、そのゲームオブジェクトの「機能」としてゲームオブジェクトにアタッチ(リスト化)されています。
Unityにおけるプログラミングとは、その機能を変化させることでゲームオブジェクトに作用させて進める作業を指します。

基本のサンプル

具体的にどのような流れで実現するのかみていきましょう

シーンの構成

ゲームオブジェクトを2つ配置します

Cube x 1
  Position (-2, 0, 0)
  Rigidbody (Use Gravity = false)
  UseGravityTestスクリプト

Sphere x 1
  Position (2, 0, 0)
  Rigidbody (Use Gravity = false)

落下するゲームオブジェクトにスクリプトがアタッチされている場合

サンプルでは、CubeにスクリプトとRigidbodyコンポーネントがアタッチされています。
作業としては、このRigidbodyのUseGravityのプロパティをオンにします

解説用シーン

using UnityEngine;

public class UseGravityTest : MonoBehaviour
{
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            GetComponent<Rigidbody>().useGravity = true;
        }
    }
}

スクリプトがアタッチされてない別のゲームオブジェクトを落下させるには

サンプルでは、Cubeにスクリプトがアタッチされていますがこれを落下させるわけではありません
別のゲームオブジェクト(Sphere)にアタッチされているRigidbodyコンポーネントに作用させます
作業としては、このRigidbodyのUseGravityのプロパティをオンにします

解説用シーン

using UnityEngine;

public class UseGravityTest : MonoBehaviour
{
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            GameObject.Find("Sphere").GetComponent<Rigidbody>().useGravity = true;
        }
    }
}

別の記述1

アクセスする頻度が高い場合、CPUの負荷を下げるために事前に変数にFindメソッドの結果を代入しておきます
このようにできるのは、Findメソッドの結果が変化しないからです

using UnityEngine;

public class UseGravityTest : MonoBehaviour
{
    GameObject sphere;

    void Start()
    {
        sphere = GameObject.Find("Sphere");
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            sphere.GetComponent<Rigidbody>().useGravity = true;
        }
    }
}

別の記述2

いっそのこと、コンポーネントレベルでキャッシュ(一旦保存)しておきます
ゲームオブジェクトの時(別の記述1)と同じく、メソッドの結果が変化しないことを利用しています

using UnityEngine;

public class UseGravityTest : MonoBehaviour
{
    Rigidbody sphereRigidbody;

    void Start()
    {
        sphereRigidbody = GameObject.Find("Sphere").GetComponent<Rigidbody>();
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            sphereRigidbody.useGravity = true;
        }
    }
}

別の記述3

さらに、メソッドで取得するのではなく、インスペクター上で得たいオブジェクトまたはコンポーネントをドラッグ&ドロップする方法があります。これも、変化することがないことが条件になります

2つのパターンをみていきましょう。ゲームオブジェクトを取得する方法とコンポーネントを取得する方法です

ゲームオブジェクトをインスペクターから取得する

取得したいゲームオブジェクトにアタッチされているコンポーネントにアクセスするのですが、さらにこのオブジェクトの他のコンポーネントにもアクセスしたい場合はこの方がいいです

ゲームオブジェクトをアウトレット接続(ドラッグ&ドロップ)することで、sphereフィールドにゲームオブジェクトが代入されます
using UnityEngine;

public class UseGravityTest : MonoBehaviour
{
    public GameObject sphere;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            sphere.GetComponent<Rigidbody>().useGravity = true;
        }
    }
}

Rigidbodyをインスペクターから取得する

取得したいゲームオブジェクトの特定のコンポーネントにしかアクセスしない場合は、このように特定してもいいでしょう

ゲームオブジェクトをアウトレット接続(ドラッグ&ドロップ)することで、sphereRigidbodyフィールドにRigidbodyコンポーネントが代入されます
using UnityEngine;

public class UseGravityTest : MonoBehaviour
{
    public Rigidbody sphereRigidbody;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            sphereRigidbody.useGravity = true;
        }
    }
}

おまけ(CubeをクリックするとSphereが落下する)

Cubeをクリックして、Sphereゲームオブジェクトを落下させるコードになります

using UnityEngine;

public class UseGravityTest : MonoBehaviour
{
    public Rigidbody sphereRigidbody;

    void OnMouseDown()
    {
        sphereRigidbody.useGravity = true;
    }
}

おまけ(Cubeをクリックしている間、Cubeの位置が連続して取得できる)

Input.MousePositionでは、スクリーンポジションが取得できます。(カメラから見た2次元の座標で、左上が(0,0)になります。縦横はディスプレイのピクセル値になります。いわゆる画面をスクリーンとして見立てた場合の座標)
この座標をもとに、CubeにRay(光線の喩え)を照射して、コライダーの衝突場所を取得するようなことをやっています

using UnityEngine;

public class UseGravityTest : MonoBehaviour
{
    public Rigidbody sphereRigidbody;

    void OnMouseDrag()
    {
        var ray = Camera.main.ScreenPointToRay(Input.mousePosition);

        if (Physics.Raycast(ray, out RaycastHit hit))
        {
            Debug.Log(hit.point);
        }
    }
}

Unity

Posted by hidepon