【Unity】オブジェクトから見たマウスの方向を取得する(2D)

オブジェクトからマウスまでの方向ベクトルとそのなす角の図 Programming

やること

オブジェクトから見たマウスの方向を取得します。

具体的には以下の図のようにオブジェクトから見たマウスの方向ベクトルとオブジェクトから見たマウスの角度の2種類の値を取得します。

手順

1. オブジェクトとスクリプトの準備

今回のターゲットとなるオブジェクトと、コードを書いてオブジェクトにアタッチするスクリプトを用意します。マウスの方向を求めたいオブジェクトは状況により異なると思うので自由なオブジェクトでいいです。

ここから先のコードはすべて、ここで用意したスクリプトに書き込んでいきます。

2. メインカメラの取得

マウスの座標を取得する準備としてまず、シーンのメインカメラをスクリプトから取得します。

カメラ格納用の変数を用意し、Camera.mainを利用してシーンのメインカメラを取得します。

Camera.mainを使用するとタグが”MainCamera”になっているオブジェクトを取得してくれます。もし、別のカメラを使用する場合は適宜、別の方法で変数に目的のカメラを格納してください。

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

public class DirectionMouse : MonoBehaviour{
	private Camera cam;

	public void Start(){
		// メインカメラを取得
    cam = Camera.main;
  }
}

3. マウスの位置の取得

マウスの座標格納用に新たにVector2の変数を用意します。

Input.mousePositionで画面上のマウスの位置を取得し、関数ScreenToWorldPoint()でワールド座標に変換しています。

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

public class DirectionMouse : MonoBehaviour{
	private Camera cam;
	private Vector2 mousePos;

	public void Start(){
    cam = Camera.main;
  }
  
  public void Update(){
	  // マウスの位置を取得
	  mousePos = cam.ScreenToWorldPoint(Input.mousePosition);
  }
}

4. 方向ベクトルの取得

方向ベクトルは先ほど取得したマウスの位置と、オブジェクトの位置を利用して計算します。

計算方法はベクトルを図示するとわかりやすいです。ワールド座標を位置ベクトルと捉えると下の図のように図示することができ、方向ベクトルがベクトル同士の引き算で計算できそうとわかります。ベクトルの引き算は「先 – 根本」なので今回の場合はカーソルの位置ベクトル オブジェクトの位置ベクトルで求まります。

よってコードは以下のようになります。

オブジェクトの座標はtransform.positionをVector2に変換して取得しています。transform.positionはVector3でVector2と直接計算できないため、変換しています。

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

public class DirectionMouse : MonoBehaviour{
	private Camera cam;
	private Vector2 mousePos;

	public void Start(){
    cam = Camera.main;
  }
  
  public void Update(){
	  mousePos = cam.ScreenToWorldPoint(Input.mousePosition);
		// マウスの方向ベクトルを取得
		Vector2 direction = mousePos - (Vector2)gameObject.transform.position;
  }
}

また、目的のゲームオブジェクトにRigidBody2Dが適用されている場合はRigidBody2Dの座標を取得する方法でもオブジェクトの座標を取得できます。

その場合は以下のコードのように新たにRigidBody2D格納用の変数を用意し、関数Start()内でゲームオブジェクトのRigidBody2Dを取得します。RigidBody2Dから座標を取得する場合はもともとVector2で取得できるので、変換は不要です。

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

public class DirectionMouse : MonoBehaviour{
	private Camera cam;
	private Vector2 mousePos;
	private Rigidbody2D rigidBody;

	public void Start(){
    cam = Camera.main;
    rigidBody = gameObject.GetComponent<Rigidbody2D>();
  }
  
  public void Update(){
	  mousePos = cam.ScreenToWorldPoint(Input.mousePosition);
		// マウスの方向ベクトルを取得
		Vector2 direction = mousePos - rigidBody.position;
  }
}

5. 角度の取得

最後に、角度を取得します。角度の取得にはアークタンジェントを利用します。

アークタンジェントは逆三角関数で普通のタンジェントが角度から傾きを求めるのに対して、アークタンジェントは傾きから角度を求めることができます。

