[Unity3D]自己动手重制坦克舰队ArmadaTank(2)从碰撞说起

在上一篇里我给出了重制的坦克舰队效果图和试玩程序。本篇介绍一下玩家坦克和敌方坦克碰撞问题。

+BIT祝威+悄悄在此留下版了个权的信息说:

我们需要什么样的碰撞

原版里,玩家与其它坦克碰撞时,玩家与对方都不能移动;而敌方坦克之间相互碰撞时,是无视碰撞直接穿透的。这些功能的实现需要一些特殊的设计。

需要注意到,坦克舰队里的坦克移动方式是以格为单位的,每次移动都会移动完整的1个单位。就是说,坦克在下图所示的D字母里面只有上边和下边两个停留位置,而不会在中间某处停留。

据此,我们给出实现方法。

障碍物检测法

在游戏画面中,看到的坦克是这样的:

但是为了实现原版的碰撞效果,我们给每个坦克都加上前后左右4个cube作为障碍物检测器(Obstacle Detector),让他们分别检测坦克所在位置的前后左右是否存在障碍物。

为了避免与子弹碰撞,我们把这些cube压扁了,其高度值只有0.1,而长宽仍为1。

此外,这些cube最终目的是检测坦克的存在,所以要给坦克本身一个Collider。

注意,这里我们让敌方坦克自身的Collider半径稍微小于0.5,以便后续的实现。

而玩家坦克的Collider半径保持0.5不变。

你会看到,这样的微小差异,会使敌方坦克之间的碰撞检测稍微迟钝一点,所以他们就可以相互穿透;而敌方坦克与玩家坦克之间仍然不可穿透。

Cube的作用

cube的作用是这样的:每个cube内部维护一个List<GameObject> obstacles列表,这个列表记录此检测器遇到的所有障碍物。每当触发OnTriggerEnter(Collider other)时,就把other指定的物体(障碍物)加入obstacles列表;每当触发OnTriggerExit(Collider other)时,就把other指定的物体(障碍物)移出obstacles列表。这样,就可以通过分析obstacles里的情况判断出此cube代表的方向(前后左右之一)是否有障碍物了。

 1 public abstract class ObstacleDetector : MonoBehaviour {
 2
 3     public System.Collections.Generic.List<GameObject> obstacles;
 4
 5     void Awake()
 6     {
 7         if (obstacles == null)
 8         {
 9             obstacles = new System.Collections.Generic.List<GameObject>();
10         }
11     }
12
13     protected abstract void OnTriggerEnter(Collider other);
14
15     void OnTriggerExit(Collider other)
16     {
17         this.obstacles.Remove(other.gameObject);
18     }
19
20     public bool IsUnblocked()
21     {
22         for (int i = 0; i < this.obstacles.Count; i++)
23         {
24             if(this.obstacles[i] != null && this.obstacles[i].collider.enabled)
25             {
26                 return false;
27             }
28         }
29         return true;
30     }
31 } 

敌方坦克的障碍物检测器

所有类型的敌方坦克的碰撞效果都相同,所以统一用下面的脚本:

 1 public class EnemyObstacleDetector : ObstacleDetector {
 2
 3     protected override void OnTriggerEnter(Collider other)
 4     {
 5         var tag = other.tag;
 6         if (tag != null)
 7         {
 8             if (tag == Tags.EnemyObstacleDetector) { return; }
 9             if (tag == Tags.PlayerObstacleDetector) { return; }
10             // 对敌方坦克来说,另一个敌方坦克是可以穿透过去的,所以不应加入obstacles列表。
11             if (tag == Tags.EnemyObstacleDetectorCenter) { return; }
12         }
13
14         this.obstacles.Add(other.gameObject);
15     }
16 }

对敌方坦克来说,另一个敌方坦克是可以穿透过去的,所以不应加入obstacles列表。

如果碰到的是别人的cube(障碍物检测器),直接忽略即可。

玩家坦克的障碍物检测器

玩家坦克与敌方坦克的碰撞效果不同,所以需要单独处理。

 1 public class PlayerObstacleDetector : ObstacleDetector
 2 {
 3
 4     protected override void OnTriggerEnter(Collider other)
 5     {
 6         var tag = other.tag;
 7         if (tag != null)
 8         {
 9             if (tag == Tags.EnemyObstacleDetector) { return; }
10             if (tag == Tags.PlayerObstacleDetector) { return; }
11         }
12
13         this.obstacles.Add(other.gameObject);
14     }
15
16 }

