ロバメモ - 素人のUnity覚書と奮闘記

素人のUnity覚書と奮闘記

移動距離が変わっても、指定した速度で等速直線移動させたい

やりたいこと

・移動距離が変わっても、指定した速度で直線移動し、到達したら止まる。

魔法師の魔法攻撃処理で悩んだのでメモ。
全体の移動距離から1フレームの移動距離(つまり速度)を割り出す方法だと、等速で移動するけど移動距離によって速度が違ってきちゃう。
そうじゃなくて、移動距離が変わっても速度は指定したままで進んで欲しい。

使うメソッド

docs.unity3d.com

public static Vector3 MoveTowards (Vector3 current, Vector3 target, float maxDistanceDelta);

current = 始点
target = 終点
maxDistanceDelta = 1フレームで進む距離

f:id:nico-taniku:20180214112550p:plain
currentからtargetに向かって、maxDistanceDeltaずつ進む。
targetmaxDistanceDeltaより近い場合は、targetの地点へ移動。つまり、targetを超えて進まない。
maxDistanceDeltaがマイナス値だと、targetと逆方向へ移動してしまうので注意。

コード

この場合のspeedは、全体の移動にかかる時間ではなく、1秒で進む距離のことになる。
数値が大きいほど早く移動する。

1秒間に何フレーム再生されるか(FPS)は不定なので、Time.deltaTimeで調整してくれている。
(ということだと思う。)

   //移動速度
    float speed = 2f;
    //標的
    GameObject target;

    public void OnStart (GameObject target)
    {
        this.target = target;
        StartCoroutine (Throw ());
    }

    IEnumerator Throw ()
    { 
        while (true) {   
            transform.position = Vector3.MoveTowards (transform.position, target.transform.position, speed * Time.deltaTime);
            yield return null;

        }
    }

任意のタイミングでOnStart()を実行する。

到達したら消滅したい場合

距離が0.1f未満になったら、小さくなって破棄する。

transform.position == target.transform.positionこの条件でも良さそうなんだけど、実行してみたらピッタリにならないようなので、少し余裕を持たせて0.1fにしてみた。
(おそらく、ピッタリにならないのはターゲットが移動しているせいだと思う。)

   IEnumerator Throw ()
    { 
        while (true) {   
            float distance = Vector3.Distance (transform.position, target.transform.position);
            if (distance < 0.1f) {
                StartCoroutine (Destroy ());
                yield break;
            }

            speed = speed * stageManager.GetPlaySpeed ();
            transform.position = Vector3.MoveTowards (transform.position, target.transform.position, speed * Time.deltaTime);
            yield return null;

        }
    }


    IEnumerator Destroy ()
    {
        while (true) {
            float speed = 6f * Time.deltaTime;
            gameObject.transform.localScale -= new Vector3 (speed, speed, speed);
            if (gameObject.transform.localScale.x <= 0f) {
                Destroy (gameObject);
                yield break;
            }
            yield return null;
        }

    }

以上。