iOS Unity3D遊戲引擎入門③

歡迎來到第三部分,這是Unity 3D for iOS初級系列教程的最後一個部分!
在這個系列的第一部分,你參觀了基本的Unity工具,建立了帶有一個簡單角色控制機制的遊戲,而且學習瞭如何部署你的項目到iOS上。javascript

而後在這個系列的第二部分,你加強了你英勇的小方塊的移動,而且給這個世界帶來一些生命,它擁有了天空,草地和一個起伏的地形。java

在第三部分,也是最後一部分,你將要添加遊戲玩法到項目中。替代簡單的繞着場景亂轉,你英勇的小方塊須要在一個給定的時間裏,衝刺穿過一個終點線。
要給你的角色一些挑戰,在方塊以z字路線通向終點的路上,障礙物會像雨點同樣落向方塊。一個倒計時的時鐘添加到劇本中。成功會伴隨歡呼 – 失敗則是震耳欲聾的沉默.:]
你也幾乎接近終點線了,因此記住 – 我行我素!(「Huey Lewis And The News」中的一首歌名)
ios

開始吧:看到盡頭了!

首先,保存Level_2場景做爲一個新的場景,命名爲Level_3. 你在這個教程的第三部分所作的全部修改都保存在這個新的場景中。
你會用兩個圓柱和一條鏈接它們的粗線來建立一條終點線,這樣玩家能夠清楚的看見目標的方向。這個終點線包括一個不可見的牆,它被用來當你英勇的小方塊穿過終點線的時候的觸發器。
選擇GameObjectCreate Empty來建立一個新的物件來表明終點線。這是一個父GameObject, 在它之下,你能夠添加圓柱,線和一堵牆。
經過Inspector面板,將這個物件重命名爲Finish Line,或者右擊這個物件,而後選擇Rename. 設置Transform Position到0,0,0.
要 建立第一個圓柱,選擇GameObjectCreate OtherCylinder。重命名它爲Post1.設置Transform Scale爲1,3,1. 設置Transform Position爲-10,0,20,把它放在玩家的前面靠左邊。用Move工具,調整y位置,讓圓柱型物件的底部比地面略微高一些。編程

提示:從z軸視角觀察場景會幫助你方便的作這樣的調整。數組


拖動Post1 GameObject,而後把它放到Finish Line GameObject下面,設置後者做爲Post1的父對象。

要建立第二個圓柱,選中Post1,右擊而後選擇Copy. 再次右擊而後選擇Paste. 從Post1到Post2重命名新的GameObject. 使用Move工具調整新座標,讓這個圓柱到玩家的右側。編輯器

提示:從y軸觀察場景(從上面),會對你的調整有幫助。另外一個可選擇的方式是,設置Transform x position到10,也應該達到這個目的。ide

下一步,建立牆來幫助你監測當終點線被穿過的時候。選擇GameObjectCreate OtherCube,而後重命名它爲Goal.設置
Transform Scale爲24,10, 0.5.設置初始的Transform Position爲0,2,0

移動這堵牆到兩個圓柱後面,若是你須要,調整x縮放的值來讓這堵牆從一個圓柱擴展到另外一個圓柱。

讓這堵牆仍然被選中,打開InspectorBox Collider組件,而後勾選Is Trigger的值。不要勾選Mesh Renderer component讓這堵牆不可見。

拖動Goal GameObject,而後把它放置在Finish Line GameObject的下面,讓Finish Line GameObject做爲父物件。
函數

連點成線

下一步,你會建立一條鏈接圓柱的線,讓玩家能夠清楚的看見終點線。你將要經過腳本從一個圓柱到另外一個圓柱畫一條線來完成這個動做。
選擇AssetCreateJavaScript來建立一個新的腳本,而後命名它爲FinishLineRender.在項目視圖裏經過雙擊打開這個腳本。刪除自動生成的函數,而後添加下面的代碼:工具

// The finish line posts
var post1 : Transform;
var post2 : Transform;
var lineColor : Color = Color.green;
function Start () {
    // Set the visual for the finish line posts
    var lineRenderer : LineRenderer = gameObject.AddComponent(LineRenderer);
    lineRenderer.SetPosition(0, post1.position);
    lineRenderer.SetPosition(1, post2.position);
    lineRenderer.material = new Material (Shader.Find("Particles/Additive"));
    lineRenderer.SetColors(lineColor, lineColor);
}