UnityではMathf.Atan2(x,y)という関数を用いることで、X 軸と 0 から始まり (x,y) で終了する 2D ベクトルの間の角度を求めることができるのでこれを使います。

Mathf.Atan2(x,y)で取得される値はラジアンのため、度数法にする場合は得られた値にMathf.Rad2Degを掛けます。これは、” 360/(PI * 2) “を定数化した値で掛けるだけで度数法に変換できます。

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

public class DirectionMouse : MonoBehaviour{
	private Camera cam;
	private Vector2 mousePos;
	private Rigidbody2D rigidBody;

	public void Start(){
    cam = Camera.main;
    rigidBody = gameObject.GetComponent<Rigidbody2D>();
  }
  
  public void Update(){
	  mousePos = cam.ScreenToWorldPoint(Input.mousePosition);
		Vector2 direction = mousePos - rigidBody.position;
		// 角度を取得
		float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
  }
}

このコードでオブジェクトからマウスへの角度が-180~180度の範囲で得られます。

使用例

以前、Qiitaで紹介していた反射するレーザーの方向の変え方をキーボード操作からマウスでの操作に変える際に、オブジェクトからマウスまでの方向ベクトルを使用しました。

Qiitaの記事はこちら

【Unity】反射するレーザーを作ろう!#完成 - Qiita
はじめに前回からコードを大幅に変更したので、追加した機能と合わせて完成版として記事にさせていただきます。実装方法の解説なども改めてするので、この記事だけ読めば全部、実装できます。読まなくても問…

実際のコード(LazerStarter.csを書き換えた)

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

public class LazerStarter : MonoBehaviour
{
  [SerializeField] private GameObject lazerMother;
  [SerializeField] private Vector2 INITIAL_DIRECTION = new Vector2(0.3f,1); //最初の方向
  //[SerializeField] private  float ROTATE_SPEED = 0.04f;  //回転速度
  [SerializeField] private Material START_COLOR;  //最初のマテリアル
  // private Rigidbody2D rigidBody;
  private GameObject newLazer;
  private LazerMother lazerMotherCS;

  private Vector2 mousePos;
  private Camera cam;

  public void Start(){
    newLazer = Instantiate(lazerMother, this.gameObject.transform.position, Quaternion.identity);
    lazerMotherCS = newLazer.GetComponent<LazerMother>();
    // rigidBody = gameObject.GetComponent<Rigidbody2D>();
    cam = Camera.main;
    lazerMotherCS.create(newLazer.transform.position, INITIAL_DIRECTION, START_COLOR);
  }

  // public void Update(){
  //   // 左回転
  //   if (Input.GetKey (KeyCode.LeftArrow)) {
  //     lazerMotherCS.move(lazerMotherCS.getOrigin(), Quaternion.Euler(0f, 0f, ROTATE_SPEED) * lazerMotherCS.getDirection());
  //   }
  //   // 右回転
  //   if (Input.GetKey (KeyCode.RightArrow)) {
  //     lazerMotherCS.move(lazerMotherCS.getOrigin(), Quaternion.Euler(0f, 0f, -ROTATE_SPEED) * lazerMotherCS.getDirection());
  //   }
  // }

  public void Drag(){
    //マウスの位置を取得
    mousePos = cam.ScreenToWorldPoint(Input.mousePosition);

    //マウスの向きを取得
    Vector2 direction = mousePos - (Vector2)gameObject.transform.position;

    float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;

    Debug.Log(angle);

    lazerMotherCS.move(new Vector2(gameObject.transform.position.x, gameObject.transform.position.y) , direction);
  }
}

参考

【Unity2D】プレイヤーをマウスの方向に回転させたい。
プレイヤーをマウスの方向に回転させる方法です
【Unity】スクリプトからMain Cameraを取得するのは簡単だよ
Main Cameraの取得はFindGameObjectWithTagやGetComponentを使わなくてもできるという話 「Camera.main」と記述して、サクッと取得しましょう。
Mathf-Atan2 - Unity スクリプトリファレンス
Tan が y/x になる角度をラジアンで返します。
Mathf-Rad2Deg - Unity スクリプトリファレンス
ラジアンから度に変換する定数(読み取り専用)