下面經過分析製做一個簡單的收集特定物體的滾球遊戲來入門unity,包括操做面板和C#腳本的編寫導入,建立Game Object和給Object添加組件等等。html
一 初始設置架構
在Assert下建立主場景MainScene。往場景中添加一3D Obj - 「平面」 Plane,rename 爲Ground,編輯器
建立玩家 Player 對象(Sphere),選中球以此點擊「Edit」->「Frame Select」或者快捷鍵「F」,可聚焦到當前所選的obj。設置0.5個unity單位讓球脫離地面。ide
新增Materials材質文件夾,給Ground對象設置顏色。設置Albedo(反射率,直接影響反射光照)的RGB爲(0,32,64),而後把「衣服」材質拖到Ground上。函數
二 移動玩家ui
玩家移動須要接收鍵盤輸入,同時碰到邊緣須要停下來,所以給玩家添加一物理剛體 - 「Rigibody」spa
(能夠經過up和down調整組件的順序).net
由於要接收鍵盤輸入,故給玩家添加一C#腳本,命名爲PlayerController3d
注意,經過組件的方式添加腳本會生成在項目根目錄下,咱們能夠新建一Scripts文件夾保持項目的組織架構的清晰,把相關的腳本都拖到這個腳本文件夾中。 本例中腳本代碼以下:code
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerController : MonoBehaviour { private Rigidbody rb; void Start() { rb = GetComponent<Rigidbody>(); } //目的是每一幀都檢測一下用戶的輸入,而後每一幀都把輸入應用到遊戲對象上 private void FixedUpdate() { //得到用戶輸入 float moveHorization = Input.GetAxis("Horizontal"); float moveVertical = Input.GetAxis("Vertical"); //注意y方向是上下移動,則這裏只需x,z Vector3 movement = new Vector3(moveHorization, 0.0f, moveVertical); rb.AddForce(movement); } }
每幀檢測有兩種方法:①Update:每一幀展現以前被調用;②Fixed Update:進行任何的物理計算以前被調用,物理代碼在這裏執行。 對剛體施加力的做用使球移動起來,是物理系統,則本例在Fixed Update裏添加代碼。
運行Play遊戲,發現有兩個問題:一是太慢;二是移動一會就脫離視野看不到了。
public class PlayerController : MonoBehaviour { //只有public變量纔會出現Inspector面板 public float speed; ... ... private void FixedUpdate() { ... ... rb.AddForce(movement* speed); } }
運行遊戲,能夠手動調節移動的速度了。
三 移動攝像機
上述的問題,顯然由於攝像機不會移動致使看到的視野頗有限,這就須要將攝像機和玩家角色綁定。 首先沿y軸向上95單位,再沿x軸旋轉45度,
而後把攝像機當作是玩家角色的子對象,這就是所謂的「第三人稱視角」。 但僅僅簡單綁定到玩家對象上,會發現攝像機的x,y,z值在瘋狂無規律變化,轉得眼花繚亂,顯然不正確。其實攝像機不須要隨着玩家對象一直翻滾,因此直接綁定是不正確的。 回想一下打CF的FTS遊戲時,能夠發現攝像頭和爆頭槍始終保持在一個相同的距離和角度的參數。 故給Camera添加腳本CameraController控制以下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class CameraController : MonoBehaviour { //跟隨對象 public GameObject player; private Vector3 offset; void Start () { //第一幀開始計算好攝像機和玩家角色對象的偏移 offset = transform.position - player.transform.position; } void LateUpdate () { //每幀保持恆定間隔 從而每幀顯示以前先移動到跟角色相關的新的位置 transform.position = player.transform.position + offset; } }
注意!:上述代碼每幀更新的方法最好使用LateUpdate。 LateUpdate和Update同樣都是每幀都會執行,但它執行在全部的東西都Update以後。這樣就能肯定玩家角色在這一幀內已經移動完成,緊接着的攝像機作的運算是最新的。
運行遊戲,發現遊戲是不會跟着動的?what! 別忘了把當前玩家即那個球拖動到player的變量賦值,正常,實現了第三人稱視角。
四 設置遊戲場地
這節要解決的問題主要有兩點,一是圍欄阻擋的添加,二是計分物的增長。建立一Empty Object,命名爲Wall,做爲父空對象。而後建立一Cube方格,命名爲WestWall,reset重置到原點。將WestWall做爲Wall的子對象。 快捷鍵F聚焦得下圖:
設置尺寸爲寬x:0.5,高y:2,長z:10,設置x位置爲-5。同理建立另外三面牆體的Game Object,
由於新建的Cube有Box Collider,則會和玩家剛體發生碰撞檢測,
五 建立收集物
新建一Cube,命名爲PickUp,同理重置reset位置。爲取消Player對象的視覺阻擋,可取消選擇Name屬性,實質是遊戲對象的Active勾選框,取消選擇會讓該遊戲對象在場景中不可見。
縮小並沿各個軸旋轉45度,而後添加腳本Rotator控制持續的轉動,根據unity官方文檔可知旋轉和移動都有對應的公用方法接口,以下:
腳本代碼以下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Rotator : MonoBehaviour { void Update () { //注意旋轉接口函數是類對象的公共方法,因此須要經過對象來調用,故必須小寫t開頭transform transform.Rotate(new Vector3(15,30,45) * Time.deltaTime);//爲使旋轉更平滑乘以deltaTime } }
運行遊戲,能看到收集物每幀實時更新旋轉角度。 接下來,就須要在場景中添加多個相似的這種拾取物,這裏有個很重要的概念點:預設體(prefab),指一個資源,它包含一個遊戲對象或對象組的模板或原型。prefab的做用在於,對一個預設的實例作變動或改變預設資源自己,則場景中全部的這個預設對象(如此例中的拾取物對象)都會作一樣的變動! 所謂的「分身」做用,這裏的收集物顯然可作成預設體:
(根目錄新建Prefabs目錄裝預設體)
將某個對象 A 拖到Prefabs文件夾,能發現對象A的Name變藍,表示成爲了預設體,以下圖:
建立一空對象做爲父節點,單獨裝載全部預設體實例instance。這裏要注意一點,即每一個instance實例對象座標系的選擇,主要有兩種:一是Local本地座標系, 是伴隨對象自身變換而改變的座標系,以下:
二是Global世界座標系, 不會因對象旋轉變換而改變座標系,以下:
本例中爲了保持各個拾取物都處於同一個水平面,故應該切換成Global模式,
(y軸方向不拖動便能保持同一水平面)
爲了更突出,可更改預設體的材質顏色,直接複用上面的一個材質,而後把材質應用到預設體上。 這裏有兩個方法:
①直接替換材質到預設體基類上。以下圖:
②替換材質到某一個預設體instance實例上,但必需要記得點擊「Apply」才能應用到預設體及其全部實例對象,以下:
六 展現分數和文本
顯然須要兩部分實現本例內容,一是展現分數,二是計算統計分值。在PlayerController中添加一count私有變量用來存儲當前分數,初始值爲0;每次發生碰撞時自增1,而後傳遞給UI控件顯示。
1)右鍵選UI部分往場景添加一個Text控件,法線畫布Canvas和事件系統EventSystem也隨之建立(UI控件內容都是放置在一畫布中,規定全部的UI元素都是畫布Canvas的子元素)。
和Game Object不一樣的是,Transform變量變成了Rect Transform,可見UI元素可設置錨點和軸心等因素:
如這裏把錨定至畫布左上角,同時把軸心設置在了左上角,設置x = 10,y = -10設置邊間距。到此UI相關設置完畢,下面要在腳本中獲取這個UI控件:
注意!:UI箱中的全部UI元素的詳細信息都在一個叫「UI」的namespace命名空間中,和腳本代碼中已有的 「using UnityEngine;」 和 「using System.Collections;」等同樣的道理,所以在腳本開頭加上:
using UnityEngine.UI;
或者在VS編輯器跳轉到定義能看到命名空間中對應UI類的定義,
接下來就能在下面編寫UI代碼,先定義一個public變量來引用保存UI文本組件,而後再初始化UI文本顯示值。代碼以下:
using System.Collections; using UnityEngine; using UnityEngine.UI; public class PlayerController : MonoBehaviour { public Text CountText_; private int count; void Start() { rb = GetComponent<Rigidbody>(); count = 10; CountText_.text = "Count Text:" + count.ToString(); } ... ... ... }
2)簡單說,就是和拾取物發生碰撞時,通知玩家對象對count變量自增並更新UI顯示;同時把被碰撞的拾取物隱藏不可見。 總結兩點:
①隱藏不可見用SetActive,但要先獲取實體類對象gameObject再調用; 銷燬對象用Destroy;
②碰撞事件監聽OnTriggerEnter,
這裏注意一點,就是要對發生碰撞的類型過濾下,由於此例中和圍欄發生碰撞也會進入這個事件通知,代碼以下:
private void OnTriggerEnter(Collider other) { if (other.gameObject.CompareTag("fuck")) { count = count + 1; CountText_.text = "Count Text:" + count.ToString(); } }
運行遊戲,發現發生碰撞的時候並無響應事件更新顯示控件。oh My God! 查閱資料,發現有一重要點忽略了,就是「trigger開關」! 接收碰撞物體的是Collider,有一 Is Trigger屬性,以下:
默認不勾選的,則會有碰撞中止的物理效果。當勾選激活此項時,會調用碰撞雙方的腳本 OnTrigger***, 反之,腳本方面沒有任何反應。 但激活帶來的反作用就是不會再有物理效果,如本例中若把player的Collider激活會發現球直接穿牆出去,同時自由落體掉下去了。 故這裏只把拾取物的prefab的trigger開關所有打開接收碰撞響應(由於拾取物沒有RigidBody剛體),整體代碼以下:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class PlayerController : MonoBehaviour { public float speed; private Rigidbody rb; public Text CountText_; private int count; void Start() { rb = GetComponent<Rigidbody>(); count = 0; CountText_.text = "Count Text:" + count.ToString(); } private void FixedUpdate() { float moveHorization = Input.GetAxis("Horizontal"); float moveVertical = Input.GetAxis("Vertical"); Vector3 movement = new Vector3(moveHorization, 0.0f, moveVertical); rb.AddForce(movement* speed); } private void OnTriggerEnter(Collider other) { if (other.gameObject.CompareTag("fuck")) { other.gameObject.SetActive(false); count = count + 1; CountText_.text = "Count Text:" + count.ToString(); } } }
運行遊戲,正常運行!
參考資料連接:
http://www.javashuo.com/article/p-flijmgxi-mg.html (Unity3D碰撞檢測)
https://www.cnblogs.com/zengbinsi/p/zengbinsi_unity3d_004.html (【Unity入門】碰撞檢測與觸發檢測)
七 編譯發佈
(或快捷鍵 Ctrl + Shift + B)
選擇不一樣的平臺,
把須要編譯的場景添加至Build Settings窗口,能夠經過「Add Open Scenes」來添加當前場景,或者從項目視圖中拖拽任意場景到Build Settings窗口的頂部區域。注意,咱們無需包含項目中的每一個場景,只包含須要的場景便可。 甚至窗口中沒有添加任何場景也能編譯,由於Unity會選擇當前正在打開編輯的場景。 最後點擊build按鈕,開始編譯。
PS.編譯過程須要Android SDK,若沒有安裝則會編譯失敗。
參考資料連接: