Unity3D技术之塔防类项目详解(一)
更新时间:2024-05-09 11:53:01 阅读量: 综合文库 文档下载
Unity3D技术之塔防类项目详解(一)
通常意义上讲,塔防游戏是指一类在地图上建造炮台或者类似建筑物来阻止敌人进攻的策略类游戏。从这个概念中,我们可以快速地抽离出来三个元素,即地图(场景)、敌人、炮台(防守单位)。当我们抽离出来这样三个元素后,现在塔防游戏就变成了这样的一种描述,即敌人按照地图中设计的路径进攻,玩家利用防守单位进行防守的一类策略游戏。经典的塔防游戏有哪些呢?比如我们最为熟悉的《植物大战僵尸》、《保卫萝卜》都是塔防类游戏的经典游戏。如果我们将塔防游戏中的防守单位的范围扩大到玩家,那么像《英雄联盟》这样的游戏同样是可以称之为塔防游戏的,因为敌我阵营的最终目的都是要摧毁敌方的防御塔,只是敌我双方都从炮台或者怪物变成了有血有肉的人物,加之角色扮演(RPG)和即时战略(RTS)等元素的混合渗透,使得这样的游戏从单纯的塔防游戏变成了一款可玩度极高的游戏(天啊,我居然在夸这个游戏.....)。好了,那么我们就来尝试着做出一个简单的塔防游戏吧,注意是简单的塔防游戏哦,既然塔防游戏的三个要素是地图、敌人和防守单位,那么我们就从这三个方面来着手设计这个游戏吧!在本篇文章中,我们将用到下面的知识:
? ? ? ? ?
Unity2D中的Sprite动画
Unity3D中的可视化辅助类Gizmos 塔防游戏中敌人按路径寻路的实现 Unity3D uGUI的初步探索 简单的AI算法
一、地图篇
地图是一个塔防游戏中玩家最为关注的地方,因为地图和敌人将直接影响到玩家的策略。如图是从《保卫萝卜》游戏中提取的一张游戏地图。在这张地图中我们可以清楚看到怪物进攻的路径,怪物将沿着地图中的路径向我方防守单位发起攻击。那么,在游戏中,我们该怎样确定怪物的攻击路径呢?首先我们可以对地图进行下分析,在地图中基本上基本上只有两种类型的区域,即可以放置防守单位的区域和不可放置防守单位的区域两种。由此我们可以设计出下面的结构:
[csharp] view plaincopy
1. using UnityEngine; 2. using System.Collections; 3.
4. [SerializeField]
5. public class GridNode : MonoBehaviour 6. {
7. public enum NodeType 8. {
9. CanPlace, 10. CantPlace 11. } 12.
13. public NodeType GridNodeType=NodeType.CanPlace; 14. }
可以看出,我们在GridNode类中定义了一个称为NodeType的枚举类型,这个枚举类型有两个值,CanPlace表示可以放置防守单位,CantPlace表示不可以放置防守单位。在GridNode类中只有一个NodeType类型的成员变量GridNodeType,该成员变量的默认值是CanPlace,即可以放置防守单位。那么,现在问题来了,我们找到了一种可以用来描述地图中不同区域的方法,可是这些区域在哪里呢?所以我们需要一种方法来生成这些区域。这里隆重向大家介绍Gizoms类,Gizmo是Unity中一个用于在场景视图可视化调试或辅助设置的工具类。简单的说,当我们需要在编辑器环境中实现某种可视化调试的时候,
我们就可以使用Gizmo类。所以的Gizmo绘制都需要在OnDrawGizmos或
OnDrawGizmosSelected函数里完成。从这两个函数的名称我们就可以看出它们的区别,OnDrawGizmos在每一帧都调用,所有在Gizmos里渲染的Gizmo都将被渲染,而
OnDrawGizmosSelected仅在脚本附加的物体被选中时渲染。好了,在了解了Gizmos的基本概念和用法后,我们回到我们的游戏中。我们刚刚提到,我们需要一种方法来生成区域以便于我们可以使用GridNode类来描述每个区域的属性,那么具体怎么做呢?其实思路就是在地图上画出网格,这样网格便可以将整个地图分割成不同的区域,然后我们就可以使用GridNode来描述每个区域的属性啦。好了,下面我们来看具体的脚本:
[csharp] view plaincopy
1. using UnityEngine; 2. using System.Collections; 3.
4. public class GridMap : MonoBehaviour { 5.
6. public static GridMap Instance=null; 7.
8. public int MapSizeX; 9. public int MapSizeZ; 10.
11. [HideInInspector]
12. public GameObject[] mNodes; 13. [HideInInspector]
14. public GameObject[] mPaths; 15.
16. void Awake() 17. {
18. Instance=this;
19. mNodes=GameObject.FindGameObjectsWithTag(\20. mPaths=GameObject.FindGameObjectsWithTag(\21. } 22.
23. void DrawGrid() 24. {
25. Gizmos.color=Color.blue; 26. for(int i=0;i<=MapSizeX;i++) 27. {
28. Gizmos.DrawLine(new Vector3(i,0,0),new Vector3(i,MapSizeZ,0)); 29. }
30. for(int j=0;j<=MapSizeZ;j++) 31. {
32. Gizmos.DrawLine(new Vector3(0,j,0),new Vector3(MapSizeX,j,0)); 33. } 34. } 35.
36. void DrawColor() 37. {
38. if(mNodes==null) return;
39. foreach(GameObject go in mNodes) 40. {
41. Vector3 mPos=go.transform.position; 42. if(go.GetComponent
43. if(go.GetComponent
if(go.GetComponent
48. Gizmos.DrawCube(mPos,new Vector3(1,1,1)); 49. } 50. } 51. } 52.
53. void DrawPath() 54. {
55. Gizmos.color=Color.white; 56. if(mPaths==null) return;
57. foreach(GameObject go in mPaths) 58. {
59. if(go.GetComponent
62. Gizmos.DrawLine(node.transform.position,node.ThatNode.transform.position); 63. } 64. } 65. } 66. } 67.
68. void OnDrawGizmos() 69. {
70. DrawGrid(); 71. DrawColor(); 72. DrawPath(); 73. } 74. 75. 76. }
文章出处【狗刨学习网】
在这段脚本中,我们首先定义了两个int类型的变量MapSizeX,MapSizeZ,这两个变量分别用来表示需要绘制网格的大小。下面我们来重点关注OnDrawGizmos方法,在这个方法中我们定义了3个方法DrawGrid、DrawColor和DrawPath。其中DrawGrid方法负责绘制地图网格,DrawColor方法负责绘制地图区域、DrawPath方法负责绘制敌人寻路路径。我们首先来说DrawGrid,DrawGrid负责绘制地图网格,默认从原点开始绘制,要绘制网格只需要绘制交错的横线和竖线即可,这里我们使用的Gizmos类下的DrawLine方法我们首先在场景中创建一个MeshRoot的空物体,将GridMap脚本附加到该物体上,我们下面来看看绘制的效果:
因为Gizmos为我们提供了可视化的调试功能,因此我们可以直接在编辑器窗口中看到实际的效果,这样我们就利用Unity绘制出了地图的网格。为了让地图的左下角和场景原点能够完全匹配,这里写了一个简单的工具类AutoPlace来实现地图的位置计算和调整:
[csharp] view plaincopy
1. using UnityEngine; 2. using System.Collections; 3.
4. public class AutoPlace : MonoBehaviour { 5.
6. //精灵渲染器
7. private SpriteRenderer mRenderer; 8. //精灵宽度
9. private float mSpriteWidth; 10. //精灵高度
11. private float mSpriteHeight; 12. 13.
14. void Start () 15. {
16. mRenderer=GetComponent
18. mSpriteWidth=mRenderer.sprite.bounds.size.x * transform.localScale.x; 19. mSpriteHeight=mRenderer.sprite.bounds.size.y * transform.localScale.y; 20. //自动调整精灵的位置
21. transform.position=new Vector3(mSpriteWidth/2,mSpriteHeight/2,0); 22. } 23. }
好了,下面我们来继续讲解地图中区域的生成。什么是地图中的区域呢?在塔防游戏中玩家通常情况下都只能在可以放置防守单位的区域放置防守的单位,那么可以放置防守单位的这些地方就是我们接下来要来研究的区域。我们首先需要根据第一步绘制的网格,为每一个网格单元创建一个空物体NodeObject,并为该物体附加GridNode脚本,如果该物体所在的位置在地图上是可以放置防守单位,那么我们就将其GridNodeType设为
CanPlace,否则就设为CantPlace。其实在这里是更喜欢用动态生成的方式来为每个网格单元添加区域属性的,不过这里我们为了将过程讲明白,索性就手动创建吧!哈哈,可是居然手动创建了96个空物体,想想都觉得醉了啊。好了,我们这里需要给每个
NodeObject设置一个GridNode的Tag,这样我们可以在程序中通过Tag来获取所有的NodeObject。最后,我们将这些NodeObject全部放到MeshRoot这个节点下面,使其成为MeshRoot的子节点。下面呢,我们继续回到GridMap脚本中的DrawColor方法中,我们在脚本的Awake方法中首先获取所有的NodeObject,然后根据每一个NodeObject对象附加的GridNode脚本,来判断这个网格单元是可以放置防守单位还是不可以放置防守单位,如果可以放置防守单位就用绿色绘制一个Cube,如果不可以放置防守单位就用红色绘制一个Cube,这样我们编辑器中就可以根据颜色来区分不同的区域了。好了,我们下面来看看实际的效果:
好了,现在大家可以很明确的看到整个地图中区域的分布,红色的部分为不可放置防守单位的区域,绿色的部分为可以放置防守单位区域。大家应该注意到红色的区域中有条白色的线,这条线呢其实就是敌人的寻路路径。那么好下面我们就来讲述敌人寻路路径的生成。相比网格和区域的生成,路径的生成要简单许多。因为路径只需要关注起点、终点和节点即可。具体怎么做呢,首先我们在场景中新建一个空物体命名为PathRoot,接下来我们在红色区域中分别为起点、终点和节点建立一个空物体,命名为PathNode,并设置其Tag为PathNode。
好了,接下来,我们再来一起看一个叫做PathNode的脚本,这个脚本的作用是描述各个路径节点的关系,类似于链表的结构:
[csharp] view plaincopy
1. using UnityEngine; 2. using System.Collections; 3.
4. public class PathNode : MonoBehaviour { 5.
6. public PathNode ThisNode; 7. public PathNode ThatNode; 8.
9. public void SetNode(PathNode _node) 10. {
11. if(ThatNode!=null){
12. ThatNode.ThisNode=null; 13. ThatNode=_node; 14. _node.ThisNode=this; 15. } 16. 17. } 18. 19. }
在这段脚本中,我们让ThisNode指向节点自身,ThatNode指向下一个节点,并提供了一个设置下一个节点的方法SetNode。现在,我们将这个脚本附加到各个PathNode上,通过编辑器可以快速地为每个节点指定ThisNode和ThatNode。那么,现在各个路径节点的关系我们已经很清楚了,接下来要做的是事情就是利用Gizmos将路径画出来,怎么画呢?从当前节点指向下一个节点就可以了。现在我们来看看DrawPath方法具体都做了什么:
[csharp] view plaincopy
1. void DrawPath() 2. {
3. Gizmos.color=Color.white; 4. if(mPaths==null) return;
5. foreach(GameObject go in mPaths) 6. {
7. if(go.GetComponent
10. Gizmos.DrawLine(node.transform.position,node.ThatNode.transform.position); 11. }
12. Gizmos.DrawCube(node.transform.position,new Vector3(0.25F,0.25F,0.25F)); 13. } 14. } 15. }
相信大家都明白了吧,我们首先根据Tag获取了全部的PathNode对象,然后根据PathNode脚本绘制了每个节点指向下一个节点的线段,同时为该节点绘制一个小Cube。好了,我们来看看最终的效果:
到现在为止,所有的关于地图的内容都讲解完了,我们来简单总结下,在这一部分,我们主要学习了可视化辅助类Gizmos在绘制网格、区域、路径等方面的应用,主要利用了DrawLine和DrawCube这两个方法。
好了,这个项目的内容比较多啦,因此决定将敌人篇、防守单位篇放在下一篇文章中来为大家讲解,因为在一篇文章中写完的话,不仅写起来会比较累,大家读起来会更累啊,所以今天的内容就是这样啦,希望大家喜欢啊!最后为大家送上今天的项目演示:
正在阅读:
Unity3D技术之塔防类项目详解(一)05-09
小学生防范性侵害宣传材料(整合)09-03
“两学一做”学习专题 98分05-18
诸暨市珍珠产业发展规划(2010—2015年) - 图文04-03
电工学与电子学 - 习题集(含答案)10-29
兰州大学本科生实践教学质量提升计划试行03-08
柠檬公主作文500字06-23
我是一本书作文550字07-10
高中经典优秀议论文800字01-07
网络设备通讯连接方式及网线接头的制作方法05-21
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 详解
- Unity3D
- 项目
- 技术
- 2018年中国律师事务所市场及行业调研报告目录
- 药物分析复习题
- 第四章 根的形态与结构
- 2014年一级建造师考试大纲(三门公共课+机电专业课)
- 水利建设项目经济评价
- CT诊断报告模板大全
- LED显示屏标书
- 关于泰勒公式的应用初探
- 小(一)型病险水库除险加固工程施工组织设计(投标)
- 电力公司装表接电项目竞赛试题库 全面的复习资料
- 选修2-1 1.1命题学案 - 图文
- 分式考点及典型例题分析(最全面)
- 750风机典型故障处理手册
- 人信地产公司人力资源管理手册
- 高等教育心理学 第十三章 群体心理与人际交往的调适模拟题
- 高三月考(化学)试题(附答案)
- 放射性事故应急处理预案
- 广东工业大学专业学位培养方案(2010年版) - 图文
- 安乡一中2017届高考语文考前冲刺练习(1---10) 学生(附答案) 龚
- 同等学力英语词汇表