知識(shí)
不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價(jià)值,我們?cè)谧非笃湟曈X(jué)表現(xiàn)的同時(shí),更側(cè)重于功能的便捷,營(yíng)銷(xiāo)的便利,運(yùn)營(yíng)的高效,讓網(wǎng)站成為營(yíng)銷(xiāo)工具,讓軟件能切實(shí)提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序?yàn)楹笃谏?jí)提供便捷的支持!
[Unity3D]Unity3D游戲開(kāi)發(fā)之塔防游戲項(xiàng)目講解(上)
發(fā)表時(shí)間:2021-1-4
發(fā)布人:葵宇科技
瀏覽次數(shù):60
喜歡我的博客請(qǐng)記住我的名字:秦元培,我的博客地址是blog.csdn.net/qinyuanpei
轉(zhuǎn)載請(qǐng)注明出處,本文作者:秦元培, 本文出處:http://blog.csdn.net/qinyuanpei/article/details/42394949
??
大家好,我是秦元培。我參加了CSDN2014博客之星的評(píng)選,歡迎大家為我投票,同時(shí)希望在新的一年里大家能繼續(xù)支持我的博客!
作為2015年的第一篇博客,博主首先想要感謝各位朋友的鼓勵(lì)和支持,在新的一年里,博主將努力為大家分享更多、更好的游戲開(kāi)發(fā)方面的原創(chuàng)技術(shù)文章,希望大家能繼續(xù)關(guān)注和支持博主的博客。那么,今天博主想和大家分享的是一個(gè)塔防游戲的項(xiàng)目案例。通常意義上講,塔防游戲是指一類(lèi)在地圖上建造炮臺(tái)或者類(lèi)似建筑物來(lái)阻止敵人進(jìn)攻的策略類(lèi)游戲。從這個(gè)概念中,我們可以快速地抽離出來(lái)三個(gè)元素,即地圖(場(chǎng)景)、敵人、炮臺(tái)(防守單位)。當(dāng)我們抽離出來(lái)這樣三個(gè)元素后,現(xiàn)在塔防游戲就變成了這樣的一種描述,即敵人按照地圖中設(shè)計(jì)的路徑進(jìn)攻,玩家利用防守單位進(jìn)行防守的一類(lèi)策略游戲。經(jīng)典的塔防游戲有哪些呢?比如我們最為熟悉的《植物大戰(zhàn)僵尸》、《保衛(wèi)蘿卜》都是塔防類(lèi)游戲的經(jīng)典游戲。如果我們將塔防游戲中的防守單位的范圍擴(kuò)大到玩家,那么像《英雄聯(lián)盟》這樣的游戲同樣是可以稱(chēng)之為塔防游戲的,因?yàn)閿澄谊嚑I(yíng)的最終目的都是要摧毀敵方的防御塔,只是敵我雙方都從炮臺(tái)或者怪物變成了有血有肉的人物,加之角色扮演(RPG)和即時(shí)戰(zhàn)略(RTS)等元素的混合滲透,使得這樣的游戲從單純的塔防游戲變成了一款可玩度極高的游戲(天啊,我居然在夸這個(gè)游戲.....)。好了,那么我們就來(lái)嘗試著做出一個(gè)簡(jiǎn)單的塔防游戲吧,注意是簡(jiǎn)單的塔防游戲哦,既然塔防游戲的三個(gè)要素是地圖、敵人和防守單位,那么我們就從這三個(gè)方面來(lái)著手設(shè)計(jì)這個(gè)游戲吧!在本篇文章中,我們將用到下面的知識(shí):
- Unity2D中的Sprite動(dòng)畫(huà)
- Unity3D中的可視化輔助類(lèi)Gizmos
- 塔防游戲中敵人按路徑尋路的實(shí)現(xiàn)
- Unity3D uGUI的初步探索
- 簡(jiǎn)單的AI算法
一、地圖篇
地圖是一個(gè)塔防游戲中玩家最為關(guān)注的地方,因?yàn)榈貓D和敵人將直接影響到玩家的策略。如圖是博主從《保衛(wèi)蘿卜》游戲中提取的一張游戲地圖。在這張地圖中我們可以清楚看到怪物進(jìn)攻的路徑,怪物將沿著地圖中的路徑向我方防守單位發(fā)起攻擊。那么,在游戲中,我們?cè)撛鯓哟_定怪物的攻擊路徑呢?首先我們可以對(duì)地圖進(jìn)行下分析,在地圖中基本上基本上只有兩種類(lèi)型的區(qū)域,即可以放置防守單位的區(qū)域和不可放置防守單位的區(qū)域兩種。由此我們可以設(shè)計(jì)出下面的結(jié)構(gòu):
[img]http://img.blog.csdn.net/20150105095547785?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWlueXVhbnBlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
using UnityEngine; using System.Collections; [SerializeField] public class GridNode : MonoBehaviour { public enum NodeType { CanPlace, CantPlace } public NodeType GridNodeType=NodeType.CanPlace; }
可以看出,我們?cè)贕ridNode類(lèi)中定義了一個(gè)稱(chēng)為NodeType的枚舉類(lèi)型,這個(gè)枚舉類(lèi)型有兩個(gè)值,CanPlace表示可以放置防守單位,CantPlace表示不可以放置防守單位。在GridNode類(lèi)中只有一個(gè)NodeType類(lèi)型的成員變量GridNodeType,該成員變量的默認(rèn)值是CanPlace,即可以放置防守單位。那么,現(xiàn)在問(wèn)題來(lái)了,我們找到了一種可以用來(lái)描述地圖中不同區(qū)域的方法,可是這些區(qū)域在哪里呢?所以我們需要一種方法來(lái)生成這些區(qū)域。這里隆重向大家介紹Gizoms類(lèi),Gizmo是Unity中一個(gè)用于在場(chǎng)景視圖可視化調(diào)試或輔助設(shè)置的工具類(lèi)。簡(jiǎn)單的說(shuō),當(dāng)我們需要在編輯器環(huán)境中實(shí)現(xiàn)某種可視化調(diào)試的時(shí)候,我們就可以使用Gizmo類(lèi)。所以的Gizmo繪制都需要在OnDrawGizmos或OnDrawGizmosSelected函數(shù)里完成。從這兩個(gè)函數(shù)的名稱(chēng)我們就可以看出它們的區(qū)別,OnDrawGizmos在每一幀都調(diào)用,所有在Gizmos里渲染的Gizmo都將被渲染,而OnDrawGizmosSelected僅在腳本附加的物體被選中時(shí)渲染。好了,在了解了Gizmos的基本概念和用法后,我們回到我們的游戲中。我們剛剛提到,我們需要一種方法來(lái)生成區(qū)域以便于我們可以使用GridNode類(lèi)來(lái)描述每個(gè)區(qū)域的屬性,那么具體怎么做呢?其實(shí)思路就是在地圖上畫(huà)出網(wǎng)格,這樣網(wǎng)格便可以將整個(gè)地圖分割成不同的區(qū)域,然后我們就可以使用GridNode來(lái)描述每個(gè)區(qū)域的屬性啦。好了,下面我們來(lái)看具體的腳本:
using UnityEngine; using System.Collections; public class GridMap : MonoBehaviour { public static GridMap Instance=null; public int MapSizeX; public int MapSizeZ; [HideInInspector] public GameObject[] mNodes; [HideInInspector] public GameObject[] mPaths; void Awake() { Instance=this; mNodes=GameObject.FindGameObjectsWithTag("GridNode"); mPaths=GameObject.FindGameObjectsWithTag("PathNode"); } void DrawGrid() { Gizmos.color=Color.blue; for(int i=0;i<=MapSizeX;i++) { Gizmos.DrawLine(new Vector3(i,0,0),new Vector3(i,MapSizeZ,0)); } for(int j=0;j<=MapSizeZ;j++) { Gizmos.DrawLine(new Vector3(0,j,0),new Vector3(MapSizeX,j,0)); } } void DrawColor() { if(mNodes==null) return; foreach(GameObject go in mNodes) { Vector3 mPos=go.transform.position; if(go.GetComponent<GridNode>()!=null){ if(go.GetComponent<GridNode>().GridNodeType==GridNode.NodeType.CanPlace){ Gizmos.color=Color.green; }else if(go.GetComponent<GridNode>().GridNodeType==GridNode.NodeType.CantPlace){ Gizmos.color=Color.red; } Gizmos.DrawCube(mPos,new Vector3(1,1,1)); } } } void DrawPath() { Gizmos.color=Color.white; if(mPaths==null) return; foreach(GameObject go in mPaths) { if(go.GetComponent<PathNode>()!=null){ PathNode node=go.GetComponent<PathNode>(); if(node.ThatNode!=null){ Gizmos.DrawLine(node.transform.position,node.ThatNode.transform.position); } } } } void OnDrawGizmos() { DrawGrid(); DrawColor(); DrawPath(); } }
在這段腳本中,我們首先定義了兩個(gè)int類(lèi)型的變量MapSizeX,MapSizeZ,這兩個(gè)變量分別用來(lái)表示需要繪制網(wǎng)格的大小。下面我們來(lái)重點(diǎn)關(guān)注OnDrawGizmos方法,在這個(gè)方法中我們定義了3個(gè)方法DrawGrid、DrawColor和DrawPath。其中DrawGrid方法負(fù)責(zé)繪制地圖網(wǎng)格,DrawColor方法負(fù)責(zé)繪制地圖區(qū)域、DrawPath方法負(fù)責(zé)繪制敵人尋路路徑。我們首先來(lái)說(shuō)DrawGrid,DrawGrid負(fù)責(zé)繪制地圖網(wǎng)格,默認(rèn)從原點(diǎn)開(kāi)始繪制,要繪制網(wǎng)格只需要繪制交錯(cuò)的橫線和豎線即可,這里我們使用的Gizmos類(lèi)下的DrawLine方法我們首先在場(chǎng)景中創(chuàng)建一個(gè)MeshRoot的空物體,將GridMap腳本附加到該物體上,我們下面來(lái)看看繪制的效果:
[img]http://img.blog.csdn.net/20150106225424442?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWlueXVhbnBlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
因?yàn)镚izmos為我們提供了可視化的調(diào)試功能,因此我們可以直接在編輯器窗口中看到實(shí)際的效果,這樣我們就利用Unity繪制出了地圖的網(wǎng)格。為了讓地圖的左下角和場(chǎng)景原點(diǎn)能夠完全匹配,博主這里寫(xiě)了一個(gè)簡(jiǎn)單的工具類(lèi)AutoPlace來(lái)實(shí)現(xiàn)地圖的位置計(jì)算和調(diào)整:
using UnityEngine; using System.Collections; public class AutoPlace : MonoBehaviour { //精靈渲染器 private SpriteRenderer mRenderer; //精靈寬度 private float mSpriteWidth; //精靈高度 private float mSpriteHeight; void Start () { mRenderer=GetComponent<SpriteRenderer>(); //計(jì)算精靈的實(shí)際大小 mSpriteWidth=mRenderer.sprite.bounds.size.x * transform.localScale.x; mSpriteHeight=mRenderer.sprite.bounds.size.y * transform.localScale.y; //自動(dòng)調(diào)整精靈的位置 transform.position=new Vector3(mSpriteWidth/2,mSpriteHeight/2,0); } }
好了,下面我們來(lái)繼續(xù)講解地圖中區(qū)域的生成。什么是地圖中的區(qū)域呢?在塔防游戲中玩家通常情況下都只能在可以放置防守單位的區(qū)域放置防守的單位,那么可以放置防守單位的這些地方就是我們接下來(lái)要來(lái)研究的區(qū)域。我們首先需要根據(jù)第一步繪制的網(wǎng)格,為每一個(gè)網(wǎng)格單元?jiǎng)?chuàng)建一個(gè)空物體NodeObject,并為該物體附加GridNode腳本,如果該物體所在的位置在地圖上是可以放置防守單位,那么我們就將其GridNodeType設(shè)為CanPlace,否則就設(shè)為CantPlace。其實(shí)博主在這里是更喜歡用動(dòng)態(tài)生成的方式來(lái)為每個(gè)網(wǎng)格單元添加區(qū)域?qū)傩缘模贿^(guò)這里我們?yōu)榱藢⑦^(guò)程講明白,索性就手動(dòng)創(chuàng)建吧!哈哈,可是博主居然手動(dòng)創(chuàng)建了96個(gè)空物體,想想都覺(jué)得醉了啊。好了,我們這里需要給每個(gè)NodeObject設(shè)置一個(gè)GridNode的Tag,這樣我們可以在程序中通過(guò)Tag來(lái)獲取所有的NodeObject。最后,我們將這些NodeObject全部放到MeshRoot這個(gè)節(jié)點(diǎn)下面,使其成為MeshRoot的子節(jié)點(diǎn)。下面呢,我們繼續(xù)回到GridMap腳本中的DrawColor方法中,我們?cè)谀_本的Awake方法中首先獲取所有的NodeObject,然后根據(jù)每一個(gè)NodeObject對(duì)象附加的GridNode腳本,來(lái)判斷這個(gè)網(wǎng)格單元是可以放置防守單位還是不可以放置防守單位,如果可以放置防守單位就用綠色繪制一個(gè)Cube,如果不可以放置防守單位就用紅色繪制一個(gè)Cube,這樣我們編輯器中就可以根據(jù)顏色來(lái)區(qū)分不同的區(qū)域了。好了,我們下面來(lái)看看實(shí)際的效果:
[img]http://img.blog.csdn.net/20150106233924796?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWlueXVhbnBlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
好了,現(xiàn)在大家可以很明確的看到整個(gè)地圖中區(qū)域的分布,紅色的部分為不可放置防守單位的區(qū)域,綠色的部分為可以放置防守單位區(qū)域。大家應(yīng)該注意到紅色的區(qū)域中有條白色的線,這條線呢其實(shí)就是敵人的尋路路徑。那么好下面我們就來(lái)講述敵人尋路路徑的生成。相比網(wǎng)格和區(qū)域的生成,路徑的生成要簡(jiǎn)單許多。因?yàn)槁窂街恍枰P(guān)注起點(diǎn)、終點(diǎn)和節(jié)點(diǎn)即可。具體怎么做呢,首先我們?cè)趫?chǎng)景中新建一個(gè)空物體命名為PathRoot,接下來(lái)我們?cè)诩t色區(qū)域中分別為起點(diǎn)、終點(diǎn)和節(jié)點(diǎn)建立一個(gè)空物體,命名為PathNode,并設(shè)置其Tag為PathNode。
好了,接下來(lái),我們?cè)賮?lái)一起看一個(gè)叫做PathNode的腳本,這個(gè)腳本的作用是描述各個(gè)路徑節(jié)點(diǎn)的關(guān)系,類(lèi)似于鏈表的結(jié)構(gòu):
using UnityEngine; using System.Collections; public class PathNode : MonoBehaviour { public PathNode ThisNode; public PathNode ThatNode; public void SetNode(PathNode _node) { if(ThatNode!=null){ ThatNode.ThisNode=null; ThatNode=_node; _node.ThisNode=this; } } }
在這段腳本中,我們讓ThisNode指向節(jié)點(diǎn)自身,ThatNode指向下一個(gè)節(jié)點(diǎn),并提供了一個(gè)設(shè)置下一個(gè)節(jié)點(diǎn)的方法SetNode。現(xiàn)在,我們將這個(gè)腳本附加到各個(gè)PathNode上,通過(guò)編輯器可以快速地為每個(gè)節(jié)點(diǎn)指定ThisNode和ThatNode。那么,現(xiàn)在各個(gè)路徑節(jié)點(diǎn)的關(guān)系我們已經(jīng)很清楚了,接下來(lái)要做的是事情就是利用Gizmos將路徑畫(huà)出來(lái),怎么畫(huà)呢?從當(dāng)前節(jié)點(diǎn)指向下一個(gè)節(jié)點(diǎn)就可以了?,F(xiàn)在我們來(lái)看看DrawPath方法具體都做了什么:
void DrawPath() { Gizmos.color=Color.white; if(mPaths==null) return; foreach(GameObject go in mPaths) { if(go.GetComponent<PathNode>()!=null){ PathNode node=go.GetComponent<PathNode>(); if(node.ThatNode!=null){ Gizmos.DrawLine(node.transform.position,node.ThatNode.transform.position); } Gizmos.DrawCube(node.transform.position,new Vector3(0.25F,0.25F,0.25F)); } } }
相信大家都明白了吧,我們首先根據(jù)Tag獲取了全部的PathNode對(duì)象,然后根據(jù)PathNode腳本繪制了每個(gè)節(jié)點(diǎn)指向下一個(gè)節(jié)點(diǎn)的線段,同時(shí)為該節(jié)點(diǎn)繪制一個(gè)小Cube。好了,我們來(lái)看看最終的效果:
[img]http://img.blog.csdn.net/20150107001554894?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWlueXVhbnBlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
到現(xiàn)在為止,所有的關(guān)于地圖的內(nèi)容都講解完了,我們來(lái)簡(jiǎn)單總結(jié)下,在這一部分,我們主要學(xué)習(xí)了可視化輔助類(lèi)Gizmos在繪制網(wǎng)格、區(qū)域、路徑等方面的應(yīng)用,主要利用了DrawLine和DrawCube這兩個(gè)方法。
好了,這個(gè)項(xiàng)目的內(nèi)容比較多啦,因此博主決定將敵人篇、防守單位篇放在下一篇文章中來(lái)為大家講解,因?yàn)樵谝黄恼轮袑?xiě)完的話,不僅博主寫(xiě)起來(lái)會(huì)比較累,大家讀起來(lái)會(huì)更累啊,所以今天的內(nèi)容就是這樣啦,希望大家喜歡??!最后為大家送上今天的項(xiàng)目演示:
[img]http://img.blog.csdn.net/20150107003715142
每日箴言:痛苦也好,錯(cuò)誤也罷,正是背負(fù)著這些,我們才能一步一步到達(dá)未知的前方,不是嗎?
[img]http://img.blog.csdn.net/20150107005423776?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcWlueXVhbnBlaQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
喜歡我的博客請(qǐng)記住我的名字:秦元培,我的博客地址是blog.csdn.net/qinyuanpei
轉(zhuǎn)載請(qǐng)注明出處,本文作者:秦元培, 本文出處:http://blog.csdn.net/qinyuanpei/article/details/42394949??
??
?
??
相關(guān)案例查看更多
相關(guān)閱讀
- 小程序開(kāi)發(fā)費(fèi)用
- 報(bào)廢車(chē)拆解管理系統(tǒng)
- 網(wǎng)站建設(shè)特性
- 網(wǎng)站建設(shè)專(zhuān)業(yè)品牌
- APP
- 云南手機(jī)網(wǎng)站建設(shè)
- 網(wǎng)站建設(shè)制作
- 大理網(wǎng)站建設(shè)公司
- 小程序開(kāi)發(fā)排名前十名
- 汽車(chē)拆解管理系統(tǒng)
- 網(wǎng)站建設(shè)快速優(yōu)化
- 云南網(wǎng)站建設(shè) 網(wǎng)絡(luò)服務(wù)
- 搜索排名
- 小程序表單
- 開(kāi)通微信小程序被騙
- 高端網(wǎng)站建設(shè)公司
- 服務(wù)器
- uniapp開(kāi)發(fā)小程序
- 云南網(wǎng)站設(shè)計(jì)
- 云南小程序開(kāi)發(fā)報(bào)價(jià)
- 小程序用戶(hù)登錄
- 云南小程序開(kāi)發(fā)制作公司
- 云南軟件定制公司
- 云南小程序設(shè)計(jì)
- 貴州小程序開(kāi)發(fā)
- 電商網(wǎng)站建設(shè)
- 云南省建設(shè)廳網(wǎng)站官網(wǎng)
- 手機(jī)網(wǎng)站建設(shè)
- web服務(wù)
- 昆明軟件公司