LineRenderer類讓你在3D空間畫一條線。給出點的陣列,你可使用Line Renderer組件(ComponentsEffectsLine Renderer)來畫直線。
你也能夠添加Line Renderer到Finish Line對象下,而後爲Post1和Post2硬編碼座標位置,可是經過代碼建立一個Line Renderer是至關容易的。就像你這裏作的。
你在Start()函數裏畫了這根線,由於你僅僅須要發生一次。首先你添加LineRenderer腳本界面組件,而後你設置這條線的第一個和第二個點到捆綁到兩個圓柱的輸入變量的值。你設置renderer的材質。
最後你設置從起始點到結束點線的顏色。這個color變量是公共的,因此你能夠改變它。
關聯這個FinishLineRender腳本組件到Finish Line GameObject上。post

提示:你能夠經過選擇Finish Line物件,而後在Inspector點擊Add Compoment來添加這個腳本。這會彈出一個搜索框 – 簡單的輸入「FinishLineRender」單詞的前面幾個字母,而後它會顯示你要的腳本。


分別分配Post1和Post2 GameObject到Post 1和Post 2變量上。

在Unity編輯器中預覽這個遊戲。你應該看見兩個目標圓柱和一條綠線穿過它們表明終點線。中止遊戲。

下一步,你將會建立一個用來探測終點線被穿越事件的新的腳本,而後會關聯這個新的腳本到Goal GameObject上。要完成這個步驟,選擇AssetsCreateJavaScript,而後命名這個腳本爲FinishLineDetection.
打開這個新的腳本,而後刪除自動生成的函數。添加下面的代碼:

function OnTriggerEnter(other : Collider) {
 
    if (other.gameObject.tag == "Player") 
    { 
        Debug.Log("You made it!!!"); 
    } 
}
@script RequireComponent(Collider)

你調用OnTriggerEnter()函數,當其餘碰撞物進入這個GameObject. 這個遊戲對象須要被設置爲針對這個事件激活的觸發器(你已經爲這個Goal物件這樣作了)。
角色GameObject有一個Character Controller組件,帶有一個碰撞器。因此當玩家跑進Goal GameObject後,OnTriggerEnter()事件會被觸發。
在你的代碼裏,你檢查若是進入Goal的GameObject有一個標籤命名爲」Player」。若是屬於這種狀況,這個英勇的小方塊已經穿過了終點線。
關聯這個FinishLineDetection腳本到Goal GameObject上。

提示:在Hierarchy視圖中,選中Goal物件,你能夠從項目視圖中拖動FinishLineDetection腳本到InspectorAdd Component按鈕來關聯這個腳本到GameObject上。

在你標記這個角色以前,給了這個角色GameObject一個普通,老套的「方塊」名字。要保持事情的一致性,重命名這個方塊GameObject到Player.

如今,添加一個標籤到這個角色物件上,讓它能夠完成終點線的監測邏輯。在玩家的Inspector中,下拉Tag選擇器,而後選擇Player.


Player是預先構建的可用的標籤之一。之後,你也能夠建立你本身的標籤來幫助識別遊戲中的全部其餘的敵人。
點擊Play並移動英勇的小方塊穿過目標線。你應該看見「You made it!!!」這條日誌信息,讓你知道你的角色穿過了終點線。

是的,英勇的小方塊能夠到達目標線,而且贏得這個遊戲,可是你不能讓它太容易了。你應該提升兩級的複雜性到這個遊戲裏:一個基於時間的挑戰和障礙物。首先讓咱們添加障礙物。

建立發射器

建立一個空的GameObject,而後把它添加到場景中。命名它爲Launcher. 這個表明來自邪惡阻擋帝國的發射器發射一些障礙物來阻止英勇的小方塊前進。
使用Move工具,在角色和終點線的z軸方向之間放置一個launcher對象,高於玩家。你能夠設置transform位置爲0,12,8做爲起始位置,若是有必要能夠微調。

