【Unity】一定のテンポで処理をする【メトロノーム】

Unityで一定のテンポを刻みたくなりました。

#【環境】
・Mac OSX El Capitan
・Unity versiton:2018.3.0

#音だけをテンポよく鳴らしたい場合
音だけ大丈夫な場合はこちらの記事の仕組みがとてもいい感じです。
 [[Unity] 正確な時間間隔で効果音を出す](https://qiita.com/orangewk/items/c84f5234b316de59d7d2)
ググってたら上記の記事に書かれているコードを解説しているQ/Aに出会ったので貼っておきます。
 [【Unity】音ゲー制作で曲とテンポずれてしまう](https://teratail.com/questions/248577)

#音に合わせて他のことも同時に処理したい場合
AudioSource.PlayScheduled();は音を出してくれますが、音と同時に別の処理がしたい場合は他の方法が必要です。

##Case1：ずっと同じテンポでOK！→InvokeRepeating（）を使う
InvokeRepeatingを使う手があります。
メリットはコードがシンプルなので読みやすいこと！
第一引数にリピートしたいメソッド名、第二引数に始めるまでの待ち時間(秒）、第三引数にリピートする間隔(秒）を入れます。

public void InvokeRepeating (string methodName, float time, float repeatRate);
[MonoBehaviour.InvokeRepeating](https://docs.unity3d.com/ja/current/ScriptReference/MonoBehaviour.InvokeRepeating.html)

```C#:TempoMaker_InvokeRepeating.cs
//invokerepeatingのつかいかた
//https://docs.unity3d.com/ja/current/ScriptReference/MonoBehaviour.InvokeRepeating.html

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TempoMaker_InvokeRepeating : MonoBehaviour
{
    [SerializeField] AudioSource audioSource;
    public const float START_SECONDS = 0.0f;
    public const float INTERVAL_SECONDS = 1.0f;

    // Start is called before the first frame update
    void Start()
    {
        audioSource = GetComponent<AudioSource>();
        InvokeRepeating("PlaySound", START_SECONDS, INTERVAL_SECONDS);
    }

    private void PlaySound()
    {
        audioSource.Play();
        print("Played");
    }
}
```
空のオブジェクトにAudioSourceとこのスクリプトをアタッチ。
AudioSourceには適当なAudioClipを入れておいてください。
ゲームを走らせると、一定間隔で音が再生され、コンソールに”Played”が増えていくと思います。


##Case2：テンポは途中で変えたい！→コルーチンを使う
途中で好きなテンポに変えたいのであればコルーチンを使いましょう。
INTERVAL_SECONDSの値を変えることでテンポを変更できます。
内容はTempoMaker_InvokeRepeating.csとほぼ一緒ですが、マウスのボタンを押している間はテンポを止める機能を追加しています。

```C#TempoMaker_Coroutine.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TempoMaker_Coroutine : MonoBehaviour
{
    [SerializeField] AudioSource audioSource;
    // Start is called before the first frame update
    private IEnumerator coroutine;
    public float INTERVAL_SECONDS = 1.0f;//インスペクターから変更可能（もちろんスクリプトからも）
    void Start()
    {
        audioSource = GetComponent<AudioSource>();
        coroutine = TempoMake();
        StartCoroutine(coroutine);
        
    }

    // Update is called once per frame
    void Update()
    {
        //マウスの左ボタンを押している間は止める、離すと再スタート
        if (Input.GetMouseButtonDown(0)) {
            StopCoroutine(coroutine);
        }else if (Input.GetMouseButtonUp(0)){
            StartCoroutine(coroutine);
        }
    }

    IEnumerator TempoMake()//一定間隔で音を鳴らして、”Played”をコンソールに表示
    {
        while (true) {
            yield return
             new WaitForSecondsRealtime(INTERVAL_SECONDS);
            audioSource.Play();
            print("Played");
        }
    }
}
```


#InvokeRepeating vs コルーチン

InvokeRepeatingは可読性は高いですが、大量のオブジェクトに使いたい場合はパフォーマンス的に不向きのようでうです。
https://answers.unity.com/questions/477862/what-is-the-best-between-startcoroutine-or-invoker.html

InvokeRepatingとコルーチンのメリット・デメリットはこちらの記事にまとまっていました。（意訳しています）
[InvokeRepeating vs Coroutines: Run a method at certain time intervals](https://www.codinblack.com/how-to-run-a-method-at-certain-time-intervals-in-unity/)




>Using an Invoke (or InvokeRepeating) is easier than using a coroutine. On the other hand, Coroutines are more flexible. You cannot pass a parameter to an invoked method but you can do this to a coroutine.
>> Invoke (または InvokeRepeating) はコルーチンより使いやすい一方、コルーチンは自由度が高い。
>>Invokeには変数を渡せないが、コルーチンなら渡すことできる。

>Another thing which we have to mention is coroutines are more performance-friendly than the Invoke. For basic games, it does not matter much but if you have several objects which do the same thing, you should consider using Coroutine instead of Invoke.
>>さらに言えることはコルーチンの方がパフォーマンスに優れているということ。簡素なゲームであればあまり関係ないが、複数のオブジェクトで同じことを行う場合、Invokeの代わりにコルーチンの使用を考えるべき。

>The last difference between Invoke and Coroutine which we will cover is the execution condition after the deactivation of the object. Invoke and InvokeRepeating do not stop after the game object is deactivated. On the other hand, this not true for coroutines. They stop after the game object is deactivated or destroyed. Therefore, you should use Invoke or InvokeRepeating, if you would like your method to continue running, even though the object is deactivated after the method is triggered.
>>最後の違いは、オブジェクトを非アクティブにした後の実行状況。InvokeとInvokeRepeatingはゲームオブジェクトを非アクティブにした後も止まらない。一方でコルーチンはゲームオブジェクトを非アクティブにしたり、デストロイすると止まる。なので、もしオブジェクトが非アクティブになってもメソッドを回し続けたいのであればInvokeかInvokeRepeatingを使うのが良い。

以上です。コルーチン便利だなー。