[Unity]オブジェクトを指に追従させる実装


はじめに

オブジェクトが指についてくる実装について3Dと2Dでまとめました。

目次

  1. 完成したコード
  2. Wold座標とScreen座標
  3. 線形補間
  4. 参考文献

完成したコード

とりあえず完成したコードを載せておきます。上が3Dで下が2Dとなっていて動かしたいオブジェクトにアタッチすればOKです。

finger.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class finger3D: MonoBehaviour
{
    Vector3 startPos;
    Vector3 screenPos;
    Vector3 worldPos;

    void Update()
    {
            if (Input.GetMouseButton(0))
           {
               startPos = transform.position;
               screenPos = Input.mousePosition;
               screenPos.z = 10;
               worldPos = Camera.main.ScreenToWorldPoint(screenPos);

               transform.position = Vector3.Lerp(startPos, worldPos,1);
           }

    }
}
finger2D.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class finger2D: MonoBehaviour
{
    Vector2  startPos;
    Vector2 screenPos;
    Vector2 worldPos;

    void Update()
    {
        if (Input.GetMouseButton(0))
        {
            startPos = transform.position;
            screenPos = Input.mousePosition;
            worldPos = Camera.main.ScreenToWorldPoint(tapPos);

            transform.position = Vector3.Lerp(startPos, worldPos,1);
        }
    }
}

とても簡単に書けます。軽く何をしているのかを説明すると

①現在のオブジェクトのWorld座標を取得
②クリックした場所のScreen座標を取得
③Screen座標をWorld座標に変換
④線形補間を用いてオブジェクトのWorld座標にスワイプした分の座標を代入

という感じです。

Wold座標とScreen座標

そもそもUnityにはSceneビューとGameビューがあってそれら二つの座標は違うものとして扱われるわけです。
なのでGameビューでのアクションをトリガーとして、オブジェクトに操作を加えるためにはScreen座標をWorld座標に変換させなければいけません。

それを行なっているのがCamera.main.ScreenToWorldPoint(screenPos);です。引数にはWorld座標に変換したいScreen座標を取ります。(Gameビューはカメラに写っているものなのでCameraのメソッドになるんだと思います。)

またスクリーン座標は型はVector3ですが実際にスマホやPCの画面がそうである通り2次元です。しかし型がVector3なのでz座標は存在していてそれをWold座標に変換する前に指定してあげないといけません。
それをしているのがscreenPos.z = 10;です。
なぜ10にしているのかというと、僕のUnityでこれを実装した時にmain cameraのz座標が-10、動かしたいオブジェクトのz座標は0になっていて距離が10離れていたからです。つまり取得したScreen座標はあくまでスクリーン上(カメラ)の位置でそれをそのままオブジェクトに反映させると少しずれてしまうんですね。なのでScreeのz座標はオブジェクトとカメラの距離にしてあげることを覚えておくといいかなと思います。

しかし2Dの場合はz軸が存在しないので何も気にしないで大丈夫です。「完成したコード」の3Dと2Dを見比べれば2Dの方はz軸に関しての記述がないことを確認できます。

線形補間

線形補間とは、任意の2点が存在する時それらの間に直線があることを仮定してその長さの数値を近似的に求めることと説明できます。
Vector3.Lerp(startPos, worldPos, 1);
で線形補間をしていて、それをオブジェクトの座標に代入しています。

この関数は一般にVector3.Lerp(最初の座標、終わりの座標、現在の位置);という使い方をします。
三つ目の引数である現在の「位置」をあえて座標と表記していない理由ですが、ここは第一引数と第二引数の距離を1という単位としてそれらの割合を0〜1の間で表すものだからです。なのでこの実装の場合第三引数を1とすればマウスにピッタリくっついてきてくれます。

参考文献