發射器存在的主要做用是發射障礙物,因此你須要給它一些能夠發射的東東。
在Unity中一般建立彈藥的方式是,經過設計一個GameObject,而後轉換爲一個能夠在場景中實例化的預製件。你將要建立一個障礙物GameObject,將它轉變爲預製件,而後讓Launcher負責發射障礙物到倒黴的角色上。

建立障礙物

建立一個方塊GameObject,而後命名它爲Obstacle. 設置Transform Scale爲2,2,2,所以它要比玩家大一些而且更加嚇人一些。這些方塊走向了邪惡的一邊。:]
給 障礙物一個有趣的外觀以區別於默認的灰色。要與示例比配,首先從Character Controller包導入一個材質:選擇AssetsImport PackageCharacter Controller,而後選擇constructor_done材質和下圖顯示的相關的紋理,最後點擊Import

新的材質應該出如今你的項目視圖中。

選擇Obstacle GameObject.經過修改InspectorMesh RendererMaterialsElement 0屬性來改變渲染的材料。點擊這個屬性邊上的原點,會彈出 Select Material對話框。

選擇你剛纔導入的constructor_done材質。關閉Select Material對話框。

如今你必須標註Obstacle GameObject,這樣後面當一個新的遊戲開始的時候你能夠清除場景中的Obstacle實例。
爲了這個目的,建立一個新的標籤名叫Enemy. 點擊InspectorTagAdd Tag. 標籤管理器會出如今面板的右側。經過點擊Tags標籤邊上的三角展開標籤數組。修改Element 0的值從0到Enemy。

選擇Obstacle GameObject,而後用新的Enemy標籤來標記這個物件。

當Obstacle被實例化的時候,你將要添加的代碼但願有一個關聯到障礙物上的是一個剛體組件。經過添加一個剛體來完成這步。選擇ComponentPhysicsRigidbody(Obstacle仍然被選中):

在項目視圖中點擊Asset文件夾。經過選擇AssetsCreatePrefab建立一個預製件。項目視圖顯示一個空的預製件。命名它爲Obstacle.

注意:若是你有比上面截屏更大的資源圖標,而且想知道如何獲得資源項的列表視圖,簡單的方式是向左滑動滑塊下面的資源列表.:]

拖動Obstacle GameObject到新的預製件上。

預製件改爲了藍顏色來指示他已經被賦值。
如今你已經建立了這個預製件做爲能夠複用的資源。在場景中你再也不須要它。launcher會接管實例化Obstacle實例的任務,當須要的時候。在Hierarchy視圖中,選擇Obstacle GameObject, 右擊而後選擇Delete.

釋放海怪…錯誤,障礙

下一步,經過腳本建立邏輯來完成發射障礙物來這個過程。
建立一個新的腳本資源,而後命名它爲ObstacleLauncher.

提示:你能夠在項目視圖中點擊右鍵,而後選擇CreateJavaScript來建立一個腳本。

打開這個新的腳本,而後用下面的代碼替換自動生成的函數:

var projectile : Rigidbody;
var speed = 5;
var maxObstacles = 2;
var launchInterval : float = 5.0;
var target : Transform;
private var nextLaunch : float = 0.0;
private var numObstaclesLaunched = 0;
function Start () {
    if (target == null) {
        // Find the player transform
        target = GameObject.FindGameObjectWithTag("Player").transform;
    }
}
function Update () {
    if ((numObstaclesLaunched < maxObstacles) && (Time.time > nextLaunch)) {
        // Set up the next launch time
        nextLaunch = Time.time + launchInterval;
 
        // Set up for launch direction
        var hit : RaycastHit;
        var ray : Ray;
        var hitDistance : float;
 
        // Instantiate the projectile
        var instantiatedProjectile : Rigidbody = Instantiate(projectile, transform.position, transform.rotation);
 
        // Simple block, try to get in front of the player
        instantiatedProjectile.velocity = target.TransformDirection(Vector3.forward * speed);     
 
        // Increment the launch count
        numObstaclesLaunched++;   
    }
}

