您好,登錄后才能下訂單哦!
Coroutine:協同程序(簡稱:協程),參考網絡給出以下兩個定義供參考。
1> 協同程序,即在主程序運行時同時開啟另一段邏輯處理,來協同當前程序的執行。換句話說,開啟協同程序就是開啟一個模擬線程。 [作者注: 不是真正的線程]
2> 是一種很古老的編程模型,以前的操作系統里進程調度里用到過,現在操作系統的進程調度都是根據時間片和優先級來進行輪換,以前是要程序自己來釋放cpu的控制權,一直不釋放一直也就占用著cpu,這種要求程序自己來進行調度的編程模型應該就叫“協程”。
語法:
function StartCoroutine (routine:IEnumerator) : Coroutine
function StartCoroutine (methodName:string, value : object = null) : Coroutine
function StopCoroutine (methodName:string) : void
function StopAllCoroutines () : void
示例:
void Start()
{
print("1: " + Time.time);
StartCoroutine(WaitAndPrint(2.0F));
print("3: " + Time.time);
}
IEnumerator WaitAndPrint(float waitTime)
{
yield return newWaitForSeconds(waitTime);
print("2: " +Time.time.ToString());
}
輸出結果:
1: 0
3: 0
2: 2.004061
Invoke:調用函數,指每隔多少時間執行一次某方法。
InvokeRepeating: 重復調用函數,指在給定時間后指定間隔時間后重復執行方法。
語法:
function Invoke (methodName: string, time :float) : void
functionInvokeRepeating (methodName :String,time : float, repeatRate : float) : void
function CancelInvoke () : void
function IsInvoking (methodName: string) :bool
示例:
private int _IntNumber = 0; //累加數字
void Start()
{
//this.Invoke("DisplayNum",1F); //只調用一次
this.InvokeRepeating("DisplayNum", 0F, 1F); //間隔1秒反復調用
}
//每隔一定時間,進行自增想加數字且輸出結果
void DisplayNum()
{
Debug.Log("自增數字: " + (++_IntNumber));
}
輸出結果:
自增數字:1
自增數字:2
自增數字:3
自增數字:4
自增數字:5
自增數字:6
(結果會無限循環下去...)
以上技術在Unity 實際編程過程中被大量應用,個人體會Invoke 與 InvokeRepeating 為 Coroutine 的簡化寫法,是按照事先定義好的固定時間間隔進行調用的編程模型。優點是結構與語法編寫簡單。Coroutine 則是更加完善,功能更加強大的編程模型。在處理需要制作多種間隔時間,從而達到一定功能的地方有良好的應用效果。以下是開發與教學過程中實際的應用場景舉例:
開發游戲倒計時案例。
(示例 1.1)
using UnityEngine;
using System.Collections;
public class GUIProgress_LevelOne : MonoBehaviour {
publicGUISkin projectWukongSkin; //項目皮膚
publicTexture2D TexGameOver_Falure; //游戲結束貼圖。
publicTexture2D TexNumberOne; //數字貼圖1
publicTexture2D TexNumberTwo;
publicTexture2D TexNumberThree;
//項目信息貼圖
publicTexture2D TexProjectLogo; //項目Logo
publicTexture2D TexRedDiamond; //紅寶石
privatebool _BoolIsDrawCountDownFlag = false; //繪制倒計時數字
private int_IntDrawNumber = 3; //繪制具體數字
void Start()
{
//啟動游戲倒計時
StartCoroutine(DrawGameStartCountDown());
}//Start_end
//游戲開始倒計時
IEnumeratorDrawGameStartCountDown()
{
//1秒的準備
yieldreturn new WaitForSeconds(1F);
//顯示數字3
_BoolIsDrawCountDownFlag = true;
_IntDrawNumber = 3;
yieldreturn new WaitForSeconds(1F); //停留1秒的查看時間
//空白時間
_BoolIsDrawCountDownFlag = false;
yieldreturn new WaitForSeconds(0.5F);
//顯示數字2
_BoolIsDrawCountDownFlag = true;
_IntDrawNumber = 2;
yieldreturn new WaitForSeconds(1F);
//空白時間
_BoolIsDrawCountDownFlag = false;
yieldreturn new WaitForSeconds(0.5F);
//顯示數字1
_BoolIsDrawCountDownFlag = true;
_IntDrawNumber = 1;
yieldreturn new WaitForSeconds(1F);
_BoolIsDrawCountDownFlag = false;
//開始游戲。
GlobalInfoManger.CurrentGameState = GameState.Playing;
}
void OnGUI()
{
GUI.skin = projectWukongSkin;
/* 顯示項目信息 */
//項目Logo
GUI.DrawTexture(new Rect(Screen.width / 2 - TexProjectLogo.width/2, 0,TexProjectLogo.width, TexProjectLogo.height), TexProjectLogo);
//紅寶石
GUI.DrawTexture(new Rect(0, 0,50,50), TexRedDiamond);
//紅寶石當前的數量
GUI.Label(newRect(50,0,100,100),GlobalInfoManger.IntRedDiamonds.ToString());
//顯示游戲時間
GUI.Label(new Rect(170, 0,150,80),"Time:");
//當前游戲的時間
GUI.Label(new Rect(300, 0, 100, 100),GlobalInfoManger.IntGameTime.ToString());
//繪制游戲不成功貼圖畫面
if(GlobalInfoManger.CurrentGameState==GameState.GameOver)
{
GUI.DrawTexture(new Rect(Screen.width / 2 - TexGameOver_Falure.width /2, Screen.height / 2 - TexGameOver_Falure.height / 2, TexGameOver_Falure.width,TexGameOver_Falure.height), TexGameOver_Falure);
}
#region繪制倒計時數字貼圖
//繪制倒計時數字貼圖
if(_BoolIsDrawCountDownFlag)
{
if(_IntDrawNumber == 3)
{
GUI.DrawTexture(new Rect(Screen.width / 2 - TexNumberThree.width / 2,Screen.height / 2 - TexNumberThree.height / 2, TexNumberThree.width,TexNumberThree.height), TexNumberThree);
}
else if (_IntDrawNumber == 2)
{
GUI.DrawTexture(new Rect(Screen.width / 2 - TexNumberTwo.width / 2,Screen.height / 2 - TexNumberTwo.height / 2, TexNumberTwo.width,TexNumberTwo.height), TexNumberTwo);
}
else if (_IntDrawNumber == 1)
{
GUI.DrawTexture(new Rect(Screen.width / 2 - TexNumberOne.width / 2,Screen.height / 2 - TexNumberOne.height / 2, TexNumberOne.width,TexNumberOne.height), TexNumberOne);
}
}
#endregion
}//OnGUI_end
}//Class_end
圖 1.1
示例 1.1 參考圖1.1進行理解,基本原理如下:
以上定義的協程方法 “DrawGameStartCountDown()” 主要是運用 “_BoolIsDrawCountDownFlag”與“_IntDrawNumber ” 這兩個字段對 OnGUI() 事件函數中“GUI.DrawTexture ” 繪制貼圖的時間間隔與繪制內容進行控制。
再舉一例:
開發游戲戰績數值統計案例。
(示例 1.2)
usingUnityEngine;
usingSystem.Collections;
public classGUI_CountResult : MonoBehaviour {
public GUISkin ProjectGUISkin; //項目皮膚
public Texture2D TexGameBackground; //游戲背景貼圖
public Texture2D TexRedDiamonds; //紅寶石貼圖
public Texture2D TexBlueDiamonds; //藍寶石貼圖
public string StrScenesName; //場景名稱。
public Texture2D TexRePlay; //"重玩"貼圖
private bool _boolRePlay = false; //是否重玩
private bool _boolExit = false; //是否退出
//開發動態文字顯示
private int _IntRunedTime = 0; //玩家跑過的時間。
private bool _BoolIsDisplayRunedTime =false; //是否顯示跑過的里程
private int _IntRedDiamondNum = 0; //玩家跑過的時間。
private bool _BoolIsDisplayRedDiamond =false; //是否顯示跑過的里程
void Start ()
{
//測試數值(等待刪除。)
//GlobalInfoManger.IntGameTime = 66;
//GlobalInfoManger.IntRedDiamonds = 88;
//開啟“動態控制顯示玩家跑過的里程(時間)”
StartCoroutine(DynamicDisplayPlayerRunLength());
//開啟“動態控制紅寶石數量統計”
StartCoroutine(DynamicDisplayRedDiamondNumber());
}//Start_end
//動態控制里程顯示
IEnumerator DynamicDisplayPlayerRunLength()
{
//等待GUI 與攝像機全部繪制完畢。
yield return new WaitForEndOfFrame();
_BoolIsDisplayRunedTime = true;
_IntRunedTime = 0;
yield return new WaitForSeconds(0.2F);
_BoolIsDisplayRunedTime = false;
while (_IntRunedTime <GlobalInfoManger.IntGameTime)
{
//不斷顯示
++_IntRunedTime;
_BoolIsDisplayRunedTime = true;
yield return newWaitForSeconds(0.03F);
_BoolIsDisplayRunedTime = false;
yield return new WaitForSeconds(0.01F);
}
_BoolIsDisplayRunedTime = true;
}
//動態控制紅寶石顯示
IEnumeratorDynamicDisplayRedDiamondNumber()
{
//等待GUI 與攝像機全部繪制完畢。
yield return new WaitForEndOfFrame();
_BoolIsDisplayRedDiamond = true;
_IntRedDiamondNum = 0;
yield return new WaitForSeconds(0.2F);
_BoolIsDisplayRedDiamond = false;
while (_IntRedDiamondNum <GlobalInfoManger.IntRedDiamonds)
{
//不斷顯示
++_IntRedDiamondNum;
_BoolIsDisplayRedDiamond = true;
yield return newWaitForSeconds(0.03F);
_BoolIsDisplayRedDiamond = false;
yield return newWaitForSeconds(0.01F);
}
_BoolIsDisplayRedDiamond = true;
}
void OnGUI()
{
GUI.skin=ProjectGUISkin;
//繪制游戲背景貼圖
GUI.DrawTexture(newRect(Screen.width/2-TexGameBackground.width/2,Screen.height/2-TexGameBackground.height/2,TexGameBackground.width,TexGameBackground.height),TexGameBackground);
//顯示統計玩家跑的里程
GUI.Label(new Rect(550, 250, 150, 200),"時間:");
if (_BoolIsDisplayRunedTime)
{
GUI.Label(new Rect(700, 250, 150,200), _IntRunedTime.ToString());
}
//顯示獲得的紅寶石的數量
GUI.DrawTexture(new Rect(550, 300, 50,50), TexRedDiamonds);
if(_BoolIsDisplayRedDiamond)
{
GUI.Label(new Rect(700, 300, 150,50),_IntRedDiamondNum.ToString());
}
//顯示獲得的藍寶石的數量(測試數據)
GUI.DrawTexture(new Rect(550, 350, 50,50), TexBlueDiamonds);
GUI.Label(new Rect(700, 350, 50, 50),GlobalInfoManger.IntRedDiamonds.ToString());
//顯示“重玩”,"退出"。
if (GUI.Button(new Rect((Screen.width /2 - TexRePlay.width / 2)-100, Screen.height / 2 - TexRePlay.height / 2+150,TexRePlay.width, TexRePlay.height), "",ProjectGUISkin.GetStyle("Btn_Replay")))
{
_boolRePlay = true;
}
else if (GUI.Button(newRect((Screen.width / 2 - TexRePlay.width / 2)+100, Screen.height / 2 - TexRePlay.height/ 2+150, TexRePlay.width, TexRePlay.height), "",ProjectGUISkin.GetStyle("Btn_Exit")))
{
_boolExit = true;
}
}//OnGUI_end
//邏輯處理。
void Update()
{
if(_boolRePlay)
{
//調用指定的場景。
GlobalInfoManger.IntGameTime =0; //時間清零
Application.LoadLevel(StrScenesName);
}
else if (_boolExit)
{
//退出游戲
Application.Quit();
}
}
}//Class_end
圖 1.2
示例 1.2 參考圖1.2進行理解,其基本原理與示例1.1基本相同,在這就不再贅述。
對于InvokeRepeating則在項目中運用的更多,請看如下示例代碼。
(示例 1.3)
usingUnityEngine;
usingSystem.Collections;
public classScenesManager_Level1 : MonoBehaviour {
public Transform TrnHero; //主人公位置信息
public string StrStartScenceName; //開始場景的名稱
//克隆道具
public GameObject Go_ScriptsObject; //腳本對象
public GameObjectGoCloneOriginal_Diamend; //克隆原型_紅寶石
public GameObjectGoCloneOriginal_Tree; //克隆原型_樹木
public GameObjectGo_CloneObj_RefPosion_Left; //克隆位置基準。
public GameObjectGo_CloneObj_RefPosion_Right;
private AudioSource _ASBGMusic; //背景音樂
private AudioSource[] _ASAudioEffect; //音頻數組
private Vector3_VecHeroPositionOfOriginal; //主人公原始位置
void Start ()
{
//游戲結束
GlobalInfoManger.CurrentGameState =GameState.Prepare;
//設置音頻
SetAudio();
//主人公位置初始值
_VecHeroPositionOfOriginal = TrnHero.transform.position;
//檢測狀態信息
InvokeRepeating("CheckHeroState",1F,1F);
//動態生成道具。(單次加載方式)
//DanymicCreateRedDiamond();
//分步加載方式
InvokeRepeating("DanymicCreateProperty",1F,1F);
}//Start_end
/// <summary>
/// 動態加載各種道具
/// </summary>
private void DanymicCreateProperty()
{
//加載紅寶石
if(GlobalInfoManger.IntGameTime==1)
{
this.CreateProperty(GoCloneOriginal_Diamend,15,30,100);
}
//第二次
if (GlobalInfoManger.IntGameTime ==15)
{
//加載寶石
this.CreateProperty(GoCloneOriginal_Diamend, 20, 30, 150);
//加載樹木
this.CreateProperty(GoCloneOriginal_Tree,5, 30, 100);
}
//第三次。
if (GlobalInfoManger.IntGameTime ==20)
{
//加載地刺
//加載寶石
this.CreateProperty(GoCloneOriginal_Diamend, 50, 30,650);
//加載樹木
this.CreateProperty(GoCloneOriginal_Tree,10,30, 600);
}
}//DanymicCreateProperty_end
/// <summary>
/// 創建道具
/// </summary>
/// <paramname="goCloneOriginal">克隆原型</param>
/// <paramname="intCloneNumber">克隆數量</param>
/// <paramname="intDestroyGOTime">銷毀時間</param>
/// <paramname="intAddingGameobjectLenth">克隆對象的距離</param>
void CreateProperty(GameObjectgoCloneOriginal,int intCloneNumber,int intDestroyGOTime,intintAddingGameobjectLenth)
{
/* 數據集合準備 */
System.Object[] ObjArray = newSystem.Object[8];
ObjArray[0] = goCloneOriginal; //克隆的原型
ObjArray[1] = intCloneNumber; //克隆的數量
ObjArray[2] = intDestroyGOTime; //克隆體銷毀的時間
//X 坐標最小數值
ObjArray[3] =Go_CloneObj_RefPosion_Left.transform.position.x;
//X 坐標最大數值
ObjArray[4] =Go_CloneObj_RefPosion_Right.transform.position.x;
//Y坐標
ObjArray[5] =Go_CloneObj_RefPosion_Left.transform.position.y;
//Z 坐標最小數值
ObjArray[6] =Go_CloneObj_RefPosion_Left.transform.position.z;
//Z 坐標最大數值
ObjArray[7] =Go_CloneObj_RefPosion_Left.transform.position.z + intAddingGameobjectLenth;
/* 調用動態克隆方法 */
Go_ScriptsObject.SendMessage("DynamicCreProperty", ObjArray,SendMessageOptions.DontRequireReceiver);
}
/// <summary>
/// 檢測主人公狀態信息
/// </summary>
void CheckHeroState()
{
//游戲時間自增
++GlobalInfoManger.IntGameTime;
//如果主人公Y軸出現較大的變化,判斷主人公掉下橋體,游戲結束
if (TrnHero.transform.position.y <(_VecHeroPositionOfOriginal.y-10))
{
GlobalInfoManger.CurrentGameState= GameState.GameOver;
}
//判斷游戲結束后,處理方式。
if (GlobalInfoManger.CurrentGameState== GameState.GameOver)
{
_ASBGMusic.Stop(); //關閉背景音樂
_ASAudioEffect[1].Play(); //播放GameOver 音頻
//3秒后返回開始場景
Invoke("ReturnStartScenes", 3F);
}
}
//設置音頻
void SetAudio()
{
//背景音樂音量大小判斷
_ASBGMusic =GameObject.Find("_AudiosManager/_AudioBGMusic").GetComponent<AudioSource>();
switch (GlobalInfoManger.ProVolumns)
{
case ProjectVlumns.None:
break;
case ProjectVlumns.NoneVolumns:
_ASBGMusic.volume = 0F;
break;
case ProjectVlumns.HalfVolumns:
_ASBGMusic.volume = 0.5F;
break;
case ProjectVlumns.FullVolumns:
_ASBGMusic.volume = 1F;
break;
default:
break;
}//switch_end
//音效處理
_ASAudioEffect =GameObject.Find("_AudiosManager/_AudioEffect").GetComponents<AudioSource>();
_ASAudioEffect[1].volume = 1F;
_ASAudioEffect[1].loop = false;
}
//返回開始開始場景
void ReturnStartScenes()
{
Application.LoadLevel(StrStartScenceName);
}
}//Class_end
示例 1.3 可以參考圖1.1進行理解,基本原理如下:
以上在Start() 事件函數中定義的“CheckHeroState()”[檢測主角的狀態信息]與“DanymicCreateRedDiamond()”[動態生成道具] 方法分別都是被InvokeRepeate 進行循環調用,按照一定的固定時間間隔。 這里在本應用場景中的以上兩個方法中由于不需要產生不固定的時間間隔,所以就不需要使用協程了。
最后提及一下Coroutine(協程)與InvokeRepeating(重復調用函數),在被腳本禁用的時候是不會自動停止調用的,需要手工編寫對應的停止調用函數進行停止,否則會出現很多問題。且還要注意調用與停止調用的時機問題,我會在下一篇博客中關于討論Unity 腳本的生命周期中進行討論,謝謝。
(跑酷游戲)源代碼下載鏈接:
http://pan.baidu.com/s/1sj8X3lV
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。