ワンボタンで動くゲームを作ってみた（長押し判定の作成）

(12/13)プログラムを一部修正しました

この投稿は「Unity アドベントカレンダー 2023その1」の2日目の記事です。
3日目の明日は @tyanmahou さんの「[UnityTextで頂点追加でルビ表示してみた](https://qiita.com/tyanmahou/items/c400d7d8b8cb2d7a6f61 "UnityTextで頂点追加でルビ表示してみた")」です。

Unityでゲームを制作中のShoyoFILMSと申します。Unityには出されたお題で1週間でゲームを作るUnity1weekという企画が定期的に開催されるのですが、先日のUnity1weekのお題は「１ボタン」でした。
投稿された作品（https://unityroom.com/unity1weeks/60）

お題をとんちで解釈してボタンを押したら犬がワンと鳴くとか、1匹のいのしし（ボタン）が登場するとかやれば面白いのができたかもしれませんが、

その時既にゲームを作っていたのと、そういえばボタンをホールド（長押し）しているかの判定処理って作ったことないなと思ったので使うボタンは1つでプッシュ（短く押して離す）とホールドで操作するゲームを作ってみることにしました。

# 実装１：UIの用意
まずは長押しをした時にそれが分かるUIを作りましょう。長押し時に減衰するゲージを用意します。記事では円形のImageを使ったゲージにしています。

1.円の画像を用意し、Image TypeをFilledに設定

2.Fill OriginをTopに設定

これでFill Amountの値を変更すると円が欠けるようになります。色とか欠ける方向（ClockWise）は自由に設定してください。

ゲームでは沢山長押し操作をする場所があるので画像はプレハブにした方がいいかもしれません。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82103/5524f92c-458d-4728-6acb-7f7ca1f2b7ff.png)

余談ですが、分かりやすさの為に私の作ったゲームでは長押しが必要な操作はテキストの前に●、短く押して実行するものは▼が前についています。
![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82103/8f309465-f6b2-2c88-f1d2-7b15e4f3b225.jpeg)

# 実装２：スクリプトの用意
続いてUIを操作するスクリプトを書きます。仕様としてはこんな感じ
A)短く押した時は反応しないor短押し処理になる
B)長押ししてる時に円が欠けていく
C)円がかけきったら何かが実行される
D)かけきる前に長押しを離したら初期状態に戻る

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

public class PieScript : MonoBehaviour
{
    public Image Pie; //欠ける画像
    public bool Pie_move = true; //画像を欠けさせるか（0以下にならないように制御）

    public void SetPie(float p){
        Pie.fillAmount = p;
    }

    public void dPie(float p){
        if(Pie_move){
            Pie.fillAmount += p;
        }
    }

    public void SetMove(bool canMove){
        Pie_move = canMove;
    }

    void Update()
    {
        if(Pie.fillAmount < 0){
            Pie_move = false;
        }
    }
}

```

こちらがゲージ本体のスクリプトです。Fill Amountを外部から変化できるようにして
それが0以下にならないように制御しています。
public Image Pieには最初に用意した画像のプレハブをセットしてください。

続いて制御するスクリプト。これはゲームの管理部に書くといいでしょう。

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

public class PieControl : MonoBehaviour
{
    public GameObject TargetPie;

    private bool holdingDown;
    private const int threshold = 100;
    private const int hold_start = 30;
    private int duration = 0;

    // Start is called before the first frame update
    void ProceedSingle()
    {
        Debug.Log("single");
    }

    void ProceedHold()
    {
        Debug.Log("Hold");
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.anyKey) {
            duration = duration + 1;
            holdingDown = true;

            if(duration>hold_start){ //B)長押ししてる時に円が欠けていく
                TargetPie.GetComponent<PieScript>().dPie(-0.01f);
            }
        }

        if (!Input.anyKey && holdingDown) {
            //A)短く押した時は反応しないor短押し処理になる
            if (duration < threshold+hold_start) {
                ProceedSingle();
            }

            //D)かけきる前に長押しを離したら初期状態に戻る
            TargetPie.GetComponent<PieScript>().SetPie(1f);

            duration = 0;
            holdingDown = false;
        }

        if (duration >= threshold+hold_start) { //C)円がかけきったら何かが実行される
            ProceedHold();
        }
    }
}
```
public GameObject TargetPieには最初に用意した画像のプレハブをセットしてください。

なんかキーが押されたらholdingDownが有効になり、durationが増えていきます。
durationが一定の値（hold_start）を超えたら長押し判定スタート。
どんどん設定した画像が欠けていきます。

キーを離した時にthreshold+hold_start以下なら短く押した判定

キーを押したままdurationがthreshold+hold_startの値を超えたら長押し成功です。

# 実装３：実際に作ったゲーム
https://unityroom.com/games/stridetothepaleblue#google_vignette
もうちょっと要素が増えたら楽しそうですね。

# 追記
知り合いに見せたら長押しはInputSystemsにあるみたいですorz
ま、まあ自分で作れた方が色々改造できるし