這個發射器被編程,用來在角色的前面發射必定數量的障礙物。它所以須要一個表明角色的輸入,當分配GameObject到腳本的時候,你可使用編輯器經過拖動GameObject到腳本的變量上來完成這步。Start()函數代碼展現了完成這步的另外一種方式。
在Start()中,一個看看那裏是否沒有目標被賦值的檢查。若是沒有目標被找到,代碼查詢一個帶有Player標籤的GameObject,而後把這個GameObject賦值到目標變量上。
GameObject.FindGameObjectWithTag() 函數調用是典型的花開銷的調用,由於你須要遍歷全部的GameObject.因此你應該想在Start()中調用(它只會被調用一次),而避免把它放到, 也就是說,Update()中(它會被調用屢次)。
在代碼中, Update()首先檢查發射器是否已經發射容許發射的最大數量的障礙物。若是不是,它也要檢查一個設置的時間間隔是否過了。這步是用來避免在一個較短的時間內發射太多的障礙物。
若是是時候發射另外一個障礙物了,那麼Obstacle預製件根據發射器的位置和旋轉角度被實例化。這個實例化的障礙物而後被已鎖定角色前進的方向發射,所以恰好落在角色的前面。
現 在保存代碼,而後舒展一下筋骨。首先,關聯這個ObstacleLauncher腳本到Launcher GameObject. 分配Obstacle預製件到腳本的projectile變量上(你能夠從資源列表中拖動預製件到變量上)。分配Player GameObject到腳本的target變量上.

在Unity編輯器中試玩這個遊戲,而且檢查當英勇的小方塊移動的時候在它前面有被髮射的障礙物。調整發射器的位置,這樣可讓被髮射的障礙物在玩家和終點線之間。你也能夠經過在z軸遠離玩家的方向,移動Finish Line GameObject來作出同樣的調整。

提示:你能夠設置Transform位置到 0,0,2. 當你移動Finish Line物件的時候,子物件也會跟隨,也就是一個父子關係或羣組關係的GameObject的做用.


你已經完成了遊戲的大部分功能。下一步用一個任務控制腳原本把全部的東西整合在一塊兒,顯示遊戲的計時器,協調遊戲的玩法,和重置場景來開始一個新的遊戲。

倒計數

建立一個新的腳本資源,並命名它爲GameController.打開這個腳本,刪除預先添加的函數,而後添加下面的代碼:

static var gameRunning : boolean = true;
var gameTimeAllowed : float = 20.0;
private var gameMessageLabel = "";
private var gameMessageDisplay : Rect;
private var timedOut : boolean = false;
private var gameTimeRemaining : float = gameTimeAllowed;
function Awake() {
    gameMessageDisplay = Rect(10, 10, Screen.width - 20, 40);
}
function OnGUI() { 
    GUI.color = Color.yellow;
    GUI.backgroundColor = Color.black;
 
    var text : String = ""; 
    if (timedOut) {
        gameMessageLabel = "Time's up!!";
    } else {
        text = String.Format( "{0:00}:{1:00}", parseInt( gameTimeRemaining / 60.0 ), parseInt( gameTimeRemaining % 60.0 ) );
        gameMessageLabel = "Time left: " + text;
    }
    GUI.Box(gameMessageDisplay, gameMessageLabel);    
}
function Update() { 
    if (!gameRunning)
        return; 
 
    // Keep track of time and display a countdown
    gameTimeRemaining -= Time.deltaTime;
    if (gameTimeRemaining <= 0) {
        timedOut = true; 
        gameRunning = false;
    }
}
Unity提供GUI控件來讓添加文本標籤和按鈕功能更加容易。gameMessageDisplay變量控制顯示在那裏。這裏你創建了倒計時器,顯示在屏幕的頂部。
OnGUI()當一個例如鼠標按鈕的的事件發生的時候被調用,或者至少每幀調用一次。GUI.Box()使用你最初設定的尺寸和當前遊戲的消息建立一個a Box Control,這些消息包括倒計時信息,一個勝利的消息或一個失敗的消息。
gameTimeAllowed變量表明遊戲的時間,而且被設置爲20秒。這個gameTimeRemaining變量跟蹤當前剩餘的時間。它初始被設置爲gameTimeAllowed的值,而後在Update()中被Time.deltaTime減掉。
Time.deltaTime是上一幀花費的以秒計的時間。記住幀率會變化的,而且這個值也會變化,當gameTimeRemaining小於零,timedOut標記被設置爲true,而後玩家被顯示一個超時的消息。
這個代碼也設置一個gameRunning來跟蹤是否 - 你也猜到了 - 遊戲是否在運行。這對於中止倒計時邏輯頗有用,而且當遊戲不在運行的時候,也會用它來控制物件的行爲。
關聯這個腳本到你的主攝像頭對象:

