はじめに
この記事は 法政大学情報科学部 Advent Calendar 2022 の 24 日目です。
こんにちは。HirokiLucky です。
今回は連続する関数 Noise について話して行きます。
作りたいもの
今回は、上から降ってくるボールをキャッチするよくあるゲームを作りたいと思います。
しかし、ボールを生成する際に Random クラスの Random.Next() や Random.Range() を使用すると、場合によっては両端に生成されてしまい連続で取ることが不可能になってしまうという問題があると思います。(下画像)
ここで、Unity.Mathematics.noise の関数を使うことで osu!catch のような滑らかなにボールを生成することができます。(上画像)
Noise 関数
Unity.Mathematics.noise には cnoise(), pnoise() など様々な関数がありますが、今回はその中でも比較的高性能(?)なシンプレックスノイズと言われる snoise 関数を扱います。
書き方
float noise = Unity.Mathematics.noise.snoise(new float2(rand, time));
マニュアル にも記載がある通り、snoise 関数は float2(), float3(), float4() を引数で取ることができます。float2() では、float2 内の第一引数では、シード値、第二引数には時間を入れます。
また、返り値として -1 ~ 1 の範囲で返されます。
第一引数を、固定値(例: 1, 100, 0.5f ...) にすると、毎回同じ生成の仕方をします。
この記事では毎回ランダムに動いて欲しいので Randam.Range() で乱数を使いますが様々な方法を試してみてください。
第ニ引数は、下記のような Update() などで時間を加算していきます。
また、掛け算することで動きを早めたり遅くしたりできます。(自分の環境では 0.3 が最適)
void Update()
{
time += Time.deltaTime * timeSpeed;
}
実装
コードのほうは以下のようになっています。
降ってくるボールだけ用意してください。
[SerializeField] private GameObject ball;
public float timeSpeed = 0.3f;
private float time = 0;
void Start()
{
StartCoroutine("Create");
}
void Update()
{
time += Time.deltaTime * timeSpeed;
}
IEnumerator Create()
{
float rand = Random.Range(-1000, 1000);
while (true)
{
float noise = Unity.Mathematics.noise.snoise(new float2(rand, time));
Instantiate(ball, new Vector3(noise * 7, 7, 0), Quaternion.identity);
yield return new WaitForSeconds(0.3f);
}
}
Start() で Create() コルーチンを呼び、一定間隔でボールを生成しています。
Update() では snoise の第ニ引数に入れるために時間計測しています。
まとめ
連続する乱数について説明しました。
滑らかに動かしたいときなどには、便利な関数だと思います。