版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2019.01.26 星期六 |
前言
Unity是由Unity Technologies開發(fā)的一個讓玩家輕松創(chuàng)建諸如三維視頻游戲、建筑可視化腻惠、實時三維動畫等類型互動內(nèi)容的多平臺的綜合型游戲開發(fā)工具,是一個全面整合的專業(yè)游戲引擎构回。Unity類似于Director,Blender game engine, Virtools 或 Torque Game Builder等利用交互的圖型化開發(fā)環(huán)境為首要方式的軟件。其編輯器運行在Windows 和Mac OS X下瓶埋,可發(fā)布游戲至Windows兼蕊、Mac果正、Wii、iPhone忆谓、WebGL(需要HTML5)裆装、Windows phone 8和Android平臺。也可以利用Unity web player插件發(fā)布網(wǎng)頁游戲倡缠,支持Mac和Windows的網(wǎng)頁瀏覽米母。它的網(wǎng)頁播放器也被Mac 所支持。網(wǎng)頁游戲 坦克英雄和手機游戲王者榮耀都是基于它的開發(fā)毡琉。
下面我們就一起開啟Unity之旅铁瞒。感興趣的看下面幾篇文章。
1. Unity開啟篇(一) —— Unity界面及創(chuàng)建第一個簡單的游戲 (一)
2. Unity開啟篇(二) —— Unity界面及創(chuàng)建第一個簡單的游戲 (二)
3. Unity開啟篇(三) —— 一款簡單射擊游戲示例 (一)
4. Unity開啟篇(四) —— 一款簡單射擊游戲示例 (二)
5. Unity開啟篇(五) —— 一款簡單射擊游戲示例 (三)
6. Unity開啟篇(六) —— Unity動畫簡介 (一)
7. Unity開啟篇(七) —— Unity動畫簡介 (二)
8. Unity開啟篇(八) —— Unity聲音簡介(一)
9. Unity開啟篇(九) —— Unity聲音簡介(二)
10. Unity開啟篇(十) —— Unity粒子系統(tǒng)簡介(一)
11. Unity開啟篇(十一) —— Unity粒子系統(tǒng)簡介(二)
開始
在本教程中桅滋,通過創(chuàng)建一個經(jīng)典的競技場射擊游戲來學(xué)習(xí)Unity中腳本的基礎(chǔ)知識慧耍。
Unity的大部分功能都在于其豐富的腳本語言C#
身辨。 您可以使用它來處理用戶輸入,操縱場景中的對象芍碧,檢測碰撞煌珊,生成新的游戲?qū)ο笠约霸趫鼍爸車渡涠ㄏ蚬饩€以幫助您的游戲邏輯。 這可能聽起來令人生畏泌豆,但Unity公開了具有完備文檔的API定庵,使這些任務(wù)變得輕而易舉 - 即使對于新手開發(fā)人員也是如此!
在本教程中踪危,您將創(chuàng)建一個自上而下的射擊游戲蔬浙,它使用Unity腳本來處理敵人的產(chǎn)生,玩家控制贞远,射擊射彈以及游戲玩法的其他重要方面畴博。
注意:本教程假設(shè)您已具備使用C#或類似編程語言的經(jīng)驗蓝仲,并了解Unity的界面和工作流程俱病。
本教程是為Unity 5.3
或更高版本編寫的。 您可以在此處here下載最新版本的Unity袱结。
雖然Unity也支持UnityScript
和Boo
亮隙,但C#
是大多數(shù)開發(fā)人員傾向于使用的編程語言,并且有充分的理由垢夹。 C#被全球數(shù)百萬開發(fā)人員用于應(yīng)用程序溢吻,Web和游戲開發(fā),并且有大量的信息和教程可以幫助您棚饵。
打開已有的工程煤裙,具體頁面如下所示:
在Scene view
視圖中查看。 這是一個小型區(qū)域噪漾,將成為游戲的戰(zhàn)場硼砰,相機和燈光。 如果您的布局與屏幕截圖中的布局不同欣硼,請選擇右上角的下拉菜單并將其更改為2 by 3
题翰。
沒有英雄角色算什么游戲? 您的第一個任務(wù)是創(chuàng)建一個GameObject
來表示場景中的玩家诈胜。
Creating the Player
在Hierarchy
中豹障,單擊Create
按鈕,然后從“3D”部分中選擇Sphere
焦匈。 將球體定位在(X:0血公,Y:0.5,Z:0)
并將其命名為Player
:
Unity
使用entity-component
系統(tǒng)來構(gòu)建其GameObjects
缓熟。 這意味著所有GameObject
都是組件的容器累魔,可以附加這些組件以賦予其行為和屬性摔笤。 以下是Unity內(nèi)置組件的幾個示例:
-
Tranform:每個
GameObject
都附帶此組件。 它保存GameObject
的位置垦写,旋轉(zhuǎn)和縮放吕世。 - Box Collider:立方體形狀的對撞機,可用于探測碰撞梯投。
- Mesh Filter:用于顯示3D模型的網(wǎng)格數(shù)據(jù)命辖。
Player GameObject
需要響應(yīng)與場景中其他對象的碰撞。
要實現(xiàn)此目的分蓖,請在Hierarchy window
窗口中選擇Player
尔艇,然后單擊“檢查器”窗口中的Add `Component按鈕。 在彈出的菜單中選擇Physics> Rigidbody咆疗,這將為播放器添加一個Rigidbody組件漓帚,以便它可以使用Unity的物理引擎母债。
像這樣調(diào)整Rigidody
的值:設(shè)置Drag
到1午磁,Angular Drag
到0并選中Freeze Position
旁邊的Y復(fù)選框。
這將確保Player
無法上下移動毡们,并且在旋轉(zhuǎn)時不會增加阻尼迅皇。
Creating the Player Movement Script
現(xiàn)在Player
已準備就緒,是時候創(chuàng)建將從鍵盤輸入并移動Player
的腳本衙熔。
在Project window
中登颓,單擊Create
按鈕并選擇Folder
。 將新文件夾命名為Scripts
红氯,并在其中創(chuàng)建一個名為Player
的子文件夾框咙。
在Player
文件夾中,單擊Create
按鈕并選擇C#Script
痢甘。 將新腳本命名為PlayerMovement
喇嘱。 序列如下所示:
注意:使用這樣的文件夾可以輕松地按角色組織所有內(nèi)容并減少混亂。 你將為
Player
制作幾個腳本塞栅,所以給它自己的文件夾是有意義的者铜。
雙擊PlayerMovement.cs
腳本。 這將打開您首選的代碼編輯器并加載腳本放椰。 Unity附帶預(yù)裝在所有平臺上的MonoDevelop
作烟,Windows
用戶可以選擇安裝Visual Studio
,并在運行安裝程序時使用它砾医。
本教程假設(shè)您使用的是MonoDevelop
拿撩,但Visual Studio
用戶應(yīng)該能夠順利進行操作而不會出現(xiàn)任何問題。
一旦您選擇的編輯器打開如蚜,您將看到以下界面:
這是Unity
為新腳本生成的默認類压恒。它源自基類MonoBehaviour
头滔,它確保此腳本將在游戲循環(huán)中運行,并具有對某些事件作出反應(yīng)的附加功能涎显。如果你來自iOS世界坤检,這個對象相當于UIViewController
。當腳本運行時期吓,Unity會按預(yù)定順序調(diào)用多個方法早歇。以下是一些最常見的:
-
Start()
:在腳本第一次更新之前,將調(diào)用此方法一次讨勤。 -
Update()
:當游戲運行且腳本啟用時箭跳,此方法將在每一幀被觸發(fā)。 -
OnDestroy()
:此方法在附加到此腳本的GameObject
之前被調(diào)用潭千。 -
OnCollisionEnter()
:當連接此腳本的碰撞器或剛體觸及另一個碰撞器或剛體時谱姓,此方法被調(diào)用。
有關(guān)事件的完整列表刨晴,請查看Unity’s documentation on MonoBehaviours的文檔屉来。
在Start()
方法上方添加以下兩行:
public float acceleration;
public float maxSpeed;
它應(yīng)該是這樣的:
這些是公共變量聲明(variable declarations)
,這意味著這些變量將在Inspector
中可見狈癞,并且可以調(diào)整而無需在腳本和編輯器之間來回切換茄靠。
acceleration
描述了Player's
速度隨著時間的推移而增加的程度。 maxSpeed
是“速度限制”蝶桶。
在其下方慨绳,聲明以下變量:
private Rigidbody rigidBody;
private KeyCode[] inputKeys;
private Vector3[] directionsForKeys;
私有變量無法通過Inspector
設(shè)置,開發(fā)人員有責(zé)任在適當?shù)臅r候初始化它們真竖。
rigidBody
將保存對附加到Player GameObject
的Rigidbody
組件的引用脐雪。
inputKeys
是一個用于檢測輸入的密鑰代碼數(shù)組。
directionsForKeys
包含一個Vector3
變量數(shù)組恢共,它將保存方向數(shù)據(jù)战秋。
用以下內(nèi)容替換Start()
方法:
void Start () {
inputKeys = new KeyCode[] { KeyCode.W, KeyCode.A, KeyCode.S, KeyCode.D };
directionsForKeys = new Vector3[] { Vector3.forward, Vector3.left, Vector3.back, Vector3.right };
rigidBody = GetComponent<Rigidbody>();
}
這段代碼鏈接每個密鑰的相應(yīng)方向,例如 按W
可將物體向前移動旁振。 最后一行獲取對atttached Rigidbody
組件的引用获询,并將其保存在rigidBody
變量中供以后使用。
要實際移動Player
拐袜,您必須處理鍵盤輸入吉嚣。
將Update()
重命名為FixedUpdate()
并添加以下代碼:
// 1
void FixedUpdate () {
for (int i = 0; i < inputKeys.Length; i++){
var key = inputKeys[i];
// 2
if(Input.GetKey(key)) {
// 3
Vector3 movement = directionsForKeys[i] * acceleration * Time.deltaTime;
}
}
}
這里有幾件重要的事情:
- 1)
FixedUpdate()
與幀速率無關(guān),在使用Rigidbodies
時應(yīng)該使用蹬铺。此方法將以恒定間隔觸發(fā)尝哆,而不是盡可能快地運行。 - 2) 此循環(huán)檢查是否按下了任何輸入鍵甜攀。
- 3) 獲取按下的鍵的方向秋泄,將其乘以加速度和完成最后一幀所花費的秒數(shù)琐馆。這將生成一個方向向量(X,Y和Z軸上的速度)恒序,用于移動
Player
對象瘦麸。
如果您不熟悉游戲編程,您可能會問自己為什么必須乘以Time.deltaTime
歧胁。當游戲運行時滋饲,幀速率(或每秒幀數(shù))將根據(jù)硬件和它所承受的壓力而變化,這可能導(dǎo)致在強大的機器上發(fā)生很快喊巍,而在較弱的機器上發(fā)生太慢可能導(dǎo)致不期望的行為屠缭。一般規(guī)則是當你每個(固定)幀執(zhí)行一個動作時,你需要乘以Time.deltaTime
崭参。
在FixedUpdate()
下面添加以下方法:
void movePlayer(Vector3 movement) {
if(rigidBody.velocity.magnitude * acceleration > maxSpeed) {
rigidBody.AddForce(movement * -1);
} else {
rigidBody.AddForce(movement);
}
}
上述方法對ridigbody
施加力呵曹,使其移動。 如果當前速度超過maxSpeed
何暮,則力量向相反方向移動以減慢玩家的速度奄喂,并有效地限制最大速度。
在FixedUpdate()
中郭卫,在if語句的右括號之前砍聊,添加以下行:
movePlayer(movement);
很好背稼! 保存此腳本并返回Unity編輯器贰军。 在Project window
中,將PlayerMovement
腳本拖動到“層次結(jié)構(gòu)”內(nèi)的Player
上蟹肘。
向GameObject
添加腳本會創(chuàng)建組件的實例词疼,這意味著將為您附加的GameObject
執(zhí)行所有代碼。
使用Inspector
將Acceleration
設(shè)置為625
帘腹,將Max Speed
設(shè)置為4375
:
運行場景并使用WASD
鍵移動Player
:
只有幾行代碼贰盗,這是一個非常好的結(jié)果!
然而阳欲,有一個明顯的問題 - 玩家可以快速移出視線舵盈。
Creating the Camera Script
在Scripts
文件夾中,創(chuàng)建一個名為CameraRig
的新腳本球化,并將其附加到Main Camera
秽晚。 需要一些幫助來弄清楚步驟? 您可以查看下面的提示筒愚。
選擇
Scripts
文件夾后赴蝇,單擊項目瀏覽器(Project Browser)
中的Create
按鈕,然后選擇C#Script
巢掺。 將新腳本命名為CameraRig
句伶。 最后劲蜻,將其拖放到Main Camera
對象上,如下所示:
現(xiàn)在考余,在新創(chuàng)建的CameraRig
類中先嬉,在Start()
方法的正上方創(chuàng)建以下變量:
public float moveSpeed;
public GameObject target;
private Transform rigTransform;
您可能已經(jīng)猜到了,moveSpeed
是攝像機跟隨目標的速度 - 可以是場景中的任何游戲?qū)ο蟆?/p>
在Start()
內(nèi)楚堤,添加以下行:
rigTransform = this.transform.parent;
此代碼獲取對場景層次結(jié)構(gòu)中父Camera
對象的變換的引用坝初。 場景中的每個對象都有一個變換Transform
,它描述了對象的位置钾军,旋轉(zhuǎn)和縮放鳄袍。
在同一個腳本中,添加以下方法:
void FixedUpdate () {
if(target == null){
return;
}
rigTransform.position = Vector3.Lerp(rigTransform.position, target.transform.position,
Time.deltaTime * moveSpeed);
}
CameraRig
移動代碼比PlayerMovement
中的移動代碼稍微簡單一些吏恭。 這是因為你不需要Rigidbody
拗小;只需在rigTransform
和目標的位置之間進行插值即可。
Vector3.Lerp()
在空間中取兩個點樱哼,在[0,1]
范圍內(nèi)取浮點哀九,它描述了沿兩個端點的點。 左端點為0
搅幅,右端點為1
阅束。將0.5
傳遞給Lerp()
將在兩個端點之間準確返回一個點。
這會使rigTransform
更接近目標位置并稍微緩和一下茄唐。 簡而言之 - 相機跟隨player
息裸。
回到Unity
。 確保在層次結(jié)構(gòu)中仍然選擇了Main Camera
沪编。 在Inspector
中呼盆,將Move Speed
設(shè)置為8,將Target
設(shè)置為Player
:
運行游戲并在場景中移動蚁廓;無論走到哪里访圃,攝像機都應(yīng)該順利地跟蹤目標變換。
Creating an Enemy
沒有敵人的射擊游戲很容易被擊敗相嵌,但有點無聊腿时。 通過單擊頂部菜單中的GameObject \ 3D Object \ Cube
創(chuàng)建敵人立方體。 將您的Cube重命名為Enemy
并添加Rigidbody
組件饭宾。
在Inspector
中批糟,首先將Cube
的Transform
設(shè)置為(0,0.5,4)
。 在Rigidbody
組件的Constraints
部分中捏雌,選中Freeze Position
類別中的Y復(fù)選框跃赚。
優(yōu)秀 - 現(xiàn)在讓你的敵人以威脅的方式四處走動。 在Scripts
文件夾中創(chuàng)建一個名為Enemy
的腳本。 您現(xiàn)在應(yīng)該成為專家满败,但如果沒有净嘀,請查看教程前面的說明以供參考厢漩。
接下來,在類中添加以下公共變量:
public float moveSpeed;
public int health;
public int damage;
public Transform targetTransform;
您可能無需太多困難就能弄清楚這些變量代表什么。 您之前使用moveSpeed
創(chuàng)建了攝像機裝備涯曲,它在此處具有相同的效果绰沥。 health
和damage
有助于確定敵人何時死亡以及他們的死亡會對Player
造成多大傷害。 最后弧哎,targetTransform
引用了Player
的變換寻拂。
說到玩家梦染,你需要創(chuàng)建一個類來表示敵人想要摧毀的所有玩家。
在項目瀏覽器中朴皆,選擇Player
文件夾并創(chuàng)建一個名為Player
的新腳本帕识;此腳本將對碰撞做出反應(yīng)并跟蹤玩家的健康狀況。 雙擊腳本進行編輯遂铡。
添加以下公共變量以存儲Player's
的生命值:
public int health = 3;
這為健康狀況提供了默認值肮疗,但也可以在檢查器中進行修改。
要處理碰撞扒接,請?zhí)砑右韵路椒ǎ?/p>
void collidedWithEnemy(Enemy enemy) {
// Enemy attack code
if(health <= 0) {
// Todo
}
}
void OnCollisionEnter (Collision col) {
Enemy enemy = col.collider.gameObject.GetComponent<Enemy>();
collidedWithEnemy(enemy);
}
當兩個帶有碰撞器的剛體接觸時伪货,OnCollisionEnter()
會觸發(fā)。 Collision
參數(shù)包含有關(guān)接觸點和碰撞速度等信息钾怔。 在這種情況下碱呼,您只對碰撞對象的Enemy
組件感興趣,因此您可以調(diào)用collidedWithEnemy()
并執(zhí)行攻擊邏輯 - 您接下來將添加該邏輯宗侦。
切換回Enemy.cs
并添加以下方法:
void FixedUpdate () {
if(targetTransform != null) {
this.transform.position = Vector3.MoveTowards(this.transform.position, targetTransform.transform.position, Time.deltaTime * moveSpeed);
}
}
public void TakeDamage(int damage) {
health -= damage;
if(health <= 0) {
Destroy(this.gameObject);
}
}
public void Attack(Player player) {
player.health -= this.damage;
Destroy(this.gameObject);
}
你已經(jīng)熟悉FixedUpdate()
了愚臀,不同的是你使用的是MoveTowards()
而不是Lerp()
。 這是因為敵人應(yīng)該始終以相同的速度移動矾利,而不是在接近目標時輕松進入姑裂。 當敵人被射彈擊中時,會調(diào)用TakeDamage()
男旗;當敵人達到0健康時舶斧,它會自我毀滅。Attack()
類似 - 它對玩家施加傷害然后敵人摧毀自己察皇。
切換回Player.cs
并在collidedWithEnemy()
中茴厉,用以下內(nèi)容替換Enemy attack code
:
enemy.Attack(this);
玩家將受到傷害,敵人將在此過程中自我毀滅。
切換回Unity
矾缓。 將Enemy
腳本附加到Enemy
對象并在Inspector
中怀酷,在Enemy上設(shè)置以下值:
- 1)
Move Speed: 5
- 2)
Health: 2
- 3)
Damage: 1
- 4)
Target Transform: Player
到現(xiàn)在為止,您應(yīng)該能夠自己完成所有這些工作而账。 自己嘗試一下胰坟,然后將結(jié)果與下面的GIF進行比較:
在游戲中,與玩家對抗的敵人構(gòu)成有效的敵人攻擊泞辐。 使用Unity的物理檢測碰撞幾乎是一項微不足道的任務(wù)笔横。
最后,將Player
腳本附加到層次結(jié)構(gòu)中的Player
咐吼。
運行游戲吹缔,并密切關(guān)注控制臺:
當敵人到達玩家時,它會成功執(zhí)行攻擊并將玩家的健康變量減少到2锯茄。但是在控制臺中拋出NullReferenceException
厢塘,指向Player
腳本:
啊哈 - 玩家不僅可以與敵人發(fā)生碰撞,還可以與游戲世界的其他部分發(fā)生碰撞肌幽,例如競技場晚碾。 這些游戲?qū)ο鬀]有Enemy
腳本,因此GetComponent()
返回null
喂急。
打開Player.cs
格嘁。 在OnCollisionEnter()
中,在if
語句中包裝collidedWithEnemy()
:
if(enemy) {
collidedWithEnemy(enemy);
}
這樣就沒有null
了廊移。
后記
本篇主要講述了Unity腳本簡介糕簿,感興趣的給個贊或者關(guān)注~~~