Invoke 调用的函数不能带参数
Invoke(“printCount”, 2); 表示经过2秒钟之后调用printCount函数
InvokeRepeating(“printCount”, 3, 1); 经过3秒钟之后调用printCount函数,之后每隔1秒调用一次该函数
IsInvoking() 判断是否有通过Invoke方式调用的函数
CancelInvoke(); 取消这个脚本上所有的调用
CancelInvoke(string methodName); 取消名字为methodName的调用
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
/// 一旦通过invoke启动了一个函数,该游戏对象是否激活失活无关,该组件是否有效无关
/// 该脚本一旦删除,其上所有invoke启动的函数都会取消执行
///
public class Invoke : MonoBehaviour
{
static int num;
private void Awake()
{
print("Awake");
}
void Start()
{
//直接调用函数
printCount();
//Invoke调用的函数不能带参数
Invoke("printCount", 2);//经过2秒钟之后调用printCount函数
InvokeRepeating("printCount", 3, 1);//经过3秒钟之后调用printCount函数,之后每隔1秒调用一次该函数
//Invoke("hasInvoke", 5);
}
// Update is called once per frame
void Update()
{
}
///
/// 注意:该函数不能有参数,如果有参数,异步调用执行不到该函数,不报错
///
void hasInvoke()
{
//判断是否有通过Invoke方式调用的函数
if (IsInvoking())
{
CancelInvoke();
}
}
void printCount()
{
num++;
print("num="+num);
}
}
1
Coroutine StartCoroutine(IEnumerator routine)
开启一个协程,利用yield语句暂停在某点,yield返回值指定了什么时机协程恢复。对于多帧执行一次的行为非常适合用协程解决,它几乎没有什么性能开销。参数传递没有限制。
2、
Coroutine StartCoroutine(string methodName, object value = null)
通过字符串开启一个协程,主要的目的是可以使用StopCoroutine来终止指定名字的函数,但是此种方法只能传递一个参数,性能上也有所损耗。
如下协程的启动方式
//形式一
StartCoroutine(CustomCorutineFn));
StartCoroutine(CustomCorutineFn(7));//向方法中传递参数
//形式二
StartCoroutine("CustomCorutineFn” );
StartCoroutine("CustomCorutineFn”,7);//向方法中传递参数
3
终止协议
1、void StopAllCoroutines()
终止运行在该MonoBehaviour上的所有协程。
2、void StopCoroutine(string methodName)
终止运行在该MonoBehaviour上的所有名字为methodName的协程。仅仅使用字符串开启的协程才可以使用该函数进行终止。
yield
yield是一种特殊类型的返回值语句,它可以确保函数在下一次被执行时,不是从头开始,而是从yield语句处开始,如果在函数中用了yield语句,需要把函数的返回值改成IEnumerator。yield后面可以有的表达式。
1、yield null(协程将在下一帧所有脚本的Update执行之后,再继续执行)
2、yield WaitForSeconds(协程在延迟指定时间,且当前帧所有脚本的Update全都执行结束后才继续执行)
3、WaitForEndOfFrame (一帧结束时,渲染之前)
4、yield WaitForFixedUpdate(协程在所有脚本的FixedUpdate执行之后,再继续执行,即等待物理更新时间0.02秒)
5.yield StartCoroutine(协程在指定协程执行结束后,再继续执行)6、yield wWW((协程在WWW下载资源完成后,再继续执行)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///
/// 如果协程启动之后,该脚本所在的游戏对象失活状态,该游戏对象上所有的协程停止,游戏对象激活也不会执行其上的协程
/// 跟该脚本组件是否有效无关
/// 该脚本一旦删除,其上所有StartCoroutine启动的协程都会取消执行
///
public class Coroutine : MonoBehaviour
{
public GameObject prefab;
// Start is called before the first frame update
void Start()
{
//普通函数调用方式
//funCoroutine(3);
//第一种:通过传入协程函数执行协程,这种方式不受参数的限制,不能制定该协程停止,只能通过StopAllCoroutines停止所有的协程
//StartCoroutine(funCoroutine(3));
//第二种:通过传入协程函数名字执行协程,注意,如果有参数而传递,该协程函数启动不了,而且报错,
//这种启动方式可以通过StopCoroutine停止该协程函数
//如果函数有参数,只能一个参数
StartCoroutine("funCoroutine",3);
StartCoroutine(createGameObject(1));
}
// Update is called once per frame
void Update()
{
if(IsInvoking())
{
print("IsInvoking");
}
}
///
/// 定义协程函数
/// 返回值:IEnumerator
/// 函数体:一定要有yield return语句
///
///
///
IEnumerator funCoroutine(float waitTime)
{
print("start funCoroutine " + Time.time+" frameCount="+Time.frameCount);
yield return null;//挂起协程,挂起一帧,等待时间到了之后继续执行下面的代码
print("yield return null "+Time.time + " frameCount=" + Time.frameCount);
yield return 100;//挂起一帧
print("yield return 100 " + Time.time + " frameCount=" + Time.frameCount);
yield return 100;//挂起一帧
print("yield return 100 " + Time.time + " frameCount=" + Time.frameCount);
yield return new WaitForSeconds(waitTime);//挂起指定时间,秒
print("yield return new WaitForSeconds + waitTime " + +Time.time + " frameCount=" + Time.frameCount);
yield return 1000000;//挂起一帧
print("yield return 1000000 " + Time.time + " frameCount=" + Time.frameCount);
}
IEnumerator createGameObject(float dtTime)
{
while (true)
{
GameObject go= Instantiate(prefab);
go.SetActive(true);
go.transform.parent = transform;
yield return new WaitForSeconds(dtTime);
if(transform.childCount>=20)
{
StopAllCoroutines();
}
}
}
}
1.在X正方向上有5个物体,依次排列开,实现从第一个物体上升到5米高时第二个物体开始上升,依次执行到最后一个物体。
思路:
协程来控制是哪一个球向上移动,分别替换go游戏对象,等待五秒换下一个, 因为设置的速度是1m/s 所以正常来说5m左右就会停下,但也会有些许的误差,因为每帧的时间都不可能完全一样。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spheres : MonoBehaviour
{
GameObject go;
int index;
void Start()
{
StartCoroutine(goContol(5.0f));
}
void move()
{
if (go.transform.position.y >= 5.0f)
{
return;
}
go.transform.Translate(0, Time.deltaTime * 1, 0);
}
IEnumerator goContol(float rate)
{
while (index < transform.childCount)
{
go = transform.GetChild(index).gameObject;
index++;
yield return new WaitForSeconds(rate);
}
}
void Update()
{
move();
}
}
2.用协程做一个计时器
思路: 时分秒都是用秒来计算。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Timer : MonoBehaviour
{
float curSecond;
Text timer;
int seconds;
int secondNum;
int miniuteNum;
int hourNum;
public bool isPause = false;
void Start()
{
timer = transform.GetComponent();
StartCoroutine(Updata());
}
IEnumerator Updata()
{
while (true)
{
secondNum++;
seconds++;
if (secondNum == 60)
{
secondNum = 0;
}
yield return new WaitForSeconds(1.0f);
}
}
void Update()
{
if (isPause == false)
{
string secstr;
string minstr;
string hourstr;
miniuteNum = seconds % 3600 / 60;
hourNum = seconds / 3600;
if (secondNum<10)
{
secstr = "0"+secondNum.ToString();
}
else
{
secstr = secondNum.ToString();
}
if (miniuteNum < 10)
{
minstr = "0" + miniuteNum.ToString();
}
else
{
minstr = miniuteNum.ToString();
}
if (hourNum < 10)
{
hourstr = "0" + hourNum.ToString();
}
else
{
hourstr = hourNum.ToString();
}
timer.text = hourstr + ":"+ minstr+":" +secstr;
}
}
}