分享

由Unity3d倒计时说开,谈StartCoroutine以及yield return的一些小细节

 3dC 2014-01-09

要做个倒计时的小功能,以前都是通过在update里记录Time.time以及上次时间变化时刻,做差后差值在0.9-1.1就减去一秒。

原理so简单,代码如下:

using UnityEngine;

using System.Collections;

public class CountDownMonoBehaviour{

    public int totalSeconds = 60;

    int leaveSeconds;//剩余时间

    string guiTitle = "开始";

    bool whetherOn = false;

    float lastTime;//上次时间变化的时刻 或者 本次开始的时刻


    void OnGUI(){

        GUI.Button(new Rect(100,50,70,40),leaveSeconds.ToString());

        if(GUI.Button(new Rect(200,50,70,40),guiTitle)){

            if(guiTitle == "开始"){

                guiTitle = "暂停";

                whetherOn = true;

                lastTime = Time.time;

            }

            else{

                guiTitle = "开始";

                whetherOn = false;

            }

        }

    }

 

    void Awake(){

        leaveSeconds = totalSeconds;

    } 

    void Update(){

        if(whetherOn){

            if(Time.time-lastTime>0.9f&&Time.time-lastTime<1.1f){

                leaveSeconds--;

                lastTime = Time.time;

            }

        }

    }

}


在认识了StartCoroutine函数后决定用这个来做一个倒计时。要注意的见一下代码备注。

public class CountDownMonoBehaviour{

    // 总秒数

    public int totalSeconds = 60;

 

    int leaveSeconds;

    bool onCountDown = false;

    string countDownTitle = "开始";

 

    void Awake(){

        leaveSeconds = totalSeconds;

    }

    void OnGUI(){

        GUI.Button(new Rect(50, 50,50, 50), leaveSeconds.ToString());

 

        if(GUI.Button(new Rect(150, 50, 80, 30), countDownTitle)){

            if(countDownTitle == "开始"){

                countDownTitle = "暂停";

                onCountDown = true;

                StartCoroutine(DoCountDown());

            }

            else{

                countDownTitle = "开始";

                onCountDown = false;

                StopAllCoroutines();  //只要StartCoroutine启动后,由它产生的效果就一直存在,除非你StopAllCorutines,而且它还会叠加,所以在OnGUI中要通过各种条件使其一次就触发一次,不需要的时候则关闭

            }

        }

    }

 

    void Update(){

        print(countDownTitle.ToString() + ",leave seconds:"+leaveSeconds.ToString());

    }

 

    IEnumerator DoCountDown(){

        while(leaveSeconds > 0){

            yield return new WaitForSeconds(1f);

            leaveSeconds--;

        }

    }

}



注意上面这段代码黄色背景的两句,由于开始倒计时,都需要经过一秒,才开始减去一秒,所以要先WaitForSeconds(1f);再leaveSeconds--;

若leaveSeconds--写在前,则突然就会减去一秒,不符合逻辑。

不解的是这里yield return 后,后面还继续执行后面的语句. 就当这里是个语法惯例吧。


今天写个东西也用到了类似的东西,在yield return 前执行和yield return后执行却得到了不同的效果。

具体就是测试个scenes传值的demo,这里从Scene1场景传值到Scene2场景。

先声明了一个类,定义了一个静态的变量,挂到Scene1的Camera上,代码:

using UnityEngine;

using System.Collections;

 

public class ValuePassMonoBehaviour

{

    public static int valuePassed ;

}


Scene1 的camera上挂的数据传值代码为:(详见注释)

public class Scene1MonoBehaviour{

    void OnGUI(){

        GUI.Button(new Rect(0,0,1024,50),"Scene0");

 

        if(GUI.Button(new Rect(100,100,100,30),"Scene1")){

            StartCoroutine(GetValue()); //当然这里完全可以不使用协程来设置值,但是有些情况比如从网络上获得数据就不得不使用协程了

            Application.LoadLevel(1);

        }

    }

 

    IEnumerator GetValue(){

        //ValuePass.valuePassed= 123456;  //写在yield return null之前可以顺利传值

        yield return null;

        ValuePass.valuePassed= 123456;    //写在yield return null之前传值不过去

    }

}


Scene2的camera上挂的数据传值代码为:

public class Scene2MonoBehaviour{

    void OnGUI(){

        GUI.Button(new Rect(0,0,1024,50),"Scene1");

        if(GUI.Button(new Rect(100,100,100,30),ValuePass.valuePassed.ToString())){

            Application.LoadLevel(0);

        }

    }

}


源程序:http://www./file/New%20Unity%20Project%206.rar?fid=2986442414-250528-3500017322&time=1354197538&sign=FPDTAE-DCb740ccc5511e5e8fedcff06b081203-7V1ch0EtF8H1ic%2By0kRRoVNQaZs%3D&expires=1h&digest=841e3aa0e0838e2fe6d2f00bf8c44ed0



    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多