本篇實現一個球體在固定區域移動撞擊Cube的游戲。
首先有1個Plane當作地面,1個Sphere當作球體,4個Cube當作牆,12個Cube當作被撞擊物體,另外還有球體的撞擊計算,在撞擊的過程適時顯示撞擊的球體數,12個Cube被撞擊后提示游戲結束。
創建項目,創建背景和球
創建一個項目,名稱為"MyRollBall",選擇項目所在文件,選擇"3D"項,點擊"Create project"。
點擊"File"菜單下的"Save Scene",在"MyRollBall"項目下的"Asserts"中創建一個自定義文件夾,名稱是"_MyScene",然后把保存的Scene命名為"MiniGame",並保存到"_MyScene"文件夾中。創建完后,在"Project"窗口下的文件結構如下:
依次點擊"GameObject"菜單下的"3D object","Plane",並在"Hierarchy"窗口中重命名為"Ground"。
點擊"Hierarchy"窗口中的"Ground",在"Scene"窗口中,Ground自動調整到"Scene"窗口的中心;在"Inspector"窗口的"Transform"中有一個"Reset"按鈕,點擊它,會把這里的Ground恢復到初始狀態;點擊"Edit"菜單下的"Frame Selected"會看到"Scene"窗口的整個畫面。
此時,"Scene"窗口的背景呈網格狀,這里需要隱藏網格。點擊"Scene"窗口"Gizmos"下拉項,把"Show Grid"的勾選去掉。
改變Ground的縮放比例,可以通過如下3種方式的一種來做:
1、點擊"Hirarchy"窗口中的Ground,按快捷鍵R,通過拖動"Scene"窗口中Ground的x,z軸來實現。
2、點擊"Hirarchy"窗口中的Ground,無需按哪個視圖快捷鍵,把鼠標移上"Inspector"窗口中,"Transform"下的"Scale"中的"X"字母或"Z"字母上,通過鼠標的左右滑動來改變縮放。
3、直接修改"Inspector"窗口中,"Transform"下的"Scale"中"X"和"Z"的屬性值。
注意:這里的Ground,即類型為"plane"的GameObject,沿y軸方向正向調整不會影響Ground的可見性,一旦拖動Y軸,讓Y軸對應的值為負值,Ground隨即不可見。這里給我們的啟示是:如果一個GameObject不可見,我們可以調整該GameObject的Y值,來使其可見。
現在再增加一個球體。在"GameObject"菜單欄的"3D Object"中選擇"Sphere",在"Hierarchy"窗口為Sphere重命名為"Player"。
在保證"Hierarchy"窗口為Sphere為選中狀態下,點擊"Edit"菜單下的"Frame Selected",Sphere在Scene窗口中出現在焦點位置,並呈選中狀態。
但是,我們發現球體的位置不太對,所以要調整球體的位置。拖動"Scene"窗口中Sphere的y軸,使其往上移動,讓整個球體在水平面之上。當然調整"Inspector"中的相關屬性也是可以的。
在"Project"下的"Asserts"中添加名稱為"Materials"的Folder。
選中"Mateirals"這個Folder,右鍵,依次選擇"Create","Material",這樣在"Mateirals"這個Folder中添加了一個名稱為"New Mateiral"的Material,並重命名為"Background"。
修改名稱為"Background"的"Inspector"窗口中的"Albedo"項,修改RGB屬性值為"0,32,64",可以在"Inspector"窗口的最下方預覽到效果。接着拖動這里的"Background"到"Scene"窗口的"Ground"上面,"Ground"因此有了Material。
點擊"Hierarchy"窗口下的"Directional Light",修改"Inspector"窗口中"Rotation"的"Y"為60。
移動球
在"Hierarchy"窗口中選擇名稱為"Player"的GameObject。
為了能夠讓名稱為"Player"的GameObject運動,需要為其添加"RigidBody"。
依次選擇"Component"菜單、"Physics"、"RigidBody",之后,在"Inspector"窗口多了一個"Rigidbody"組件。當然,為GameObject添加組件Compnenet的方式不止這一種,可以點擊"Inspector"窗口的"Add Component"按鈕。還可以在"Inspector"窗口中調整各個組件的順序。還可以折疊或展開各個組件面板。
選中"Project"下的"Asserts",添加一個"Scripts"文件夾。
再次選中"Hierarch"中的"Player",在其對應的"Inspector"窗口中點擊"Add Component"按鈕,點擊"New Script",命名為"PlayerController"。按這種方式添加的腳本自動附加到GameObject上了。而在"Asserts"下也多了一個名稱為"PlayerController"的腳本,為了把文件夾組織得更好,把該腳本拖入剛創建的"Scripts"文件夾。
雙擊腳本,在Visutal Studio中打開,編輯如下:
using UnityEngine;using System.Collections;public class PlayerController : MonoBehaviour{public float speed;private Rigidbody rb;void Start (){rb = GetComponent<Rigidbody>();}void FixedUpdate(){float moveHorizontal = Input.GetAxis("Horizontal");float moveVertical = Input.GetAxis("Vertical");Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);rb.AddForce(movement * speed);}// Update is called once per framevoid Update () {}}
可以在官網查看到所有的API:http://docs.unity3d.com/ScriptReference
再次點擊"Hirarchy"下的"Player",在其對應的"Inspector"窗口下的"Player Controller"這個腳本中,調整Speed的屬性值,設置為100。
運行。
按動鍵盤方向鍵,球以某種速度移動起來。
移動Camera
現在想把Camera附加到球體上。
首先設置Camera的位置。
在MainCamera對應的"Inspector"窗口中,在"Transform"下,調整"Position"的x,y,z分別為"0,10,-10",調整"Rotation"的x,y,z分別為"45,0,0",再在"Hierarchy"窗口中把"Main Camera"拖動到"Player"上,使其成為"Player"的一個子GameObject。這意味着當球體移動的時候,Camera也會跟着移動。
再次運行,這次看到球體移動非常快,這是因為Camera的位置相對於球體變化了。
在"Hierarch"窗口中,把"Main Camera"移動出"Player",不要讓其成為球體的子GameObject。
為"Main Camera"添加一個名稱為"CameraController"的腳本,編輯如下:
using UnityEngine;using System.Collections;public class CameraController : MonoBehaviour {//說明這個Camera指向於某一個Gameobject,在這里是球體public GameObject player;//Camera的偏移量private Vector3 offset;void Start(){//Camera的位置-球體的位置offset = transform.position - player.transform.position;}void LateUpdate(){//讓Camera根據球體的位置獲得一個新位置transform.position = player.transform.position + offset;}}
好,現在要把球體賦值給Camera。先打開"Main Camera"對應的"Inspector"窗口,然后拖動"Hierarchy"窗口下的名稱為"Player"的球體到"Inspector"中"Camera Controller"中"Player"這個屬性框上。
運行,這時,球在運動的時候有了一個很好的Camera角度。
設置球體運動區域
為了放置球體在移動過程中掉落,我們需要設置球體的運行區域。
創建一個空的"Game Object",並重命名為"Walls",並把之設置為默認值。
創建一個"Cube"類型的"Game Object",並重命名為"West Wall",並把之設置為默認值,拖動使其成為空"Game Object"的子項。
現在,"Scene"窗口中呈現出如下的位置關系。
這時需要調整Cube的位置,依次創建4個Cube,從4個方向擋住球體。
再次運行,球體被牢牢困在4個cube中間。
創建被球體撞擊的物體
創建一個Cube類型的GameObject,重命名為"Pickup",設置其默認值,點擊"Edit"菜單中的"Frame Selected"使其成為"Scene"窗口的焦點。
按如下設置"Pickup"的"Transform"。
現在想為其增加旋轉效果。為其專門創建一個名稱為"Rotator的腳本"。
using UnityEngine;using System.Collections;public class Rotator : MonoBehaviour {// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {transform.Rotate(new Vector3(15, 30, 45) * Time.deltaTime);}}
運行,"Pickup"會不停地旋轉。
在"Project"窗口中,在"Asserts"下創建"Prefabs"文件夾。
把"Hierarchy"中的"Pickup"拖動到"Prefabs"文件夾中。
創建一個空的GameObject,重命名為"Pickups",設置默認值。
把"Asserts"中"Prefabs"中的"Pickup"拖動到"Pickups"中,作為子GameObject。
選中"Hierarchy"窗口中的"Pickup",選擇左上角的"Local"模式,拖動"Pickup"到一個合適的位置。
復制"Pickup"12個,圍成一個圈。
在"Project"窗口中的"Material"文件夾中再復制一個,重命名為"Pickup",改變其顏色為黃色。
把其拖動到"Scene"窗口中的各個"Pickup",這時,所有的"Pickup"呈現為黃色。
撞擊物體
修改腳本"PlayerController"。
using UnityEngine;using System.Collections;public class PlayerController : MonoBehaviour{public float speed;private Rigidbody rb;void Start (){rb = GetComponent<Rigidbody>();}void FixedUpdate(){float moveHorizontal = Input.GetAxis("Horizontal");float moveVertical = Input.GetAxis("Vertical");Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);rb.AddForce(movement * speed);}//Collider表示被球體碰撞的其它物體void OnTriggerEnter(Collider other){if (other.gameObject.CompareTag("Pick Up")){other.gameObject.SetActive(false);}}// Update is called once per framevoid Update () {}}
回到Unity界面,選擇"Project"界面上"Prefabs"文件夾內的"Pickup",在"Inspector"窗口加添加"Pick Up"標簽。
運行,控制鍵盤方向鍵,當物體碰撞到Cube上的時候,Cube沒有消失。這不是我們所期望的。
回到Unity界面,選擇"Project"界面上"Prefabs"文件夾內的"Pickup",在"Inspector"窗口,在"Box Collider"中,勾選"Is Trigger"。
運行,控制鍵盤方向鍵,當物體碰撞到Cube上的時候,Cube消失。這正是我們所期望的。
所有的帶Rigid Body的Game Object被Unity理解為dynamic,不帶Rigid Body的Game Object被Unity理解成為static。如果沒有把Game Object附加Rigid Body的話,Unity在每一幀都會統計這些static Game Object,這非常消耗資源。所以,我們應當為Game Object附加Rigid Body,讓其變成dynamic。static是不可以移動的,而dynamic是可以移動的。
回到Unity界面,選擇"Project"界面上"Prefabs"文件夾內的"Pickup",在"Inspector"窗口,點擊"Add Component"按鈕,為其添加Rigid Body組件。
再次運行,發現所有的Cube消失了,為什么?
回到Unity界面,選擇"Project"界面上"Prefabs"文件夾內的"Pickup",在"Inspector"窗口,把"Rigid Body"中"Use Gravity"的勾選去掉。
再次運行,正常運行。
顯示分數
在"Hierarch"窗口中添加Text,Text作為Canvas的子Game object出現,並重命名為"Counter Text"。選擇Text,改變其字體顏色為白色,同時按住"alt"+"shift"鍵,改變Text的位置。
在"Hierarch"窗口中添加Text,Text作為Canvas的子Game object出現,並重命名為"Win Text"。選擇Text,改變其字體顏色為白色。
修改"PlayerController"腳本。
using UnityEngine;using System.Collections;using UnityEngine.UI;public class PlayerController : MonoBehaviour{public float speed;public Text countText;public Text winText;private Rigidbody rb;private int count;void Start(){rb = GetComponent<Rigidbody>();count = 0;SetCountText();winText.text = "";}void FixedUpdate(){float moveHorizontal = Input.GetAxis("Horizontal");float moveVertical = Input.GetAxis("Vertical");Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);rb.AddForce(movement * speed);}void OnTriggerEnter(Collider other){if (other.gameObject.CompareTag("Pick Up")){other.gameObject.SetActive(false);count = count + 1;SetCountText();}}void SetCountText(){countText.text = "擊中了: " + count.ToString() + "個";if (count >= 12){winText.text = "成功!";}}}
把"Hierarchy"窗口中,"Canvas"下的Text拖拽到"Player"球體對應的"Inspector"窗口內的"Counter Text"和"Win Text"屬性值框上。
Build游戲
選擇"File"菜單下的"Build Settings"。
點擊"Add Current"按鈕,把當前的"Scene"添加進來。
點擊"Build"按鈕。保存.exe文件保存到某個位置。
運行可執行文件,即看到與Unity軟件中一樣的效果。
參考資料:https://unity3d.com/learn/tutorials/projects/roll-a-ball/moving-the-camera