試玩遊戲,而後混一下子直到時間用完,目的是測試倒計時顯示和失敗的情況。它很是不容易看的清,可是不要擔憂,你會立刻改變它。中止遊戲。

 

 

有時候你會贏,有時候你會輸

 

你應該顯示一個勝利的消息,當英勇的小方塊穿過終點線的時候,或者撞上不可見的牆 - 它渴望爲完成這個挑戰獲得一些鼓勵!這個消息包含他完成挑戰花費的時間。
你也應該讓玩家知道時間還剩下多少!
設置這些消息最好的地方是GameController腳本。可是,終點線監測的代碼在另一個腳本里: FinishLineDetection. 
有一個方法讓你能夠處理這個問題,在GameController中定義一個函數,讓FinishLineDetection腳原本調用,當角色穿過這天線的時候。這個函數而後經過OnGUI()函數出發但願顯示的消息。
添加兩個私有變量到GameController腳本。一個用來跟蹤完成挑戰的時間,另一個用來標記一次成功的行動(下面的代碼能夠添加到存在的私有變量以後):
private var missionCompleted : boolean = false;
private var missionCompleteTime : float = gameTimeAllowed;
而後添加下面的代碼到GameController腳本的最後面:
function MissionComplete() { 
    if (!gameRunning)
        return;
 
    missionCompleted = true; 
    gameRunning = false;
 
    missionCompleteTime =  gameTimeAllowed - gameTimeRemaining;
}
MissionComplete()檢查遊戲是否正在運行。若是它正在運行,它設置missionCompleted標記爲true,而後gameRunning標誌爲false. 完成遊戲的時間而後被保存下來。
如今修改OnGUI(),而且添加勝利的狀況(以下面顯示的)來顯示它完成的時間消息。新的代碼就放在var text : String = 「」這行後面,而且改變現有的if條件:
    if (missionCompleted) {
        text = String.Format( "{0:00}:{1:00}", parseInt( missionCompleteTime / 60.0 ), parseInt( missionCompleteTime % 60.0 ) );
        gameMessageLabel = "Mission completed in: " + text;
    } else if (timedOut) {
        gameMessageLabel = "Time's up!!";
        ...
切換到FinishLineDetection腳本,而後修改根據下面部分來修改(新增的部分用註釋標記了):
#pragma strict
var gameControllerScript : GameController; // 1: new
function OnTriggerEnter(other : Collider) {
 
    if (other.gameObject.tag == "Player") 
    { 
        Debug.Log("You made it!!!"); 
        gameControllerScript.MissionComplete(); // 2: new
    } 
}
@script RequireComponent(Collider)
新的代碼被數字標出,完成下面的事情:
  1. 定義一個公共的變量來指向GameController腳本。你立刻會給它賦值。
  2. 在GameController腳本中調用MissionComplete()來出發勝利的狀況。
 

要分配gameControllerScript變量,選擇Goal GameObject,而後選擇InspectorFinish Line Detection,而後點擊Game Controller Script邊上的原點。選擇Main Camera GameObject,最後關閉對話框。

 

試玩遊戲,衝向終點線,避開那些邪惡的阻擋物。當你在規定的時間內完成的時候,檢查是否顯示正確的消息。

中止遊戲,而後再次點擊Play。測試失敗的狀況。確保那個邏輯仍然能夠工做。

改變顯示的字體

你也許注意到,特別是若是你用Unity Remote或者你的iOS設備來測試這個遊戲,顯示遊戲消息的字體很是的小。這是一個很好的機會來學習如何導入字體到Unity中。
在相似這樣的網站http://dafont.com,這裏有豐富的字體你能夠獲取到.這裏例子中你將要用到的是免費的用於構造<a href="http://www.dafont.com/transformers-movie.font">變形金剛的字體</a>,他最初用在變形金剛電影裏!也許你的小方塊和障礙物是這個電影裏的一個隱藏的角色.:]
我添加上面這個字體(和一些你將會用到的其餘的資源)到Resources.zip文件,你能夠從<a href="http://cdn1.raywenderlich.com/downloads/DashAndZag_Resources.zip">這裏</a>下載。
下載這個資源包,而後解壓它的內容。找到字體文件而後拖動這個Transformers Movie.ttf到你項目視圖的Assets文件夾下面,導入進去。在項目視圖中選擇Transformers Movie資源。用Inspector查看導入的設置。改變字體大小的設置到36.點擊Apply.

你已經導入你的自定義的字體,而且在你的項目中準備好使用它們了。
打開 GameController腳原本改變消息的字體。定義一個公共變量來設置字體:
var gameMessageFont : Font;
經過改變OnGUI()來改變用於顯示標籤的字體,就像下面展現的那樣:
function OnGUI() { 
    GUI.skin.font = gameMessageFont;
    GUI.color = Color.yellow;
...
你經過分配gameMessageFont公共變量爲GUI.skin.font來改變字體。 
如今選擇主攝像頭GameObject. 經過拖拽字體資源到gameMessageFont變量來分配gameMessageFont爲你新導入的字體。

預覽遊戲,並檢查使用新字體顯示的消息。

嗯,好些了!

它老是在計時 !

下一步建立一個遊戲中的按鈕來控制遊戲的開始和容許玩家在勝利和失敗後從新開始遊戲。當遊戲沒有運行的時候你會顯示這個按鈕。回憶你定義過一個gameRunning標誌,用它你能夠控制這個按鈕是否顯示。 
要建立播放按鈕和相關的功能。你必須修改GameController腳本。首先定義一個私有的變量來控制播放按鈕的文字:
private var playButtonText = "Play";
而後添加一個新的函數叫作startGame()來構建一個新的遊戲:
function startGame() {
    // Reset if starting a new game
    gameTimeRemaining = gameTimeAllowed; 
    timedOut = false;
    missionCompleted = false;
 
    // Change button text after the initial run
    playButtonText = "Play Again";
 
    // Kick off the game
    gameRunning = true;
}
如今修改OnGUI(),經過添加下面的代碼到OnGUI()底部(在全部存在的代碼後面),當遊戲沒有運行的時候來顯示這個按鈕:
    // The menu button
    if (!gameRunning) {
        var xPos = Screen.width / 2 - 100;
        var yPos = Screen.height / 2 + 100;
        if( GUI.Button( new Rect( xPos, yPos, 200, 50 ), playButtonText ) ) {
            startGame();
        }
    }
最後,設置gameRunning標誌爲false.只要修改變量存在的那行,調換初始值從true到false:
static var gameRunning : boolean = false;
OnGUI使用GUI.Button()函數來放置一個按鈕。按鈕的文字是一個變量,因此初始它設置爲"Play",每次從新開始前是"Play Again" 
GUI.Button()封裝在一個if語句中。若是按鈕被點擊,返回true. 當用戶點擊按鈕,你開始這個遊戲。startGame()首先初始化遊戲,改變play按鈕的文字,最後設置gameRunning標記爲true.
在Unity編輯器裏預覽遊戲。檢查play按鈕初始狀態是可見的,當你點擊它後隱藏掉了。也覈對當一次快跑結束後,play按鈕再次出現,並且文字從"Play"變成了"Play Again".注意第一次以後,每次你點擊play按鈕,時間會被重置,倒計時器會從新開始。
可是也注意到玩家能夠在play按鈕被點擊前就能夠移動。這是否是有一點煩人?不要讓你英勇的小方塊搶跑!
要處理這個細節,要使用gameRunning變量。這個變量是一個全局變量經過靜態前綴定義。添加下面的代碼到MoveAround腳本的Update()頭上:
   if (GameController != null &amp;&amp; !GameController.gameRunning)
       return;
你也應該不讓發射器,發射障礙物,當遊戲尚未開始的時候。添加下面的代碼到ObstacleLauncher腳本的Update()頭上:
   if (GameController != null &amp;&amp; !GameController.gameRunning)
       return;
試玩遊戲確認當遊戲沒有開始的時候,玩家不能移動,障礙物沒有被髮射。

每一個小方塊須要一個嶄新的開始

如今play按鈕工做正常了,你也許注意到及時一個新的遊戲開始,計時器被設置了,可是遊戲的其餘方面沒有被重置。
障礙物中止墜落,是由於它們可能到達發射的最大上限,可是它們也沒有消失。還有這個英勇的小方塊沒有回到它原來的位置。一個乾淨的重置讓遊戲有一個全新的開始,例如,障礙物被清除和從新加載,角色的位置被重置。
理想的方式來完成這個功能是發送一條消息到全部感興趣的部分來重置它們本身。英勇的小方塊將返回到它原始的位置,而發射器會從新裝填。
要作到這點一個方式是在腳本中定義一個reset函數,來重置行爲。GameObject.SendMessage()能夠調用這個reset函數,但願關聯GameObject組件(腳本)能夠處理這個函數調用。 
這裏是你要如何實現的代碼:
  1. 你要在MoveAround腳本中定義一個叫作resetGame()函數來重置玩家的位置到遊戲開始的初始位置。
  2. 你要在ObstacleLauncher腳本里定義一個叫作resetGame()函數來重置障礙物的數量到零。
  3. 你要循環遍歷給定的GameObject列表,包括player和發射器GameObject,調用 GameObject.SendMessage(「resetGame」, …)來調用這個reset.
  4. 你要在GameController添加劇置的邏輯,當用戶重置遊戲。
可是代碼比文字更有說服力。首先打開MoveAround添加下面的遍歷和函數:
var originalPosition : Vector3;
var originalRotation : Quaternion;
function Awake() {
    originalPosition = transform.position;
    originalRotation = transform.rotation;
}
function resetGame() {
    // Reset to original position
    transform.position = originalPosition;
    transform.rotation = originalRotation;
}
而後打開ObstacleLauncher腳本,而後添加這個新的函數:
function resetGame() {
    // Reset to original data
    numObstaclesLaunched = 0;
}
下一步打開GameController腳本,而後添加下面變量:var gameObjectsToReset : GameObject [];
上面這行定義了一個GameObject的數組,這是一個包含resetGame函數的GameObject數組,依此調用它們來完成一個個重置。
如今替換存在的startGame()函數用下面代碼(或者只要更新匹配的代碼):
function startGame() {
    // Reset if starting a new game
    gameTimeRemaining = gameTimeAllowed; 
    timedOut = false;
    missionCompleted = false;
 
    // Change button text after the initial run
    playButtonText = "Play Again";
 
    // Clean out any enemy objects
    var enemies = GameObject.FindGameObjectsWithTag("Enemy");
    for (var enemy : GameObject in enemies) {
        Destroy ( enemy);
    }
    // Call all game reset methods
    for (var gameObjectReceiver : GameObject in gameObjectsToReset) {
        gameObjectReceiver.SendMessage("resetGame", null, SendMessageOptions.DontRequireReceiver);
    }
 
    // Kick off the game
    gameRunning = true;
}
這段新的代碼經過查找全部標記爲Enemy標記的GameObejct來清除全部的敵對實例。Destroy()在敵對的GameObject上被調用。這會清除場景中全部的障礙物。
而後代碼處理gameObjectsToReset數組,發送每一個GameObject一條消息來調用resetGame()函數。它不是強制性的要求數組中的組件有實現resetGame()函數。你須要分配對象來處理。
如今選擇主攝像頭對象,而後注意公共變量Game Objects To Reset:

設置尺寸爲2.數組元素會擴展。分配Player GameObject到 元素0,而後Launcher GameObject到元素1.

試玩遊戲,覈對在一次勝利或失敗後,遊戲徹底重置了本身。覈對玩家位置重置到原始地方,全部障礙物被清除,並且大概遊戲從新開始後障礙物開始再次墜落。

相關文章
相關標籤/搜索