読者です 読者をやめる 読者になる 読者になる

【Unity】美しくパトロールさせたい~ベジェ曲線を試してみる

Unity Programming

前回の記事の続き。
【Unity】パトロールスクリプトを作ってみる - 奇跡のヌードル帝国

何点かポイントを取って経路を巡回させるスクリプトは前回の奴で問題ない。
トロールする人間は普通まっすぐ歩くし、通路は大抵真っすぐだ。だから問題ない。
でもなんか、曲がってたっていいじゃないですか。

目的

巡回経路のプログラムにベジェ曲線の経路を辿らせてみる。

ベジェ曲線とは、"N 個の制御点から得られる N - 1 次曲線である。"とwikipediaには書いてあるが、要はいい感じの滑らかな曲線である。

このサイトに載ってる解説と応用例が何となくわかりやすい。
新・C言語 〜ゲームプログラミングの館〜 [DXライブラリ]

シューティングゲーム作ってた時に知ったけど、割と色々応用できるんだなって思う。
プログラムテクニック覚え書き

まぁ具体的にどんな感じに応用するかは知らない。

結果

四点を絶対に通り、点と点の間は制御点に引っ張られるようなベジェ曲線の軌道を描く。
www.youtube.com

www.youtube.com

Unityには軌跡を表示できるTrail Rendererというコンポーネントがあるのでそれを利用させてもらった。
どんな経路を通っているのか分かりやすいと思う。

尚、動画のキャプチャには以下のスクリプトを利用した。感謝。とても使いやすいです。
Screen recording utility. · GitHub

実装

ソースコード

利用したのは1個の制御点から得られる2次曲線。

using UnityEngine;
using System.Collections;

public class bezierPatrol : MonoBehaviour {
    const float margin = 1.0f;

    public Vector3[] checkpoints;
    public Vector3[] ctrlPoints;

    private float time;
    private int whereToGo;

    private Vector3 BezierCurve(Vector3 pt1, Vector3 pt2, Vector3 ctrlPt, float t) {
        if (t > 1.0f)
            t = 1.0f;

        Vector3 result = new Vector3();
        float cmp = 1.0f - t;
        result.x = cmp * cmp * pt1.x + 2 * cmp * t * ctrlPt.x + t * t * pt2.x;
        result.y = cmp * cmp * pt1.y + 2 * cmp * t * ctrlPt.y + t * t * pt2.y;
        result.z = cmp * cmp * pt1.z + 2 * cmp * t * ctrlPt.z + t * t * pt2.z;
        return result;
    }

    // Use this for initialization
    void Start () {
        time = 0.0f;
        whereToGo = 0;
	}
	
	// Update is called once per frame
	void Update () {
        if (checkpoints.Length == 0)
            return;

        if (time > 1.0f) 
            time = 0.0f;

        if (checkpoints.Length <= this.whereToGo)
            whereToGo = 0;

        this.transform.position = BezierCurve(checkpoints[whereToGo], checkpoints[(whereToGo + 1) % checkpoints.Length],ctrlPoints[whereToGo], time);

        if (Vector3.Distance(transform.position, checkpoints[(whereToGo + 1) % checkpoints.Length]) < margin)
        {
            Debug.Log(whereToGo);
            whereToGo++;
            time = 0.0f;
        }

        time += Time.deltaTime / 2.0f;
    }
}

checkpointsとctrlの要素数が同数である事が前提。その辺のチェックをしていないので注意。
チェックポイントnとn+1の間の制御点として、制御点nを用意している感じ。

簡単な割りにはいい感じの結果を出してくれてる。

考察

何となくお昼時に時間が余ったのでサクッと作ってみた。
ゲームの巡回兵士には使えない・・・と思うけど、多分背景の隅っこの方でいい感じに泳いでるような魚とか、鳥とかそういう感じの自由な奴らの動きの実装はこんな感じで良いかもしれない。
後は開始点と終点は必ず通るという性質があるのでホーミング弾の経路計算に利用したり、まぁ何だかんだ利用の幅はあるのだと思う。
ぶっちゃけこのスクリプトだと制御点を最初から指定しなきゃならないあたり結構面倒だから、Vector3型の適当な制御点を生成できるような感じの何かを適宜実装しよう。

むしろUnityで動画出力する方法を出せたのが一番の収穫だったり。