对玩家坦克来说,其它坦克是不能穿透的。

同样,如果碰到的是别人的cube(障碍物检测器),直接忽略即可。

继承与GetComponent

ObstacleDetector是一个抽象基类,敌方坦克和玩家坦克分别使用的是其子类EnemyObstacleDetector和PlayerObstacleDetector。此时,GetComponent<T>()仍然可以正常使用。它返回一个基类对象的引用,此引用实际指向的则是某个子类的对象。

这是一个通用的知识。

 1 public class TankTranslate : MonoBehaviour
 2 {
 3     private System.Collections.Generic.Dictionary<TankToward, ObstacleDetector> obstacleDetectorDict;
 4
 5     // Use this for initialization
 6     void Start()
 7     {
 8         if (obstacleDetectorDict == null)
 9         { obstacleDetectorDict = new System.Collections.Generic.Dictionary<TankToward, ObstacleDetector>(); }
10         var names = new string[] { "forward", "backward", "left", "right" };
11         var direction = new TankToward[] { TankToward.Z, TankToward.NZ, TankToward.NX, TankToward.X };
12         for (int i = 0; i < names.Length; i++)
13         {
14             var child = this.transform.FindChild(names[i]);
15             var script = child.GetComponent<ObstacleDetector>();
16             obstacleDetectorDict.Add(direction[i], script);
17         }
18     }
19 } 

起火冒烟

坦克被击中会损失health值,视觉效果上我们用冒烟的浓度显示。

冒烟效果用particle System组件来做。

控制冒烟的浓度需要一个脚本。

 1 public class TankSmoke : MonoBehaviour
 2 {
 3     public TankHealth tankHealthScript;
 4     private float lastHealth;
 5
 6     // Update is called once per frame
 7     void Update()
 8     {
 9         if (lastHealth != tankHealthScript.health)
10         {
11             var lostHealth = (TankHealth.maxHealth - tankHealthScript.health);
12             if (lostHealth <= 0)
13             {
14                 this.particleSystem.enableEmission = false;
15             }
16             else
17             {
18                 this.particleSystem.Play();
19                 this.particleSystem.enableEmission = true;
20                 this.particleSystem.emissionRate = 50 * lostHealth / TankHealth.maxHealth;
21             }
22             lastHealth = tankHealthScript.health;
23         }
24     }
25 }

原版坦克舰队里的冒烟素材图片是这样的:

为了正常显示,需要设置其Shader为Mobile Particles/Alpha Blended,并设置Tiling和Offset如下图所示。

如果您不了解Tiling和Offset的含义,可以参考这里(图文详解Unity3D中Material的Tiling和Offset是怎么回事)。

+BIT祝威+悄悄在此留下版了个权的信息说:

如果您需要项目源码请通过下方二维码捐赠10元并留下您的联系方式。

ps:感谢上次捐赠的人,虽然只有1人。此文作为回馈,但愿您满意。

pps:我更换了博客皮肤,自我感觉比较良好。

