博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[Unity3D]自己动手重制坦克舰队ArmadaTank(2)从碰撞说起
阅读量:7282 次
发布时间:2019-06-30

本文共 4932 字,大约阅读时间需要 16 分钟。

[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
obstacles; 4 5 void Awake() 6 { 7 if (obstacles == null) 8 { 9 obstacles = new System.Collections.Generic.List
();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是一个抽象基类,敌方坦克和玩家坦克分别使用的是其子类EnemyObstacleDetectorPlayerObstacleDetector。此时,GetComponent<T>()仍然可以正常使用。它返回一个基类对象的引用,此引用实际指向的则是某个子类的对象。

这是一个通用的知识。

1 public class TankTranslate : MonoBehaviour 2 { 3     private System.Collections.Generic.Dictionary
obstacleDetectorDict; 4 5 // Use this for initialization 6 void Start() 7 { 8 if (obstacleDetectorDict == null) 9 { obstacleDetectorDict = new System.Collections.Generic.Dictionary
(); }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
();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             else17             {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的含义,可以参考这里()。

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

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

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

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

 

转载地址:http://jqzjm.baihongyu.com/

你可能感兴趣的文章
windows10序列号
查看>>
进程间的通信---信号量(semget,semctl,semop)
查看>>
基于大数据技术之电视收视率企业项目实战(hadoop+Spark)
查看>>
Java开发环境的搭建(windows)
查看>>
Hello Metro:Windows 8下首个App
查看>>
vim编辑器
查看>>
html表格学习
查看>>
python数据类型 循环语句 循环关键字
查看>>
利用管道完成数据从MySQL到Redis的高效迁移
查看>>
Unity Android真机调试
查看>>
Python使用urllib、urllib2捉取网页内容
查看>>
轻量级的bug管理平台对比
查看>>
keepalived高可用部署
查看>>
linux工程师技术-01 -SElinux、配置高级连接、防火墙管理策略
查看>>
tomcat部署乱码
查看>>
网络安全小实验
查看>>
1月30日
查看>>
forClass
查看>>
每一个关注支付的人都在这里
查看>>
百晓生带你玩转linux系统服务搭建系列-----搭建DHCP服务和中继代理
查看>>