Unity入門:第一個遊戲
Unity官網提供了詳盡的文件和豐富的教學視訊,昨天跟著視訊做了一個簡單的3d遊戲“roll-a-ball”。遊戲涉及了許多Unity的基本知識,用來入門很不錯。
這篇博文並不講述整個遊戲的製作流程,如果您感興趣,可以訪問這裡,如果訪問遇到什麼困難,在B站有一摸一樣的視訊。
這是完成以後的樣子:
執行效果:
作為個人小結,下面寫一些做這個遊戲的收穫:
1、什麼是Unity?
一款遊戲引擎,至於什麼是遊戲引擎,這裡不展開。
2、下載和安裝
作為學習用途,下載personal版即可。
3、熟悉Unity介面
進入Unity後,將會看到這樣的介面:
上圖將介面劃分成了5部分,下面分別解釋每部分的功能:
(1)Toolbar
上面的按鈕有不同的功能,比如左側的第一個按鈕可以用來移動場景中的物體,第二個按鈕用來進行平移變換,第三個按鈕用來進行旋轉變換等。
(2)Hierarchy window
顧名思義,這個部分顯示的是“層次結構”,場景中的物件都會被列到這個視窗中。當我們新建一個Unity專案時,Unity就會自動為我們新增兩個東西:Main Camera和Directional Light,一個是相機,一個是光照。Hierarchy window上面有一個create按鈕,點選這個按鈕,我們可以看到一個包含了空物件、2d,3d物件、UI、光照、相機等在內的選單,在這裡你可以點選你想建立的東西。
(3)Scene view
這是遊戲的場景,我們可以通過調整右上角的座標系圖案來調整觀察場景的位置。
(4)Inspector window
當我們選中一個物件,開啟Inspector window,這個物件的資訊,例如所在的位置,平移了多少等等都會在這個視窗顯示,當然也可以用這個視窗來調整場景中的物件,例如為了編輯方便,一開始我們會使用transform中的reset,將物件放置在座標原點(0,0,0)。Inspector window最下面有一個Add Component按鈕,通過這個按鈕可以給物件增加其它的component,例如新增一條C#指令碼等。
(5)Project window
這個視窗顯示的是這個遊戲使用的資源,通常我們會在這裡建立一些資料夾,例如Scenes資料夾專門儲存場景,Materials資料夾專門儲存材質,Scripts資料夾專門儲存指令碼等。Project window上有一個不起眼的create按鈕,這個按鈕很有用,例如我們可以點選create->folder來新建一個資料夾等等。
事實上,這只是Unity介面一個最基本的佈局,你可以自己拖動這些window或者view來將它們放置在自己喜歡的位置,也就是說,操作介面是可以個性化的。其實上面漏掉了一個很重要的view:game view,如下圖所示:
這個view的按鈕就在scene view旁邊,上圖中我已經將它拖動到了scene view下面,這個檢視顯示的是我們的遊戲最終呈現給使用者的樣子,製作好一個遊戲後,可以點選Toolbar中間那個表示Play的按鈕進行試玩,遊戲的執行情況就顯示在這個檢視中。
為了方便編輯,我們常把Scene view和Game view並列在一起,就像上圖一樣,這樣,在用Play試玩除錯的時候可以不用頻繁切換檢視,從而節省了時間。
4、怎麼理解遊戲中的幾個指令碼?
Unity會自動為每個新建的C#指令碼生成void Start()和void Update()兩個方法,第一個在第一幀,也就是遊戲剛開始時呼叫,第二個在畫面更新時呼叫(準確地說是在渲染每一幀之前被呼叫)。
在這個遊戲中我們會用到三個指令碼:
(1)CameraController.cs
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;
}
}
指令碼的作用是當Player移動時,讓相機也隨著移動。
這裡有一個問題:要達到類似的效果,為什麼不直接把Main Camera設定成Player的孩子?
(2)PlayerController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
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 ("PickUp"))
{
other.gameObject.SetActive (false);
count++;
SetCountText();
}
}
void SetCountText()
{
countText.text = "Count:" + count.ToString ();
if(count>=12)
{
winText.text="You Win!";
}
}
}
這個指令碼被新增到了叫做Player的小球上,Start函式用來做初始化,其中的getComponent用來獲取剛體物件,也就是新增到叫做Player的小球上的那個RigidBody。為什麼用FixedUpdate()不用Update()?因為FixedUpdate在做物理計算之前被呼叫,這個遊戲中的碰撞屬於physics的範疇,所以用FixedUpdate()。還有一個要注意的函式是OnTriggerEnter(),這個函式在物件碰到collider的時候會被觸發,在這個例子中,我們給12個Pickup關聯上了一個叫“PickUp”的Tag,當碰撞發生時如果發現Tag是PickUp,就deactivate這個PickUp(每個PickUp的is trigger需要勾選上)。教學視訊中提到一個問題:除了要給PickUp的collider勾選is trigger,還要加上rigidbody(is kinematic),這是因為Unity計算所有collider的體積後把它們放在一個cache裡,如果collier是靜態的(static),這樣做可以避免在每幀更新的時候重複計算,但是在我們這個遊戲中,因為每次collider都在旋轉,所以每次它的體積都會被重複計算,為了節省資源,可以把collider設定成動態的(dynamic=collider+rigidbody)。
(3)Rotater.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotator : MonoBehaviour {
// Update is called once per frame
void Update () {
transform.Rotate (new Vector3(15,30,45)*Time.deltaTime);
}
}
這裡要用的是Update而不是FixedUpdate(和物理無關)。
5、其他
(1)prefab
類似模板一樣,可以將需要複用某個邏輯的一堆物件放到prefab資料夾中,這就可以對整體進行編輯、修改了。
(2)快捷鍵
例如ctrl+D用來duplicate
(3)有不懂的查文件!!!