この記事では Unity の C# スクリプトを使い、スクリーン座標からワールド座標を求める方法について説明します。
使用した Unity のバージョンは 2020.1.1f1(64-bit)
プラットフォームは Windows 10(64ビット) です。
以前、別のブログに掲載していた記事を手直ししたものです。
当時は Unity 4 でしたが、この部分は全く変わっていません。
たぶん、バージョンに関係なく使えます。
ScreenToWorldPoint() を使います。
// マウスのポインタがあるスクリーン座標を取得 Vector3 screen_point = Input.mousePosition; // z に 1 を入れないと正しく変換できない screen_point.z = 1.0f; // スクリーン座標をワールド座標に変換 Vector3 world_position = Camera.main.ScreenToWorldPoint(screen_point);
スクリーン座標は2次元なので、3次元の Vector3 に突っ込んだ時、z は初期値の 0 になります。
0 で困るときは、0 以外の値を入れる必要があります。
スクリーン座標をワールド座標に変換する際、スクリーン座標の z に 1 を入れないと、正しく変換できません。
うっかり、z を初期値(0)のまま ScreenToWorldPoint() に渡してしまうと、おかしなワールド座標に変換されてしまいます。
Input.mousePosition は、古い Input システムでのマウスカーソル位置を取得する方法ですが、(2020/10/31現在)まだ使えます。
新しい Input システムでは、Mouse.current.position.ReadValue() を使います。
新しい Input システムを使うには、パッケージマネージャーを使ってインストールした上で、あれこれセットアップが必要です。
インストールとセットアップ方法については、下記ブログ記事参照。
Camera.main.ScreenToWorldPoint() を初めて使ったとき、うまく変換できず、その理由に気づくまで何時間も格闘しました。
私と同じ失敗で貴重な時間を浪費する方が少しでも減りますよう、祈りを込めて、ここに記録しておきます。
応用すると、こんなことができます。
クリックした位置にキューブを移動させる…ということをやっていますが、クリックした位置(スクリーン座標)をキューブを移動させる位置(ワールド座標)に変換する必要があり、そこで使っています。
ソースコード
using UnityEngine; public class CubeScript : MonoBehaviour { public float length_per_second = 2.0f; //移動スピード Vector3 destination; //目的地の座標 Vector3 start_point; //移動開始時の座標 float start_time; //移動開始時の時間 float journey_length; //移動距離 bool is_moving = false; void Update() { if (Input.GetMouseButtonDown(0)) { this.start_point = this.transform.position; Vector3 screen_point = Input.mousePosition; screen_point.z = 1.0f; this.destination = Camera.main.ScreenToWorldPoint(screen_point); this.start_time = Time.time; this.journey_length = Vector3.Distance(this.start_point, this.destination); this.is_moving = true; } if (this.is_moving) { float length_by_elapsed_time = (Time.time - this.start_time) * this.length_per_second; float fraction_length_by_elapsed_time = length_by_elapsed_time / this.journey_length; Vector3 lerp = Vector3.Lerp(this.start_point, this.destination, fraction_length_by_elapsed_time); this.transform.position = lerp; if (Vector3.Distance(this.transform.position, this.destination) < 0.1f) { // 目的地までの距離が 0.1 未満になったら移動完了 this.is_moving = false; } } } }
同じところで躓きました。ですがこの記事のおかげで早く解決できました。ありがたや。