LoginSignup
3
4

More than 5 years have passed since last update.

Coroutineの罠にハマった話(Update内で呼ばれるCoroutineとUpdate内の処理の順番)

Last updated at Posted at 2018-10-22

結論

具体的な事例を元に書くので話が少しややこしくなるかもしれないため,とりあえず結論を書きます.

Update内で呼ばれるCoroutineとUpdate内の処理の順番

[初コルーチン呼び出し]
1. [StartCoroutineよりも上の部分のUpdate関数内の処理]->
2. [Coroutine] ->
3. [StartCoroutineよりも下の部分のUpdate関数内の処理]

[2回目以降のコルーチン呼び出し]
1. [Update関数内の処理全て]->
2. [Coroutineの続き]

Screen Shot 2018-10-23 at 1.22.47 (2).png

やりたかったこと

Coroutine内でアニメーションの処理を書いて,終わったタイミングだけUpdate内でアクションを起こしたかった...
(*イメージは下記のコード)

CoroutineSample.cs
public class test : MonoBehaviour {
    bool flag = false;
    void Start () { 
    }

    void Update () {
           flag = false;
           if(Time.FrameCount%3600 == 0) StartCoroutine("Motion");  
           if(flag) Debug.Log("true")
    }

    private IEnumerator Motion()
    {
        for (int i = 0; i < 30; i++)
        {
            //AnimationCode
            yield return null;
        }
        flag = true;
        yield return null;
    }
}

しかし,何も起こらなかった....

自分の理解でのこのコードの処理の順番

  1. [StartCoroutineよりも上の部分のUpdate関数内の処理]->
  2. [Coroutineの続き] ->
  3. [StartCoroutineよりも下の部分のUpdate関数内の処理]

って感じでした.
しかし,Update内でDebug.Logを使い,bool値を追ってみるとずっとfalseになっている...おかしい...

Coroutine,Updateの実行順番

処理の実行順序を調べるため,こんなコードを書いてみた

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

public class test : MonoBehaviour {

    void Start () {

    }

    void Update () {

        Debug.Log("Before-Update");
        if (Time.frameCount == 0)
        {
            StartCoroutine("Motion");
        }
        Debug.Log("After-Update");
    }

    private IEnumerator Motion()
    {
        for (int i = 0; i < 30; i++)
        {
            Debug.Log("--------Coroutine----------");
            yield return null;
        }


    }
}

結果
Screen Shot 2018-10-23 at 1.22.47 (2).png

結論

初めにCoroutineが呼ばれるのは予想してた
1. [StartCoroutineよりも上の部分のUpdate関数内の処理]->
2. [Coroutine] ->
3. [StartCoroutineよりも下の部分のUpdate関数内の処理]

であったが,それ以降の処理については
1. [Update関数内の処理]->
2. [Coroutineの続き]

のようでした

補足

メソッド

  • yield return null: yield return nullにたどり着いた時点で処理を中断して次のフレームからまた処理の続きを行うって物です.

意見

自分はキーフレーム系の処理があまり好きではありません...めんどくさいので..ですが映像を作っているとそうも言ってられない時があります.例えばAEとかで作っている回転し終わったタイミングで平行移動とかカクカクした感じのモーションなど.そんな時にCoroutineを使うことでそのキーフレームを使うことの悩みも解消できるのでぜひ試してみてください.
簡易的なものですが参考にしていてください↓

sample02.cs
private IEnumerator Motion()
    {
        int frameNum = 60;
        for (int i = 0; i < frameNum; i++)
        {
            var dy = 30.0f / frameNum;
            this.transform.Rotate(new Vector3(0.0f, -dy, 0.0f));
            yield return null;
        }

        frameNum = 10;
        for (int i = 0; i < frameNum; i++)
        {
            var dx = 25.0f / frameNum;
            this.transform.Rotate(new Vector3(dx, 0.0f, 0.0f));
            yield return null;
        }
        yield return null;
    }
3
4
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4