【Unity】保存した時刻からの経過時間によって処理を分岐させる


# やりたいこと
* 攻撃を試みた時、その瞬間の時刻と前回攻撃時の時刻を比較し、前回攻撃からの経過時間によって処理を分岐させる

発動を無効化(on/off)ではなく経過時間によって発動するアクションを変えたかったためこの実装方法を選択

`DateTime型`を用いて処理を書きます

# 時間の保存
まずはじめに「最後に発動した時刻」を保存する
* PlayerPrefsに保存

「PlayerPrefs」については下記記事を参考にしました
[【Unity】PlayerPrefs の使い方やメリット/デメリットなどをまとめてみた](https://qiita.com/riekure/items/3fd4526b13d8e89a7fc6)

* DateTime型はPlayerPrefsに対応していないため、バイナリに変換しstring型に置き換えます
```C#
using UnityEngine;
using System;

public class Sample
{
    public static void SaveAttackTime()
    {
        var currentTime = DateTime.Now;
        PlayerPrefs.SetString("LastAttackTime", currentTime.ToBinary().ToString()); 
    }
}
```

# 保存した時刻をロードする
```C#
public static string LoadAttackTime()
{
    string lastAttackTimeString = PlayerPrefs.GetString("LastAttackTime", "");
    return lastAttackTimeString;
}
```

# 攻撃を試みた時に瞬間の時刻と前回攻撃時の時刻を比較
```C#
public void CheckAttackEnabled() //攻撃を試みた際に呼び出す
{
    //前回攻撃時刻が保存されていない場合、最初の攻撃
    if (string.IsNullOrWhiteSpace(LoadAttackTime()))
    {
        //攻撃
        SaveAttackTime(); //この攻撃時刻を保存する
    }
    else
    {
        long timeValue = Convert.ToInt64(LoadAttackTime());
        var PastPostBoardTime = DateTime.FromBinary(timeValue);
        DateTime dt1 = DateTime.Now;
        DateTime dt2 = PastPostBoardTime;
        if (dt1 >= dt2.AddSeconds(10))
        {
            //攻撃
            SaveAttackTime(); //この攻撃時刻を保存する
        }
        else
        {
            //攻撃失敗
        }
    }
}
```
攻撃を試行した時刻(dt1)と、前回の攻撃の時刻(dt2)+設けたいインターバル(今回は10秒)を比較し、インターバル経過前に再度攻撃を試行すると失敗となります

PlayerPrefsは同じkey(今回の場合「"LastAttackTime"」)で保存した場合上書きされるため、攻撃成功時に時刻を保存してあげます

死んだときや終了したときには**保存した時間を削除する**処理を入れます

```C#
//死んだときや終了したときには下記処理で保存した時間を削除
    public static void DeleteAttackTime()
    {
        PlayerPrefs.DeleteKey("LastAttackTime");
    }
```

保存先を統一すれば攻撃の種類によって異なるインターバルの幅を設けることが可能です



---
スクリプト全文
```C#
using UnityEngine;
using System;

public class Sample
{
    public static void SaveAttackTime()
    {
        var currentTime = DateTime.Now;
        PlayerPrefs.SetString("LastAttackTime", currentTime.ToBinary().ToString()); 
    }

    public static string LoadAttackTime()
    {
        string lastAttackTimeString = PlayerPrefs.GetString("LastAttackTime", "");
        return lastAttackTimeString;
    }

    public void CheckAttackEnabled() //攻撃を試みた際に呼び出す
    {
        //前回攻撃時刻が保存されていない場合、最初の攻撃
        if (string.IsNullOrWhiteSpace(LoadAttackTime()))
        {
            //攻撃
            SaveAttackTime(); //この攻撃時刻を保存する
        }
        else
        {
            long timeValue = Convert.ToInt64(LoadAttackTime());
            var PastPostBoardTime = DateTime.FromBinary(timeValue);
            DateTime dt1 = DateTime.Now;
            DateTime dt2 = PastPostBoardTime;
            if (dt1 >= dt2.AddSeconds(5))
            {
                //攻撃
                SaveAttackTime(); //この攻撃時刻を保存する
            }
            else
            {
                //攻撃失敗
            }
        }
    }
    //死んだときや終了したときには下記処理で保存した時間を削除
    public static void DeleteAttackTime()
    {
        PlayerPrefs.DeleteKey("LastAttackTime");
    }
}
```
# 感想
ケースがケースだけに「いつ使うん？」といった内容となってしまいました

拙い実装ですが他に良い方法知っておりましたら教えて下さい

# 参考文献

* [C#を攻略しようー変換ー](https://www.kisoplus.com/sample2/henkan.html)

* [【Unity】PlayerPrefs の使い方やメリット/デメリットなどをまとめてみた](https://qiita.com/riekure/items/3fd4526b13d8e89a7fc6)