using UnityEngine;
public class Ball : MonoBehaviour
{
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
這個(gè)腳本文件名為
Ball
,引用了
UnityEngine
這個(gè)命名空
間,組件類型為
Ball
,繼承了
MonoBehaviour
,這些都是自動(dòng)生
成的部分。這里需要關(guān)注的是其中的
Start()
函數(shù)和
Update()
函
數(shù)。
Start()
函數(shù)在游戲開始運(yùn)行的時(shí)候執(zhí)行一次,特別適合進(jìn)行
組件初始化。而
Update()
函數(shù)每幀都會(huì)執(zhí)行,在不同設(shè)備上更新
的頻率有所區(qū)別,特別是當(dāng)系統(tǒng)硬件資源不足時(shí),幀率就會(huì)降
低,因此
Update()
函數(shù)實(shí)際執(zhí)行的頻率是變化的。
Start
和
Update
又被稱為
“
事件
”
,因?yàn)樗鼈兎謩e是在
“
該組件
開始運(yùn)行
”
和
“
更新該組件
”
這兩個(gè)事件發(fā)生時(shí)被調(diào)用的。第
2
章
會(huì)詳細(xì)講解腳本組件的各種事件函數(shù)。
這里介紹一個(gè)非常常用的方法:
Debug.Log()
用于向
Console
(控制臺(tái))窗口輸出一串信息。下面改動(dòng)腳本,加上兩句輸出
信息的代碼。
using UnityEngine;
public class Ball : MonoBehaviour
{
// Use this for initialization
void Start()
{
Debug.Log("組件執(zhí)行開始函數(shù)!");
}
// Update is called once per frame
void Update()
{
Debug.Log("當(dāng)前游戲進(jìn)行時(shí)間:" + Time.time);
}
}
運(yùn)行游戲,找到
Console
窗口,如果沒有打開,則選擇主菜
單中的
Window→General→Console
選項(xiàng)打開,如圖
1-5
所示。
圖1-5 讓Console窗口顯示出來
暫停游戲,查看
Console
窗口中的信息,發(fā)現(xiàn)開始函數(shù)只執(zhí)
行了一次,后面所有的
“
當(dāng)前游戲進(jìn)行時(shí)間:秒數(shù)
”
都是
Update()
函數(shù)被調(diào)用時(shí)輸出的。如果仔細(xì)觀察,可以發(fā)現(xiàn)時(shí)間的流逝不
太穩(wěn)定,特別是在游戲剛啟動(dòng)的時(shí)候偏差較大。
Debug.Log()
函數(shù)是寫代碼、查
bug
的好幫手,越是編程高
手,越是使用得多。
Debug.Log()
函數(shù)也是最簡單、最可靠的一
種調(diào)試手段,未來還會(huì)反復(fù)使用這個(gè)方法,建議從現(xiàn)在開始就
多多應(yīng)用它。
1.1.3 修改物體位置
在
Unity
里修改物體位置,實(shí)際上就是修改
Transform
(變
換)組件的數(shù)據(jù)。在
Inspector
窗口里可以方便地查看和修改
Transform
組件的位置(
Position
)、旋轉(zhuǎn)(
Rotation
)和縮放
(
Scale
)參數(shù),如圖
1-7
所示。
圖1-7 查看和修改物體位置
在界面中可以修改的參數(shù)在腳本中也能修改,而在腳本中
可以修改的參數(shù)就不一定會(huì)在界面上出現(xiàn)了,因?yàn)槟_本的功能
比界面上展示的功能要多得多。
修改
Transform
組件中的
Position
有兩種常用方法。一種是使
用
Translate()
函數(shù)。
// 物體將沿著自身的右側(cè)方向(X軸正方向也稱為向右)前進(jìn)1.5個(gè)單位
transform.Translate(1.5f, 0, 0);
另一種是直接指定新的位置。如果在游戲一開始就把物體
放在(
1, 2.5, 3
)的位置,則只需要修改
Start()
函數(shù)。
void Start () {
transform.position = new Vector3(1, 2.5f, 3);
}
這里可能有兩個(gè)讓人覺得奇怪的地方:
“2.5”
要寫作
“2.5f”
,
設(shè)置位置時(shí)要用
new Vector3(x, y, z)
這種寫法。
這些主要源于
C#
語法的規(guī)定。直接寫
2.5
會(huì)被認(rèn)為是一個(gè)
double
類型的數(shù),而這里需要的是
float
類型的數(shù),所以必須加上
f
后綴。而寫
“new”
的原因是
Vector3
是一個(gè)值類型,而
position
是
一個(gè)屬性,由于
C#
中引用和值的原理,因此不能使
用
“transform.position.y = 2.5f”
這種寫法直接修改物體的位置。這
里的解釋可能對(duì)初學(xué)者來說有點(diǎn)模糊,不過沒有關(guān)系,可以先
記住并使用這個(gè)語法,隨著
C#
編程學(xué)習(xí)的深入自然會(huì)明白。
如果要做一個(gè)連續(xù)的位移動(dòng)畫,只需要讓物體每幀都移動(dòng)
一段很小的距離就可以了。也就是說,可以把改變位置的代碼
寫在
Update()
函數(shù)里,但是每幀都要比前一幀多改變一些位置。
例如,以下兩種方法都可以讓物體沿
z
軸前進(jìn)。
void Update()
{
transform.Translate(0, 0, 0.1f);
// 在這個(gè)例子中等價(jià)于:
transform.position += new Vector3(0, 0, 0.1f);
}
以上兩句代碼只選擇寫其中一句即可,另一句可以注釋
掉。運(yùn)行游戲,觀察小球是否持續(xù)運(yùn)動(dòng)。
小提示
物體位置的兩種寫法有本質(zhì)區(qū)別
如果深究,這里有兩個(gè)要點(diǎn):一是向量的使用和向量加
法,二是局部坐標(biāo)系與世界坐標(biāo)系之間的區(qū)別和聯(lián)系。
Translate()
函數(shù)默認(rèn)為局部坐標(biāo)系,而修改
position
的方
法是世界坐標(biāo)系。
3D
數(shù)學(xué)基礎(chǔ)知識(shí)會(huì)在后續(xù)章節(jié)詳細(xì)說明,
這里先把關(guān)注點(diǎn)放在位移邏輯上。
前面提到,由于系統(tǒng)繁忙時(shí)無法保證穩(wěn)定的幀率,因此對(duì)
于上面的寫法,如果幀率高,小球移動(dòng)就快;幀率低,小球移
動(dòng)就慢。我們需要在
“
每幀移動(dòng)同樣的距離
”
和
“
每秒移動(dòng)同樣的
距離
”
之間做出選擇。
按游戲開發(fā)的常規(guī)方法,應(yīng)當(dāng)選擇
“
每秒移動(dòng)同樣的距
離
”
。舉個(gè)例子,如果幀率為
60
幀
/
秒時(shí)物體每幀移動(dòng)
0.01
米,那
么幀率只有
30
幀
/
秒時(shí)就應(yīng)該每幀移動(dòng)
0.02
米,這樣才能保證物
體移動(dòng)
1
秒的距離都是
0.6
米。這里雖然原理復(fù)雜,但實(shí)際只需
要略作修改即可。
transform.Translate(0, 0, 5 * Time.deltaTime);
// 或
transform.position += new Vector3(0, 0, 5 * Time.deltaTime);
}
Time.deltaTime
表示兩幀之間的間隔,如幀率為
60
幀
/
秒時(shí)這
個(gè)值為
0.0167
秒,幀率只有
10
幀
/
秒時(shí)這個(gè)值為
0.1
秒,用它乘以
移動(dòng)速度就可以抵消幀率變化的影響。由于
Time.deltaTime
是一
個(gè)比較小的數(shù),因此速度的數(shù)值應(yīng)適當(dāng)放大一些。
1.1.4 讀取和處理輸入
Unity
支持多種多樣的輸入設(shè)備,如鍵盤、鼠標(biāo)、手柄、搖
桿、觸摸屏等。很多輸入設(shè)備有著類似的控制方式,如按鍵盤
上的
W
鍵或上箭頭鍵,將手柄的左搖桿向前推,都代表
“
向
上
”
,用
Unity
的術(shù)語表述則是
“
沿縱軸(
Vertical
)向上
”
。以下
代碼就可以獲取用戶當(dāng)前的縱軸輸入和橫軸輸入。
void Update()
{
float v = Input.GetAxis("Vertical");
float h = Input.GetAxis("Horizontal");
Debug.Log("當(dāng)前輸入縱向:" + v + " " + "橫向:" + h);
}
Input.GetAxis()
函數(shù)的返回值是一個(gè)
float
類型的值,取值范
圍為
-1~1
。
Unity
用這種方法將各種不同的輸入方式統(tǒng)一在了一
起。
以上代碼會(huì)輸出
v
和
h
的數(shù)值。運(yùn)行游戲,然后按鍵盤上的
W
、
A
、
S
、
D
鍵或方向鍵,查看
Console
窗口是否正確讀取到了
輸入值。
通過簡單的乘法就可以將輸入的幅度與物體運(yùn)動(dòng)的速度聯(lián)
系起來。
void Update()
{
float v = Input.GetAxis("Vertical");
float h = Input.GetAxis("Horizontal");
Debug.Log("當(dāng)前輸入縱向:" + v + " " + "橫向:" + h);
transform.Translate(h * 10 * Time.deltaTime, 0, v * 10 * Time.deltaTime);
}
代碼解釋:先取得當(dāng)前的縱向、橫向輸入(取值范圍
為
-1~1
),然后將輸入值與速度(代碼中的數(shù)字
10
)和
Time.deltaTime
相乘,以控制物體的移動(dòng)。每幀最小移動(dòng)距離為
0
,在
60
幀時(shí)
x
軸的每幀最大移動(dòng)幅度是
1*10*0.0167
,即
0.167
米,
z
軸同理。
運(yùn)行游戲,按
W
、
A
、
S
、
D
鍵或方向鍵,看看效果。
1.1.5 實(shí)例:實(shí)現(xiàn)一個(gè)移動(dòng)的小球
下面利用上面所講解的內(nèi)容,實(shí)現(xiàn)一個(gè)移動(dòng)小球的案例,
具體操作如下。
01
新建一個(gè)球體。
02
調(diào)整攝像機(jī)的朝向和位置,可以設(shè)置為俯視、平視或斜
上方視角。
03
為球體創(chuàng)建腳本
Ball
并掛載,完整代碼如下。
using UnityEngine;
public class Ball : MonoBehaviour
{
public float speed = 10;
void Start()
{
}
void Update()
{
float v = Input.GetAxis("Vertical");
float h = Input.GetAxis("Horizontal");
transform.Translate(h * speed * Time.deltaTime, 0, v * speed * Time.deltaTime);
}
}
04
運(yùn)行游戲。單擊
Game
(游戲)窗口,然后按
W
、
A
、
S
、
D
鍵或方向鍵就可以看到球體以一定的速度移動(dòng)了。運(yùn)行游
戲的效果如圖
1-8
所示。
圖1-8 控制小球移動(dòng)
通過修改
Translate()
函數(shù)的參數(shù),可以使球體沿不同方向移
動(dòng),如修改為以下代碼就能實(shí)現(xiàn)沿
xy
平面移動(dòng),而不是沿
xz
平
面移動(dòng)。
transform.Translate(h*speed*Time.deltaTime,
v*speed*Time.deltaTime, 0);
用這種寫法修改速度非常方便,不需要反復(fù)修改代碼。因
為
speed
是一個(gè)
public
字段(
C#
中類的成員變量稱為字段,兩種
術(shù)語叫法,不影響理解),
Unity
會(huì)為這種字段提供一個(gè)快捷的
修改方法。在場景中選中球體,在
Inspector
窗口中查看它的腳
本組件,如圖
1-9
所示。
圖1-9 腳本中的速度變量顯示在面板中
讀者會(huì)發(fā)現(xiàn)這里出現(xiàn)了一個(gè)
Speed
變量,值為
10
,這就是腳
本中的
public float speed = 10
所帶來的效果。由于在真實(shí)的游戲
開發(fā)過程中有很多參數(shù)需要設(shè)計(jì)師反復(fù)細(xì)致調(diào)節(jié),因此
Unity
默
認(rèn)將
public
字段直接放在界面上,用戶可以隨時(shí)修改速度,并且
被修改的參數(shù)會(huì)在下一次
Update()
函數(shù)執(zhí)行時(shí)立即生效,也就是
說在游戲運(yùn)行時(shí)也可以隨時(shí)修改參數(shù)并生效。
唯一需要注意的是,如果游戲運(yùn)行前
Speed
的值設(shè)定為
20
,
運(yùn)行時(shí)改為了
30
,那么停止運(yùn)行游戲后,
Speed
的值會(huì)回到
20
。
運(yùn)行時(shí)的改動(dòng)都不會(huì)被自動(dòng)保存,需要在調(diào)整時(shí)記下合適的數(shù)
字,停止運(yùn)行后手動(dòng)修改。將參數(shù)顯示到編輯器中還有更多技
巧,將在第
2
章繼續(xù)討論。
教程相關(guān)資源
Unity 3D游戲開發(fā)+腳本編程完整指南(工程文件+PPT).zip