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

2022年8月22日

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

基本のサンプル

2つのオブジェクト間アクセスのサンプルで見ていきます

シーンの構成

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

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

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

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

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

解説用シーン

Cubeにアタッチするスクリプト

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