Unity C#でオブジェクトをドラッグで動かすスクリプトの書き方

IT

色んなゲームで利用可能な、ドラッグでオブジェクトを動かす方法です。
キャンバスが存在し、レンダーモードがスクリーンスペース-カメラであることを前提にしています。

スポンサーリンク

成果物

unity ドラッグ5
ドラッグするとオブジェクトが動きます。
以下のコードをスクリプトに追加し、コライダーをセットしたオブジェクトにアタッチすれば動きます。
//Unity C#
    void OnMouseDrag()
    {
        //マウスの座標を取得してスクリーン座標を更新
        Vector3 thisPosition = Input.mousePosition;
        //スクリーン座標→ワールド座標
        Vector3 worldPosition = Camera.main.ScreenToWorldPoint(thisPosition);
        worldPosition.z = 0f;

        this.transform.position = worldPosition;
    }

以下作成記録です。

座標の取得

unity ドラッグ 移動1
考え方としては、
①ドラッグしている間に
Input.mousePositionでマウスの座標を求めて
③オブジェクト自身の座標にマウスの座標を代入すればいいんですが、
//Unity C#
    void OnMouseDrag()
    {
        Vector3 thisPosition = Input.mousePosition;
        this.transform.position = thisPosition;
    }

unity ドラッグ3
これだけ実装すると、触った瞬間に消滅する(正確にははるか彼方に吹き飛ばされる)オブジェクトになります。

座標の変換

これはInput.mousePositionで取得できる座標はスクリーン座標で、オブジェクトの位置を記述するワールド座標とは単位の基準がちがうからです。
この記事ではドラッグでカメラの移動をするために、スクリーン→ワールド→ローカルと座標を変換しています。

これの座標変換部分だけもらってくると、下記のようなコードになります。

//Unity C#
    void OnMouseDrag()
    {
        //マウスの座標を取得してスクリーン座標を更新
        Vector3 thisPosition = Input.mousePosition;
        //スクリーン座標→ワールド座標
        Vector3 worldPosition = Camera.main.ScreenToWorldPoint(thisPosition);
        //ワールド座標→ローカル座標
        Vector3 localPosition = this.transform.InverseTransformPoint(worldPosition);

        this.transform.position = localPosition;
    }
unity ドラッグ4
これで実行するとある程度は意図通りに動きますが、オブジェクトがマウスに遅れる、画面のはじっこまで来ないといういう現象が発生します。

検証

各座標を取得するとこうなります。

//Unity C#
        Debug.Log("スクリーン座標" + thisPosition);
        Debug.Log("ワールド座標" + worldPosition);
        Debug.Log("ローカル座標" + localPosition);
        Debug.Log("オブジェクトの座標" + this.transform.position);
unity ドラッグ 移動2
オブジェクトはワールド座標で位置を決定しているので、ローカル座標で位置を指定するとズレが生じます。
しかしワールド座標をオブジェクトに代入しても、なぜかズレてしまいます。
座標を確認すると、ワールド座標のz軸が-10になっていることがわかります。
unity ドラッグ 移動3
実際にオブジェクトのz軸をインスペクターで変更してみると、
unity ドラッグ 移動4
オブジェクトが消える(位置が変わる)ことが確認できます。
ワールド座標のz軸を変更して、これをオブジェクトの位置に代入してやると冒頭のコードになります。
//Unity C#
        //マウスの座標を取得してスクリーン座標を更新
        Vector3 thisPosition = Input.mousePosition;
        //スクリーン座標→ワールド座標
        Vector3 worldPosition = Camera.main.ScreenToWorldPoint(thisPosition);
        worldPosition.z = 0f;
やりたいことから逆引きするUNITYの使い方まとめ
Unityをやりたいことから学習していけるよう、機能・用途別にまとめたページです。C#の命令別の逆引きは現時点で作っていません。2019の時期に書き始めているので、それより前のバージョンについては言及しません。

コメント