[Unity3D]自己动手重制坦克舰队ArmadaTank(2)从碰撞说起相关推荐

  1. Xamarin.Forms之UserDialogs 重制版本

    在 forms 里面,目前使用比较多的弹出组件是 Acr.UserDialogs ,但是这个组件有些小问题,比如 loading .hide 会同时把 toast 给一起关掉,android 下的 t ...

  2. 暗黑2 计算机中丢失,《暗黑破坏神2》部分源代码丢失不是事 暴雪照样重制

    2019年<暗黑破坏神>之父Max Schaefer曾表示他们丢失了<暗黑破坏神2>部分源代码,还有开发资料,艺术文档等.这是不可挽回的.致命的崩坏.暴雪将很难去重制一个< ...

  3. 2019/4/2更新 重制3617-6.17 增加918+6.21 二合一引导启动系统盘

    强烈推荐用小固态,不要用U盘,U盘容易出现错误.现在各种矿山倒塌,矿车一大堆,都带有16G的小固态或者msata之类的,刚好可以利用上. DS3617xs-6.17up3(重制UEFI版)介绍: 1. ...

  4. macbook系统占用硬盘大_解决macos双系统情况下重制macos系统导致windows系统盘一直占用的情况...

    由于mac的系统里面文件太多,又懒得整理就直接重制整个系统了,但是在重制的时候忘了件大事,我是双系统,还单独装了个windows10,刚刚重制完突然才想起还有个win10,这下觉得出大事了..心想占用 ...

  5. Ardupilot -- APM源码笔记(重制)~序言

    首先,本篇不会涉及到源码方面的解读跟指导,只是为了后续章节做一些说明,并讲讲写下这些博文的原因 说起无人机的话,应该很多人会想到大疆.亿航这些商业巨头,这样的产业能发展起来也跟无人机代码开源有关.从微 ...

  6. 粉丝用开源游戏引擎重制超级马里奥 64

    <超级马里奥64>的忠实粉丝Aryok Piñera正利用开源游戏引擎Blender Game Engine重制游戏.Blender Game Engine是 开源3D绘图软件Blende ...

  7. unity3D期末大作业,坦克射击游戏

    unity3D期末大作业,坦克射击游戏 坦克射击游戏,可以发射子弹打击物体,坦克可以撞碎墙壁,树木,有背景音效详情如下动态图:(下载链接在文章末) 制作过程: 首先,从Asset Store中下载并i ...

  8. 魔兽服务器重置稀有刷新,魔兽世界8.0重制阿拉希稀有坐标和分布图 重制阿拉希稀有坐标...

    为各位带来魔兽世界8.0重制阿拉希稀有坐标和分布图,新版本中这样稀有怪可以掉落各种稀有坐骑和宠物道具,下面我们就来看一看魔兽世界8.0重制阿拉希稀有坐标吧,希望对大家有所参考. 魔兽世界8.0重制阿拉 ...

  9. Axure 9 实战案例,动态面板的应用 4.1,省市区三级联动下拉菜单(重制简易版)

    前言 Hello!欢迎来到Axure 9 实战案例教程专栏. 本次课程我们继续来学习一下,动态面板的应用.本篇我们来讲解一下,如何绘制省市区联动下拉菜单(重新撰写简易版). 下拉菜单初稿 为了节省时间 ...

最新文章

  1. MATLAB错误:没有为类’struct’的值定义函数’subsindex’
  2. linux文件系统基本知识
  3. 总有个短信发来一行乱码_个别收到的短信乱码,有什么办法还原么。。。
  4. 实时OLAP分析利器Druid介绍
  5. 机器学习——贝叶斯分类器
  6. 图片或文字或box垂直居中
  7. 一个肥皂泡的破灭(组图)
  8. Douglas Peucker算法的C#实现
  9. 关于3Q大战和反垄断
  10. jQuery API/1.1.1/CSS
  11. 一张图秒懂Android事件分发机制
  12. 智慧树python第三章答案_智慧树Python语言应用第三单元章节测试答案选修课网课慕课答案...
  13. 经典排序算法之:堆排序
  14. BT面板静态文件镜像库v7.1.0
  15. matlab在图片上写字后保存
  16. 编写一个程序,计算1000以内不能被7整除的数值和
  17. epub电子书如何用IOS苹果手机打开?
  18. RouterOS配置端口映射的方法
  19. go语言:环境变量GOPROXY和GO111MODULE设置
  20. 燕青遇故人 ---《水浒传》中比较有诗意的章节

热门文章

  1. HANA_SQL常见错误代码
  2. Html事件change,了解change事件
  3. 找人才更高效?招聘小程序会是企业的最佳选择!
  4. 哈希表(散列表)介绍
  5. Docker镜像源修改
  6. 电脑有哪些常用快捷键?70个电脑常用的快捷键大全
  7. Microsoft Visual Studio 2008序列号
  8. 台湾第三方支付平台欧付宝参与臺大…
  9. google html5 摄像头,chrome html5如何调用摄像头?
  10. java判断五张牌中有一对,五张同花顺概率,52张扑克牌,任取5张牌,求出现一对、两对、同花顺的概率。 请帮忙解决一下这道概率题,求详细的列出式......