原文鏈接:https://blog.csdn.net/q764424567/article/details/100770946
一翰绊、前言
今天我們要用Unity3D做一個植物大戰(zhàn)僵尸的仿制版本。為了保持簡單髓霞,我們將忽略所有花哨的東西,如菜單,多層關卡或過場動畫躲履,并專注于在后院與僵尸作戰(zhàn)炼幔。
效果圖:
二、源碼
UI資源和源代碼請搜索QQ群:1040082875下載
三滚局、正文
版本
==Unity5.0.1f1==
1.主攝像機設置
如果我們選擇主照相機在層次性然后我們可以設置背景色若要黑色居暖,請調整大小而位置如下圖所示:
2.創(chuàng)造草地
注意:右擊圖像,選擇另存為藤肢。保存到項目的資產(chǎn)文件夾并將其保存到新的Sprites文件夾太闺。
讓我們在項目區(qū)選擇它:
然后修改導入設置在==Inspector==:
*[Inspector]:自定義設置面板
注:Pixels to Unit 值設成32這意味著32 x 32像素將適合在游戲世界的一個單位。我們將使用這個值作為我們所有的紋理嘁圈。
之后省骂,我們可以將圖片從項目區(qū)拖入到場景中:
我們會把它定位在(0, 0)所以它在我們游戲的左下角:
添加排序層
我們正在制作一個2D游戲,所以我們不能用三維作為深度效果最住,也不能輕易區(qū)分背景和前景钞澳。相反,我們將使用Sorting Layer告訴統(tǒng)一它應該先畫哪些元素涨缚。例如轧粟,我們應該先畫背景圖,然后再畫植物仗岖。(因此在背景之上).
我們可以換草Sorting Layer如果我們看看Inspector中的Sprite Renderer組件:
讓我們選擇添加排序層.逃延。從分選層列表,添加Background層轧拄,并將其移動到頂部揽祥,如下所示:
之后,我們再次選擇草檩电,并分配先前創(chuàng)建的Background分類層:
==注意:Unity從上到下畫層拄丰,因此背景中的任何內容都將位于列表的頂部府树。==
現(xiàn)在,草將永遠被植物和僵尸所吸引料按。
3.草皮音效
稍后奄侠,在處理“構建”菜單時,我們需要一種方法來確定是否單擊了草瓦载矿。在United中有各種不同的方法來實現(xiàn)這一點垄潮,但最簡單的方法是只使用OnMouseUpAsButton函數(shù),如果單擊了草闷盔,則由United自動調用該函數(shù)弯洗。
現(xiàn)在這里有一件事要記住:只有當游戲對象有對撞機時逢勾,Unity才能做到這一點牡整。所以讓我們選擇添加組件->物理二維->Box Collider 2D在Inspector并啟用Is Trigger 選項:
- Is Triggers
==注意:Is Trigger意味著草會收到各種各樣的碰撞信息,但實際上不會發(fā)生碰撞溺拱。所以逃贝,如果僵尸走進草瓦,它就不會與它相撞迫摔。==
復制草
現(xiàn)在我們的游戲中只有一片草瓦沐扳。讓我們在Hierarchy,選擇Duplicate然后把它放在(1, 0)..然后我們將再次復制它攒菠,并將其放置在(2, 0)..我們會繼續(xù)復制迫皱,直到我們有10 * 5左下角瓷磚位于(0, 0)右上方的瓷磚在(9, 4):
==注意:重要的是所有的瓷磚都有圓形的位置(2, 3)從來沒有(2.01, 3.023).==
4.生命值腳本
僵尸應該能夠攻擊植物,并且開火的植物也可以攻擊講師辖众。
我們需要創(chuàng)建一個Health.cs
我們可以通過右鍵單擊項目區(qū)然后選擇Create->C#腳本:
我們給它起個名字Health.cs然后拖入到新的Scripts文件夾:
我們可以通過雙擊腳本打開并修改腳本:
using UnityEngine;
using System.Collections;
public class Health : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
我們不需要Start或者Update函數(shù)卓起,所以讓我們移除這兩個函數(shù)。
相反凹炸,我們將添加一個INT變量cur戏阅,該變量跟蹤當前的生命值,并添加一個減少該變量的函數(shù)啤它。
如果當前的生命值低于0然后奕筐,應摧毀該實體:
using UnityEngine;
using System.Collections;
public class Health : MonoBehaviour {
// Current Health
[SerializeField]
int cur = 5;
public void doDamage(int n) {
// Subtract damage from current health
cur -= n;
// Destroy if died
if (cur <= 0)
Destroy(gameObject);
}
}
==注:我們使用[SerializeField]屬性讓Unity知道我們希望能夠在Inspector面板中修改cur變量。這通常這是通過public訪問權限变骡,但在這種情況下离赫,我們不希望其他腳本能夠訪問cur變量。相反塌碌,他們應該使用doDamage函數(shù)渊胸。
該腳本稍后將添加到所有植物和僵尸。==
5.創(chuàng)建向日葵植物
向日快圖片
由于我們正在開發(fā)一個2D游戲台妆,動畫是非常容易的翎猛。
對于我們的向日葵胖翰,我們只需要一個閑置的動畫,它的頭部輕微移動:
注意:右擊圖像切厘,選擇另存為萨咳。并將其保存在項目的Assets/Sprites文件夾。
讓我們在項目區(qū)然后在Inspector面板中修改導入設置:
這個Filter Mode和Format影響圖片的分辨率疫稿。
設置Sprite Mode為Multiple告訴Unity培他,這一張照片可以分割成幾個向日葵。
切片
我們可以打開Inspector面板中按Sprite Editor按鈕
之后遗座,我們可以在Sprite Editor中看到我們的向日葵:我們要做的就是打開Slice菜單靶壮,將類型設置為格網(wǎng)像素大小為32 x 32..之后,我們按下Slice按鈕:
讓我們按Apply然后關閉 Sprite Editor
如果我們看看項目區(qū)然后我們可以看到我們的向日葵現(xiàn)在有兩個子節(jié)點:
6.向日葵動畫
從這兩個slices創(chuàng)建一個Unity動畫是非常容易的。我們所要做的就是在項目區(qū)然后把他們拖到場景中:
一旦我們把它拖到場景中,Unity會問我們在哪里保存動畫螃征。
我們可以在我們的項目區(qū)創(chuàng)造一個新的SunflowerAnimation文件夾蝇狼,然后將其保存為idle.anim.
Unity會為我們創(chuàng)建兩個文件:
這就是我們的動畫,如果我們按下Play:
==注意:我們可以在SunflowerAnimation文件夾中通過雙擊sunflower_0抗果,選擇idle狀態(tài)筋帖,然后可以在Inspector面板更改speed==
7.添加物理、標簽與生命值
我們的植物應該是物理世界的一部分冤馏,這意味著我們必須分配一個Collider給它日麸。
一個Collider確保物體會與植物發(fā)生碰撞,而植物也會與其他物體發(fā)生碰撞逮光。
讓我們選擇植物代箭,然后在Inspector面板按下添加組件->Physics 2D->Box Collider 2D:
我們還需要找出某個游戲對象是一個植物,一個僵尸涕刚,還是完全不同的東西嗡综。
這就需要Unity標簽系統(tǒng)了。
如果我們看看Inspector杜漠,我們可以看到當前標記是Untagged:
我們選擇Plant標簽极景。
在標記列表中,然后添加Plant標記到可用標簽列表驾茴,
再次選擇plant盼樟,然后從標記列表中分配標記:
最后在Inspector那里添加組件->Scripts->Health
僵尸可以在稍后對草地plant造成傷害:
注:我們的向日葵剛剛被隨意放置在現(xiàn)場的某個地方。我們將把它保存在那里锈至,下一步我們將生成陽光
5.生成陽光
畫陽光
向日葵植物每隔幾秒鐘就會孕育出一個新的陽光晨缴,所以讓我們先畫一個:
==注意:右擊圖像,選擇另存為裹赴。并將其保存在項目的Assets/Sprites文件夾喜庞。==
我們將使用以下方法導入設置:
Foreground Layer前景層
我們希望太陽被畫在背景前面和植物前面诀浪。讓我們點擊添加排序層。
再一次創(chuàng)造另一個分選層延都,說出來前景并將其移至列表的底部:
之后雷猪,我們可以再次選擇sun并分配Foreground排序層:
創(chuàng)建預制件
讓我們把陽光拖到Hierarchy一次,創(chuàng)建一個游戲對象:
然后按下添加組件->Physics 2D>Circle Collider 2D
碰撞器可以讓陽光可以接收碰撞信息:
==注意:在實際的植物大戰(zhàn)僵尸游戲中晰房,陽光并沒有真正地與植物或僵尸發(fā)生碰撞求摇。我們可以通過在Circle Collider 2D中勾選Is Trigger。這意味著陽光接收到碰撞信息殊者,但從未真正與任何物體發(fā)生碰撞与境。僵尸將能夠穿過它,而不是與它相撞猖吴。==
之后摔刁,我們創(chuàng)建一個新的文件Prefabs,將sun拖到Prefabs文件中創(chuàng)建一個預制體:
現(xiàn)在我們可以將sun從場景中刪除海蔽。
注意:稍后將通過使用實例化功能生成陽光共屈。
8.創(chuàng)建生成腳本
我們希望向日葵每隔幾秒鐘產(chǎn)生一個新的陽光。這種行為可以通過腳本實現(xiàn)党窜。讓我們選擇向日葵拗引,然后點擊添加組件->New Script:
我們給它起個名字SunSpawn,選擇C#作為語言
然后將其移動到項目的Scrips文件夾中幌衣。之后矾削,我們將打開它:
using UnityEngine;
using System.Collections;
public class SunSpawn : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
我們將添加一個公共GameObject變量,允許我們稍后在Inspector中指定預制體:
public class SunSpawn : MonoBehaviour {
public GameObject prefab;
...
這個實例化函數(shù)允許我們將預置體加載到場景中豁护。
這個InvokeRepeting函數(shù)允許我們從某個時候開始哼凯,重復調用某個函數(shù)。
例如择镇,如果我們想在1秒內第一次生成挡逼,然后每2秒重復一次,我們將使用
InvokeRepeting(“Spawn”腻豌,1家坎,2)
我們希望在10秒內產(chǎn)生第一個陽光,然后每10秒繼續(xù)生成更多的陽光吝梅,下面是我們的代碼:
using UnityEngine;
using System.Collections;
public class SunSpawn : MonoBehaviour {
public GameObject prefab;
// Use this for initialization
void Start() {
// Spawn first Sun in 10 seconds, repeat every 10 seconds
InvokeRepeating("Spawn", 10, 10);
}
void Spawn() {
// Load prefab into the Scene
// -> transform.position means current position
// -> Quaternion.identity means default rotation
Instantiate(prefab,
transform.position,
Quaternion.identity);
}
}
現(xiàn)在我們可以保存腳本并再一次查看Inspector面板虱疏。
腳本有一個預制體插槽,因為我們的預制體變量是公開的苏携。
讓我們拖著我們的SunPrefab從項目區(qū)到預制件腳本的插槽:
如果我們按下Play然后我們每10秒就能看到一個新的太陽生成做瞪。
陽光移動
陽光生成后,它應該慢慢地消失在屏幕的頂端。我們將使用 Rigidbody 2D装蓬。
剛體通常被用于物理世界中的任何東西著拭,而這些東西應該是在移動的。
讓我們在Inspector那里單擊添加組件->Physics2D->Rigidbody2D牍帚。我們將為它分配以下屬性:
現(xiàn)在我們要做的就是給剛體一些速度(這是movement direction * speed)..以下圖像顯示某些運動方向所需的不同矢量:
我們將創(chuàng)建另一個C#腳本儡遮,命名為DefaultVelocity然后一直用它來設定速度:
using UnityEngine;
using System.Collections;
public class DefaultVelocity : MonoBehaviour {
// The Velocity (can be set from Inspector)
public Vector2 velocity;
void FixedUpdate () {
GetComponent<Rigidbody2D>().velocity = velocity;
}
}
注意:我們在每個FixedUpdate調用此函數(shù),以便無論發(fā)生什么情況暗赶,該腳本所附加的內容都將嘗試繼續(xù)移動鄙币。這對于僵尸來說是很有用的,當他們跑進一個植物時蹂随,可能無法繼續(xù)移動十嘿,但是我們的腳本將確保他們在植物被摧毀后再次開始移動。
之后岳锁,我們再次選擇Sun預置绩衷,然后單擊添加組件->Scripts->Default Velocity
我們指定一個速度向上 (進入y方向):
如果我們按下Play然后,我們現(xiàn)在可以看到太陽陽光生成激率,然后向上移動:
收集陽光
當我們談到陽光的時候唇聘,我們必須做的最后一件事就是讓Player收集它。
我們將需要一個全局變量得分柱搜,以跟蹤多少陽光被收集,每當玩家點擊陽光剥险,我們將增加這個數(shù)的大小聪蘸。
Unity有Onmousedown函數(shù),該函數(shù)確定我們是否單擊了GameObject表制。
所以讓我們創(chuàng)建一個新的C#腳本SunCollect然后使用Onmousedown函數(shù):
using UnityEngine;
using System.Collections;
public class SunCollect : MonoBehaviour {
// Global score
public static int score = 100;
void OnMouseDown() {
// Increase Score
score += 20;
// Destroy Sun
Destroy(gameObject);
}
}
注:我們必須使用靜態(tài)以使分數(shù)變量全局化健爬。這意味著其他腳本可以使用SunCollection.score獲取到數(shù)值。最初的分數(shù)是100么介,所以玩家有一些陽光來開始建造植物娜遵。
一旦我們將腳本添加到SunPrefab中,我們就可以按Play壤短,等待太陽生成陽光设拟,然后點擊它收集它。
清理層級
現(xiàn)在向日葵還在場景中久脯,但我們不希望它從一開始就在那里纳胧。
游戲應該在啟動后自動生成它。
因此帘撰,讓我們從它拖到Prefabs文件夾:
6.植物開火
植物圖片
好吧跑慕,讓我們再創(chuàng)造一種植物,這種植物能夠向僵尸射擊。和往常一樣核行,我們將從繪制所有動畫開始牢硅。頂部的兩個切片是空閑動畫,底部的兩個切片是開火動畫:
==注意:右擊圖像芝雪,選擇另存為减余。并將其保存在項目的Assets/Sprites文件夾。==
導入設置
點擊Sprite Editor绵脯,然后使用以下設置對其進行切片:
7.植物動畫
創(chuàng)造動畫
這一次佳励,我們有兩個動畫在我們的形象。前兩個切片是空閑動畫蛆挫,最后兩個切片是開火動畫赃承。
將前兩個切片拖入到場景中然后創(chuàng)建空閑動畫:
命名它idle.anim并將其保存在一個新FiringplantAnimation文件夾中
射擊動畫的操作方式也是一樣的:
如果我們按下Play然后我們可以在游戲中看到我們的兩個動畫:
注意:它們仍然是兩個不同的游戲對象,但是我們很快就會處理好的悴侵。
清理對象
讓我們在層級面板上刪除firingplant_2瞧剖,然后去項目區(qū)刪除firingplant_2動畫控制器,刪完以后的樣子:
注意:這么做只是為了整潔可免,不刪除也沒有影響
修改動畫控制器
在Project區(qū)抓于,雙擊firingplant_0動畫控制器,打開動畫控制器浇借,可以看到當前狀態(tài)機firingplant_0在項目區(qū):
現(xiàn)在我們看到的就是閑散狀態(tài)捉撮。如果我們想讓它在某個時候播放射擊動畫,那么我們將再創(chuàng)建一個狀態(tài)巾遭,我們將firing.anim動畫也拖入到動畫控制器:
我們需要某種參數(shù)來幫助Unity確定何時進入射擊狀態(tài)灼舍。
我們將選擇參數(shù)選項卡,然后在右邊單擊+骑素,添加一個Trigger類型的參數(shù)給它起個名字IsFiring:
注意:觸發(fā)器是只觸發(fā)一次的參數(shù)刚夺。稍后献丑,我們將在腳本中設置此參數(shù)。
當IsFiring參數(shù)被觸發(fā)筐摘,我們將切換到射擊狀態(tài)。讓我們右鍵單擊idle狀態(tài),選擇Make Transition然后將白色箭頭拖到firing狀態(tài):
之后郭赐,點擊白色箭頭捌锭,我們將禁用Has Exit Time屬性并設置條件IsFiring:
注意:禁用Has Exit Time,是因為轉換不應該在一段時間之后自動發(fā)生
現(xiàn)在豁状,我們再從firing到idle泻红。這一次我們將開啟Has Exit Time
因為我們希望動畫狀態(tài)機從firing到idle在下一秒自動執(zhí)行谊路。
我們還將設置Exit Time為1:
這是我們最后的狀態(tài)機:
注意:狀態(tài)機現(xiàn)在可以根據(jù)設置的IsFiring參數(shù)自動切換idle和firing狀態(tài)
8.植物的物理和Tag
添加碰撞器
設置Tag為Plant:
添加Health.cs腳本給植物挤巡,以便僵尸稍后能夠對植物造成傷害:
9.植物的子彈
畫個子彈
我們將使用16x16px紋理作為子彈:
==注意:右擊圖像矿卑,選擇另存為母廷。并將其保存在項目的Assets/Sprites文件夾。==
導入設置
子彈預制體
我們將把子彈紋理拖到場景中业舍,然后將其拖回項目區(qū)舷暮,它創(chuàng)建了一個Prefab:
之后下面,我們可以再次從層次面板中刪除它耗啦。
子彈物體
添加碰撞器和剛體:
注意:我們啟用了Is Trigger所以子彈會穿過植物而不是與它們相撞帜讲。
發(fā)射子彈
子彈一被實例化就應該飛向右邊舒帮。
我們已經(jīng)有了一個腳本,通過使用剛體的velocity译红。
所以讓我們選擇添加DefaultVelocity.cs腳本侦厚,指定一個速度讓它向右飛:
注意:這是基于組件的開發(fā)的美妙之處刨沦。我們可以寫一次腳本,然后重復使用它在我們的游戲中的各種實體来破。
碰撞造成傷害
為了檢查碰撞徘禁,我們將使用Unity的OnTriggerEnter2D函數(shù)
一旦子彈飛進另一個GameObject娘荡,就會調用該函數(shù)
在這種情況下它改,我們將檢查它是否是僵尸(通過比較標簽)然后降低它的生命值央拖。
讓我們創(chuàng)建一個新的C#腳本鲜戒,命名為BulletDamage.cs然后雙擊打開,不需要Stat函數(shù)和Update函數(shù)刪除失都,然后添加一個OnTriggerEnter2D函數(shù):
using UnityEngine;
using System.Collections;
public class BulletDamage : MonoBehaviour {
void OnTriggerEnter2D(Collider2D co) {
// Zombie?
if (co.tag == "Zombie") {
// Deal Damage, destroy Bullet
co.GetComponent<Health>().doDamage(1);
Destroy(gameObject);
}
}
}
注意:我們使用GetComponent找到僵尸上面的組件Health粹庞,然后我們通過調用doDamage功能。之后流码,我們通過以下方法將子彈從游戲中銷毀
我們可以通過選擇Add Component->Scripts->Bullet Damage:
10.植物發(fā)射子彈
既然我們有了子彈漫试,我們就可以讓我們的開火植物一看到僵尸就射它。
我們新添加一個腳本Firing.cs,然后雙擊打開它:
using UnityEngine;
using System.Collections;
public class Firing : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
首先劫哼,我們得找出植物右邊是否有僵尸眯亦。
我們可以通過使用RaycastAll功能妻率。一個RaycastAll射出一條射線穿過這個世界宫静,然后發(fā)現(xiàn)它是否擊中了任何東西。
所以捌袜,如果我們從屏幕的最右邊向植物發(fā)射射線虏等,如果它與標有“僵尸”標簽的物體相撞霍衫,那么植物就應該在發(fā)射子彈。
這是我們的功能:
bool zombieInFront() {
// Raycast from the right of the game to the plant
Vector2 origin = new Vector2(9.5f, transform.position.y);
RaycastHit2D[] hits = Physics2D.RaycastAll(origin, -Vector2.right);
// Find out if any Zombie was hit
foreach (RaycastHit2D hit in hits) {
if (hit.collider != null &&
hit.collider.gameObject.tag == "Zombie")
return true;
}
return false;
}
注意:RaycastAll函數(shù)返回所有點擊峰髓,而不像Raycast函數(shù)那樣只返回第一個點擊。我們也可以從植物向屏幕右側射出一束光線徐紧。但是從右向植物發(fā)射更好并级,因為如果我們給植物增加一個碰撞器,我們就會遇到麻煩愈涩,在這種情況下履婉,射線只會擊中植物本身辑奈。我們使用-Vector2.right身害。因為它是向左塌鸯。我們使用向量(9.5f, pos.y)作為光線投射的位置,因為這是草的右邊界茧球,還有植物的高度抢埋。
我們還需要一個公共的Prefab變量,這個變量將被設置為子彈預制體:
public class Firing : MonoBehaviour {
// The Bullet Prefab
public GameObject bulletPrefab;
...
}
現(xiàn)在我們可以寫我們的Shoot函數(shù)饥努,實例化生成子彈,并設置IsFiring參數(shù)在我們的動畫狀態(tài)機中溶浴,
每當它看到僵尸時:
void Shoot() {
if (zombieInFront()) {
// Animation
GetComponent<Animator>().SetTrigger("IsFiring");
// Instantiate Bullet
Instantiate(bulletPrefab, transform.position, Quaternion.identity);
}
}
如果我們把它們放在一起的話,情況是這樣的:
using UnityEngine;
using System.Collections;
public class Firing : MonoBehaviour {
// The Bullet Prefab
public GameObject bulletPrefab;
// Shooting Interval
public float interval = 0.5f;
// Use this for initialization
void Start () {
// Try to shoot every few seconds
InvokeRepeating("Shoot", 0, interval);
}
bool zombieInFront() {
// Raycast from the right of the game to the plant
Vector2 origin = new Vector2(9.5f, transform.position.y);
RaycastHit2D[] hits = Physics2D.RaycastAll(origin, -Vector2.right);
// Find out if any Zombie was hit
foreach (RaycastHit2D hit in hits) {
if (hit.collider != null &&
hit.collider.gameObject.tag == "Zombie")
return true;
}
return false;
}
void Shoot() {
if (zombieInFront()) {
// Animation
GetComponent<Animator>().SetTrigger("IsFiring");
// Instantiate Bullet
Instantiate(bulletPrefab, transform.position, Quaternion.identity);
}
}
}
然后我們點擊植物,將我們的預制體子彈拖入到預制體插槽中:
注意:一旦我們加入僵尸戏自,我們就可以嘗試一下射擊了。
然后將植物firingplant拖入到prefab文件夾猛们,做成一個預制體弯淘。
11.生成菜單
現(xiàn)在我們創(chuàng)建菜單,并實現(xiàn)需要的功能态鳖。
Build Info組件
我們的建造菜單將需要每個植物的價格和一個小預覽圖像。
現(xiàn)在這種數(shù)據(jù)必須存儲在某個地方邦泄。
要做到這一點,最好的方法是將其存儲在每個植物的預制體中包蓝。
讓我們選擇我們的兩個植物預制體,然后點擊添加組件硅瞧,新腳本腕唧,命名為BuildInfo颂暇,然后雙擊打開:
using UnityEngine;
using System.Collections;
public class BuildInfo : MonoBehaviour {
public Texture previewImage;
public int price;
}
我們將使用以下預覽圖像:
==注意:右擊圖像,選擇另存為县爬。并將其保存在項目的Assets/Sprites文件夾。==
導入設置選中兩幅圖片:
然后我們分別選擇我們的Build Info組件,分配以下屬性:
向日葵
寒冰射手
12.繪制菜單
為了顯示菜單名,我們將使用OnGUI函數(shù):
- 畫陽光和設置陽光分數(shù)
- 每種植物
- 畫出植物的樣子和需要的陽光數(shù)量
讓我們先梳理一下步驟:
- 使用GUILayout將菜單定位在最上面的中心
- 使用Horizontal 畫出框框(帶有方框式)
- 畫陽光圖像和陽光的分數(shù)
- 畫出每個植物
- 繪制按鈕預覽圖像和價格
注意:GUILayout.Button只能顯示一個圖像或者一個文本工闺,不能兩個都顯示,我們希望顯示預覽圖和價格叠殷,我們將使用GUIContent
我們點擊Main Camera,選擇添加組件壶冒,新建一個腳本胖腾,命名為BuildMenu.cs
這是我們的BuildMenu腳本:
using UnityEngine;
using System.Collections;
public class BuildMenu : MonoBehaviour {
// Sun Image
public Texture sunImage;
// Plant Prefabs
public BuildInfo[] plants;
void OnGUI() {
// Begin Gui
GUILayout.BeginArea(new Rect(Screen.width/2 - 100, -7, 200, 100));
GUILayout.BeginHorizontal("box");
// Draw the Sun
GUILayout.Box(new GUIContent(SunCollect.score.ToString(), sunImage));
// Draw each Plant's BuildInfo
foreach (BuildInfo bi in plants) {
GUILayout.Button(new GUIContent(bi.price.ToString(), bi.previewImage));
}
// End Gui
GUILayout.EndHorizontal();
GUILayout.EndArea();
}
}
注意:植物預制板是一個數(shù)組(因此[ ])。這意味著這不僅僅是一個而是一組群井。
保存腳本后,我們將把我們的太陽圖像和植物預制板從我們的項目區(qū)進入腳本的插槽:
如果我們按下Play然后我們就可以看到我們的菜單了:
啟用和禁用按鈕
現(xiàn)在有更多的東西要在這里實現(xiàn)。首先,每個按鈕應該啟用缺脉,只有當玩家收集到足夠的太陽支付它。這可以很容易地通過使用GUI.enabled:
// Draw each Plant's BuildInfo
foreach (BuildInfo bi in plants) {
GUI.enabled = SunCollect.score >= bi.price;
GUILayout.Button(new GUIContent(bi.price.ToString(), bi.previewImage));
}
注意:這會將一個bool值(真或假)分配給GUI.enabled礁扮。bool值是通過判斷SunCollect.score是否植物的價格要高來判斷是否為真太伊。
如果我們按下Play,我們就可以看到我們的按鈕被禁用芳悲,除非我們有足夠的陽光:
13.生成植物
讓我們來處理最重要的部分:生成植物。
玩家應首先單擊“生成”菜單中的“植物”按鈕罢洲,然后單擊“草地”殿较。之后淋纲,植物應該建在那塊草地上。
因此伙窃,首先,我們需要跟蹤玩家想要建造的植物:
// Currently building...
public static BuildInfo cur;
注:public static因為我們希望以后能夠從另一個腳本訪問它鳍怨。
一旦玩家點擊一個按鈕,我們就會設置cur變量為玩家想要創(chuàng)建的植物:
// Draw each Plant's BuildInfo
foreach (BuildInfo bi in plants) {
GUI.enabled = SunCollect.score >= bi.price;
if (GUILayout.Button(new GUIContent(bi.price.ToString(), bi.previewImage)))
cur = bi;
}
14.草地的腳本
現(xiàn)在确徙,我們將不得不等待玩家點擊草地。
如果他點擊了一個伴逸,那么我們想要構建BuildInfo.cur 植物。
讓我們選擇場景中的所有草塊,然后單擊Add Component->New Script官紫。
我們給它起個名字Grass酝陈,再一次將它移到我們的Scripts 文件夾中,然后打開它。
我們將使用OnMouseUpAsButton函數(shù)以確定是否單擊了草地:
using UnityEngine;
using System.Collections;
public class Grass : MonoBehaviour {
void OnMouseUpAsButton() {
// Build Stuff
}
}
現(xiàn)在我們將找出是否有什么東西要建喇勋,如果有压彭,我們將建造它汗盘,并讓玩家支付陽光:
using UnityEngine;
using System.Collections;
public class Grass : MonoBehaviour {
void OnMouseUpAsButton() {
// Is there something to build?
if (BuildMenu.cur != null) {
// Build it
Instantiate(BuildMenu.cur.gameObject, transform.position, Quaternion.identity);
SunCollect.score -= BuildMenu.cur.price;
BuildMenu.cur = null;
}
}
}
注意:我們可以從任何位置訪問BuildMenu的cur變量。這起作用是因為public static菱阵。我們用實例化使用草地的位置(transform.position),默認的旋轉(Quaternion.identity)虑稼。之后我們清除cur變量,因為我們已經(jīng)完成了創(chuàng)建。
如果我們按下Play然后我們現(xiàn)在可以創(chuàng)建一些植物:
15.僵尸
畫僵尸
現(xiàn)在我們一直在等待的是:僵尸:
和往常一樣躲庄,我們將從繪制一個包含所有動畫幀的圖像開始噪窘。第一行包含行走動畫,第二行包含攻擊動畫:
==注意:右擊圖像,選擇另存為谱秽。并將其保存在項目的Assets/Sprites文件夾。==
導入設置:
圖像將被切片為32 x 32網(wǎng)格:
16.僵尸動畫
讓我們創(chuàng)建moving動畫,通過選擇前4個切片并將它們拖到場景中來創(chuàng)建動畫:
我們會把它命名為moving.anim存放在一個新的ZombieAnimation文件夾
接下來的兩片將是attacking動畫:
我們會把它命名為attacking.anim存放在一個新的ZombieAnimation文件夾
清理
與往常一樣鲫寄,我們將在場景中刪除zombie_4吉执,在項目文件中刪除zombie_4的動畫狀態(tài)機
17.僵尸動畫狀態(tài)機
我們前面已經(jīng)創(chuàng)建了很多次狀態(tài)機了,已經(jīng)很熟悉了:
參數(shù)是:
- Trigger類型的IsAttacking變量
這些Transitions 是:
- 進攻:=IsAttacking
- 進攻到移動:= Exit Time 1.0
這意味著只要我們說IsAttacking地来,動畫狀態(tài)機將播放進攻動畫一秒鐘戳玫。然后它會自動回到移動狀態(tài)未斑。
18.僵尸物理
我們的僵尸應該是物理世界的一部分量九,這意味著它需要一個BoxCollider2D。
它也應該四處移動颂碧,這意味著它需要一個Rigidbody 2D:
19.僵尸移動
僵尸應該向左走荠列。當然,我們可以再次使用我們的DefaultVelocity腳本载城,選擇Add Component->Scripts->Default Velocity然后分配一個速度肌似,讓它慢慢地向左走:
20.僵尸攻擊腳本
一旦僵尸與植物相撞,它就應該每秒鐘攻擊一次诉瓦。
添加一個新腳本ZombieAttacking.cs川队,然后雙擊打開力细,不需要Start函數(shù)和Update函數(shù),刪除固额,然后添加OnCollisionStay2D函數(shù):
using UnityEngine;
using System.Collections;
public class ZombieAttacking : MonoBehaviour {
void OnCollisionStay2D(Collision2D coll) {
// Collided with a Plant?
if (coll.gameObject.tag == "Plant") {
// Do Stuff...
}
}
}
僵尸站在植物前應播放攻擊動畫:
void OnCollisionStay2D(Collision2D coll) {
// Collided with a Plant?
if (coll.gameObject.tag == "Plant") {
// Play Attack Animation
GetComponent<Animator>().SetTrigger("IsAttacking");
}
}
它也應該對植物造成傷害眠蚂,但每秒鐘只能造成一次:
using UnityEngine;
using System.Collections;
public class ZombieAttacking : MonoBehaviour {
// Last Attack Time
float last = 0;
void OnCollisionStay2D(Collision2D coll) {
// Collided with a Plant?
if (coll.gameObject.tag == "Plant") {
// Play Attack Animation
GetComponent<Animator>().SetTrigger("IsAttacking");
// Deal damage once a second
if (Time.time - last >= 1) {
coll.gameObject.GetComponent<Health>().doDamage(1);
last = Time.time;
}
}
}
}
注意:我們只是用Time.time找出從那時起已經(jīng)過去了多少時間最后的時間,然后進入植物 Health腳本斗躏,調用doDamage函數(shù)并重置最后的時間到了逝慧。
還記得我們是如何檢查僵尸射擊和子彈記錄上的標簽?
讓我們添加僵尸Tag到我們的僵尸啄糙,以確保它可以被子彈射中:
我們還將添加一個Health腳本:
如果我們按下Play建造一個向日葵
然后我們可以看到僵尸將如何嘗試攻擊到它笛臣。
如果我們建了一個寒冰射手,那么我們就可以看到它是如何在幾槍之后殺死僵尸的隧饼!
我們還將通過復制幾個僵尸沈堡,他們將僵尸定位在水平的右邊,這樣他們在步行幾秒鐘后才能到達:
如果我們按下Play然后我們就可以看到游戲的行動:
21.摘要
我們剛剛創(chuàng)造了一個干凈而簡單的植物大戰(zhàn)僵尸游戲燕雁。
該教程相當長诞丽,但仍然有許多功能和改進可以添加到游戲。
和往常一樣拐格,現(xiàn)在是你讓游戲變得有趣的時候了僧免!