【Unity】波がうち寄せる南の島。。。出来た♬

[前回はとりあえず、波を再現しました](https://qiita.com/MuAuan/items/a95363fa11fbe50afe62)が、どうも動くメカニズムがちょっと。。。ということで普通に物理的に妥当な式でやり直し。。合わせて南の島を再現してそこに打ち寄せる姿♪
出来ました！

###やったこと
（１）物理的に波は？
（２）波を動かす
（３）山を作る
（４）OculusGoで見る
###（１）物理的に進行波は？
適当な参考サイトがない。。。ということで以下
【参考】
・[正弦波＠高校物理の備忘録](https://physnotes.jp/wave/sin-wave/)
以下のような波は時間とともに動くということです。

```math
y(x,t)=A\sin2\pi(\frac{t}{T}-\frac{x}{\lambda})
```
ここで時間的な周期T,波長λ、振幅Aです。
ちなみに波速つまり波の速さ(波長λ分進むのに要する時間T)は

```math
v=\frac{\lambda}{T}
```
###（２）波を動かす
ということで前回のCalculateを以下のように変更しました。

```cs
float Calculate(double X, double Y)
    {
        float s= (float)Math.Sin((X+Y-0.1*t)*0.8);
        float s1 = 1 + (float)0.05 *UnityEngine.Random.value + (float)0.1 *(float)s;
        //float s1 = UnityEngine.Random.value;
        return s1;
    }
```
新しいのはsinの中に-0.1tを入れたところ。。この係数０．１が波速ということになります。
また、進行方向は（X,Y）の係数(1,1)の方向になります。
###（３）山を作る
山は前々回と同じですが、山に草色と石色をペイントしてよりそれらしく装飾してみました。
ちなみに山のアッセットは以下のものを使いました。
Free Island Collection
今回はついにTerrainのTextureをEdit Textureで貼り付けることができました。
![IslandInSea3.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/1d30bc4d-5d99-77cc-1723-b35c45e88682.jpeg)
これを使って山をぬりぬりしました。
![yamanuri.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/33d5f5be-d6f2-3562-af91-d1152de2bc54.jpeg)

そして懸案の海の色。。。これいいのないけどとりあえず青っぽい色で塗りました。
![IslandinSea.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/7d2c5a70-27f6-6c75-1908-10e2367e6fef.jpeg)
【参考】
・[テレインテクスチャ@Unityマニュアル](https://docs.unity3d.com/ja/current/Manual/terrain-Textures.html)
###（４）OculusGoで見る
これ位がどうやらOculusGoの限界ではないか。。転送にすごく時間がかかるようになった。動作は一応できているけど。。。
ということでこんな感じになりました。
[【Unity】波がうち寄せる南の島。。。出来た♬](https://youtu.be/xIYbfeK69Cs)
<a href="http://www.youtube.com/watch?feature=player_embedded&v=xIYbfeK69Cs" target="_blank"><img src="http://img.youtube.com/vi/xIYbfeK69Cs/0.jpg"  </a>
※画像をクリックするとYouTube動画につながります
###まとめ
・島と海を作成して南の島に打ち寄せる波を作成した
・進行波を物理的に動かした
・島をぬりぬりした

・人を配置して冒険したい
・適当なトリガーで雨を降らせたい、風を吹かせたい
・森や木々を作りたい
###おまけ
全体のコード

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

public class RandCircle : MonoBehaviour
{
    [SerializeField]
    double baseX = 20.0;
    [SerializeField]
    double baseY = 20.0;
    [SerializeField]
    double renderArea = 50;
    TerrainData terrainData;
    float t = 0;

    // Use this for initialization
    void Start()
    {
        terrainData = GetComponent<Terrain>().terrainData;
        StartCoroutine(UpdateTerrainCoroutine());
    }
    // Update is called once per frame
    void Update()
    {
        terrainData = GetComponent<Terrain>().terrainData;
        StartCoroutine(UpdateTerrainCoroutine());
        //Debug.Log(terrainData.heightmapHeight);
        renderArea = 50;
        t += 1;
    }
    float Calculate(double X, double Y)
    {
        float s= (float)Math.Sin((X+Y-0.1*t)*0.8);
        float s1 = 1 + (float)0.05 *UnityEngine.Random.value + (float)0.1 *(float)s;
        //float s1 = UnityEngine.Random.value;
        return s1;
    }
    IEnumerator UpdateTerrainCoroutine()
    {
        var heights = new float[terrainData.heightmapWidth, terrainData.heightmapHeight];
        //renderArea *= 0.98;
        var startX = baseX - renderArea / 2.0;
        var startY = baseY - renderArea / 2.0;
        var renderAreaPerWidth = renderArea / terrainData.heightmapWidth;
        var renderAreaPerHeight = renderArea / terrainData.heightmapHeight;
        for (int x = 0; x < terrainData.heightmapWidth; x++)
        {
            for (int y = 0; y < terrainData.heightmapHeight; y++)
            {
                heights[x, y] = Calculate(
                    startX + x * renderAreaPerWidth,
                    startY + y * renderAreaPerHeight);
                heights[x, y] = heights[x, y]/ 2;
            }
        }
        terrainData.SetHeights(0, 0, heights);
        yield return null;
    }
}
```