color×2

自分なりに学んだ事を記すところ

敵の攻撃を受けたら一時停止する

今回はプレイヤーが敵の攻撃を受けたら、数秒動きを止めてまた再開するという流れを作っていこうと思います。

改変前はこんな感じに作ってました。

 

攻撃を受けても動き続けています。
スムーズにプレイできて良いかなと思ってこの流れを作りましたが、人によっては焦ってしまうとアドバイスをいただきました。

 

早速一時停止するように作ろうと思います。

ググったところ、Time.timeScaleを使えば停止できると判明。
Time.timeScale=0なら停止、1なら再開します。

そしてコルーチン(数秒たってから処理を行う)を使えばもうできる…
コルーチンがよく分からない方はこちらのサイトを読んでみてください↓

【Unity】処理を止める方法。一定時間待ってから処理を実行するスクリプト - カリップ

なんだ、思ったより簡単にできてしまった…

private void OnTriggerEnter2D(Collider2D collision)
    {
        //敵の弾丸(Damage)が当たったら
        if (collision.gameObject.tag == "Damage")
        {
            //コルーチンで3秒間停止
            StartCoroutine(Restart()); 
        }
    }

public IEnumerator Restart()
    {
        //3秒停止する
        Time.timeScale = 0;
        yield return new WaitForSeconds(3.0f);

        //再開する
        Time.timeScale = 1;
    }

完璧だろうと動作確認。

ダメでした。3秒経っても動かず、しかも攻撃が出来てしまう…

コルーチンが働かない原因が何か探っているとこんなサイトを発見。

Time.timeScaleに影響されないWaitForSecondsRealtime - Unity(C#)初心者・入門者向けチュートリアル ひよこのたまご

しかし実はWaitForSecondsで扱われる時間は、Time.timeScaleに影響され、Time.timeScaleを0にすると永久に再開されません!

なんだと!?

Time.timeScaleの影響を無視した現実時間分だけ待機したい場合は、WaitForSecondsの代わりにWaitForSecondsRealtimeを使います!

なるほど!もしかしてこれに変更するだけで上手くいくかも?
yield return new WaitForSeconds(3.0f);
yield return new WaitForSecondsRealtime(3.0f);に書き換えて動作確認。

動きました!!これで効果音やプレイヤーの見た目を調整すればそれっぽくなりそう。
プレイの流れを確認していると、ゲームオーバーになってもう一度プレイするとこの画面から動かなくなってしまった。

原因はやはりTime.timeScale。それとシーン移動が関係していた。
ライフが0になればゲームオーバーのシーンに移動するように書いているのですが、Time.timeScale=0になってから即座にシーン移動しているようです。

なのでこれ以降の3秒待ってTime.timeScale=1に戻す処理はしてくれません。

対処としてStart()Time.timeScale=1を記述して解決しました。

あとはダメージを受けていない時だけ攻撃できるようにbool値を使ったif文を入れたり、効果音入れたり、プレイヤーの見た目をどうにかすると…

色々改善の余地はありますが、望んでいた一時停止の要素を追加することができました!

最終的に出来上がったコードを載せて終わりにします。

bool isDamage = false; //ダメージを受けている最中か?
SpriteRenderer sp; //プレイヤーを非表示にするために必要

void Start()
    {
        sp = GetComponent<SpriteRenderer>();

        //動くように初期化
        Time.timeScale = 1;
    }

void Update()
    {
        //ダメージを受けていない時なら攻撃可能
        if (!isDamage)
        {
            //プレイヤーが攻撃するように書いてる
        }
    }

private void OnTriggerEnter2D(Collider2D collision)
    {
        //敵の弾丸(Damage)が当たったら
        if (collision.gameObject.tag == "Damage")
        {
            //ダメージ受けてたら処理を行わない
            if (isDamage)
            {
                return;
            }

            //コルーチンで3秒間停止
            StartCoroutine(Restart()); 
        }
    }

public IEnumerator Restart()
    {
        //停止する
        isDamage = true; //ダメージ受けてる最中
        sp.color = new Color(0, 0, 0, 0); //プレイヤーを視覚上消す
        Time.timeScale = 0;

        //ダメージ音鳴らすことを書いてる

        //3秒停止する
        yield return new WaitForSecondsRealtime(3.0f);

        //再開する
        Time.timeScale = 1;
        sp.color = new Color(1f, 1f, 1f, 1f); //プレイヤー表示
        isDamage = false;
    }