[Unity3D]自己动手重制坦克舰队ArmadaTank(2)从碰撞说起
[Unity3D]自己动手重制坦克舰队ArmadaTank(2)从碰撞说起
在上一篇里我给出了重制的坦克舰队效果图和试玩程序。本篇介绍一下玩家坦克和敌方坦克碰撞问题。
我们需要什么样的碰撞
原版里,玩家与其它坦克碰撞时,玩家与对方都不能移动;而敌方坦克之间相互碰撞时,是无视碰撞直接穿透的。这些功能的实现需要一些特殊的设计。
需要注意到,坦克舰队里的坦克移动方式是以格为单位的,每次移动都会移动完整的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代表的方向(前后左右之一)是否有障碍物了。
public abstract class ObstacleDetector : MonoBehaviour {
public System.Collections.Generic.List<GameObject> obstacles;
void Awake()
{
if (obstacles == null)
{
obstacles = new System.Collections.Generic.List<GameObject>();
}
}
protected abstract void OnTriggerEnter(Collider other);
void OnTriggerExit(Collider other)
{
this.obstacles.Remove(other.gameObject);
}
public bool IsUnblocked()
{
for (int i = ; i < this.obstacles.Count; i++)
{
if(this.obstacles[i] != null && this.obstacles[i].collider.enabled)
{
return false;
}
}
return true;
}
}
敌方坦克的障碍物检测器
所有类型的敌方坦克的碰撞效果都相同,所以统一用下面的脚本:
public class EnemyObstacleDetector : ObstacleDetector {
protected override void OnTriggerEnter(Collider other)
{
var tag = other.tag;
if (tag != null)
{
if (tag == Tags.EnemyObstacleDetector) { return; }
if (tag == Tags.PlayerObstacleDetector) { return; }
// 对敌方坦克来说,另一个敌方坦克是可以穿透过去的,所以不应加入obstacles列表。
if (tag == Tags.EnemyObstacleDetectorCenter) { return; }
}
this.obstacles.Add(other.gameObject);
}
}
对敌方坦克来说,另一个敌方坦克是可以穿透过去的,所以不应加入obstacles列表。
如果碰到的是别人的cube(障碍物检测器),直接忽略即可。
玩家坦克的障碍物检测器
玩家坦克与敌方坦克的碰撞效果不同,所以需要单独处理。
public class PlayerObstacleDetector : ObstacleDetector
{ protected override void OnTriggerEnter(Collider other)
{
var tag = other.tag;
if (tag != null)
{
if (tag == Tags.EnemyObstacleDetector) { return; }
if (tag == Tags.PlayerObstacleDetector) { return; }
} this.obstacles.Add(other.gameObject);
} }
对玩家坦克来说,其它坦克是不能穿透的。
同样,如果碰到的是别人的cube(障碍物检测器),直接忽略即可。
继承与GetComponent
ObstacleDetector是一个抽象基类,敌方坦克和玩家坦克分别使用的是其子类EnemyObstacleDetector和PlayerObstacleDetector。此时,GetComponent<T>()仍然可以正常使用。它返回一个基类对象的引用,此引用实际指向的则是某个子类的对象。
这是一个通用的知识。
public class TankTranslate : MonoBehaviour
{
private System.Collections.Generic.Dictionary<TankToward, ObstacleDetector> obstacleDetectorDict; // Use this for initialization
void Start()
{
if (obstacleDetectorDict == null)
{ obstacleDetectorDict = new System.Collections.Generic.Dictionary<TankToward, ObstacleDetector>(); }
var names = new string[] { "forward", "backward", "left", "right" };
var direction = new TankToward[] { TankToward.Z, TankToward.NZ, TankToward.NX, TankToward.X };
for (int i = ; i < names.Length; i++)
{
var child = this.transform.FindChild(names[i]);
var script = child.GetComponent<ObstacleDetector>();
obstacleDetectorDict.Add(direction[i], script);
}
}
}
起火冒烟
坦克被击中会损失health值,视觉效果上我们用冒烟的浓度显示。
冒烟效果用particle System组件来做。

控制冒烟的浓度需要一个脚本。
public class TankSmoke : MonoBehaviour
{
public TankHealth tankHealthScript;
private float lastHealth; // Update is called once per frame
void Update()
{
if (lastHealth != tankHealthScript.health)
{
var lostHealth = (TankHealth.maxHealth - tankHealthScript.health);
if (lostHealth <= )
{
this.particleSystem.enableEmission = false;
}
else
{
this.particleSystem.Play();
this.particleSystem.enableEmission = true;
this.particleSystem.emissionRate = * lostHealth / TankHealth.maxHealth;
}
lastHealth = tankHealthScript.health;
}
}
}
原版坦克舰队里的冒烟素材图片是这样的:

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

如果您不了解Tiling和Offset的含义,可以参考这里(图文详解Unity3D中Material的Tiling和Offset是怎么回事)。
如果您需要项目源码请通过下方二维码捐赠10元并留下您的联系方式。
ps:感谢上次捐赠的人,虽然只有1人。此文作为回馈,但愿您满意。
pps:我更换了博客皮肤,自我感觉比较良好。
[Unity3D]自己动手重制坦克舰队ArmadaTank(2)从碰撞说起的更多相关文章
- [Unity3D]自己动手重制坦克舰队ArmadaTank
[Unity3D]自己动手重制坦克舰队ArmadaTank 我玩过一款坦克游戏ArmadaTank(坦克舰队),如下图所示 几个月前我尝试用Unity3D重制这款游戏,已经可以玩起来了.下面是在PC上 ...
- Xamarin.Forms之UserDialogs 重制版本
在 forms 里面,目前使用比较多的弹出组件是 Acr.UserDialogs ,但是这个组件有些小问题,比如 loading .hide 会同时把 toast 给一起关掉,android 下的 t ...
- 使用AndEngine重制《是男人就上一百层》
1.为什么还要做<是男人就上一百层> 一是在用Android原生API开发完<是男人就上一百层>以后,一直想体验一下用引擎开发游戏是个什么感觉,顺便也让游戏听上去高大上一些(使 ...
- 《杜增强讲Unity之Tanks坦克大战》8-子弹碰撞处理
8 子弹碰撞处理 为了处理子弹打到坦克的伤害我们在这里新建一个Shell.cs 子弹有两种情况,碰到坦克炸开,没有碰到坦克则过2s子弹销毁. void Start () { Destroy (game ...
- 重制AdvanceWars第一步 -- 搞定地图
首先来聊下高级战争吧Advance Wars,由任天堂旗下的Intelligent Systems开发的战棋游戏.初作诞生于GBA上,后来继续跟进了高战2黑洞崛,而后在下一代掌机DS上也出了三代续作高 ...
- 替换/重制Homebrew源
homebrew主要分两部分:git repo(位于GitHub)和二进制bottles(位于bintray),这两者在国内访问都不太顺畅.可以替换成国内的镜像,git repo国内镜像就比较多了,可 ...
- 微软重制Windows 1.0系统:祖师爷出山了
Windows官方推特在7月1日发布了一条很有趣的动态,“向大家介绍全新的Windows 1.0,带MS-DOS.时钟等”.配发的视频回顾了从Windows 1.0/3.1到Windows 10期间, ...
- BIT祝威博客汇总(Blog Index)
+BIT祝威+悄悄在此留下版了个权的信息说: 关于硬件(Hardware) <穿越计算机的迷雾>笔记 继电器是如何成为CPU的(1) 继电器是如何成为CPU的(2) 关于操作系统(Oper ...
- Unity3D 回合制 网上源码 目前还在研究构思
我们已将回合制的战斗模式讲解得很清楚了.那么,如果在Unity3D游戏中实现一个回合制游戏呢?我们从最简单的一对一模式来设计回合制游戏的原型.我们可以游戏的状态划分为下面三种状态: 1. ...
随机推荐
- “玲珑杯”ACM比赛 Round #7 B -- Capture(并查集+优先队列)
题意:初始时有个首都1,有n个操作 +V表示有一个新的城市连接到了V号城市 -V表示V号城市断开了连接,同时V的子城市也会断开连接 每次输出在每次操作后到首都1距离最远的城市编号,多个距离相同输出编号 ...
- font-family字体总结
宋体 SimSun黑体 SimHei微软雅黑 Microsoft YaHei微软正黑体 Microsoft JhengHei新宋体 NSimSun新细明体 PMingLiU细明体 MingLiU标楷体 ...
- windowsservice
1.创建 windows服务 项目 文件 -> 新建项目 -> 已安装的模板 -> Visual C# -> windows ,在右侧窗口选择"windows 服务 ...
- bootstrap入门
Bootstrap提供了如下重要的特性:❑一套完整的基础CSS插件.❑丰富的预定义样式表.❑一组基于jQuery的JS插件集.❑一个非常灵活的响应式(Responsive)栅格系统,并且崇尚移动先行( ...
- jQuery.zTree的跳坑记录
最近项目用到树型结构的交互,一开始并不打算选择zTree,为了项目进度我妥协了,这一妥协后果就是我进坑了,在2天的挣扎中,我终于跳出坑了,活了下来,有一些感慨纪录下来. 有一个业务场景需要2个树型结构 ...
- 根据url下载图片
如题:在我要动手写的时候才发现不搜索根本就是写不出来,究其原因还是因为基础不扎实,由于用的少已经没有能力写出了 首先需要获取url数据流,然后写进文件里即可,仅仅两步可惜我写不出来啊跟着搜来的内容写一 ...
- rake deploy ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to解决方法
需要修改项目中Rakefile文件的内容: 原始内容:system "git push origin #{deploy_branch}" 改后内容:system "git ...
- VMware Workstation 12序列号
VMware Workstation 12序列号:5A02H-AU243-TZJ49-GTC7K-3C61N 就好像之前微软,让大家用盗版一样,这样可以更快的拥有市场占有率.事实上,输入key即可永久 ...
- Python 爬虫6——Scrapy的安装和使用
前面我们简述了使用Python自带的urllib和urllib2库完成的一下爬取网页数据的操作,但其实能完成的功能都很简单,假如要进行复制的数据匹配和高效的操作,可以引入第三方的框架,例如Scrapy ...
- grunt 单独压缩多个js和css文件【转】
原文地址:http://xiaomiya.iteye.com/blog/2177877 使用grunt来压缩前端js,css文件 因为最近做的客户端本地项目有用到十几个js,js提交之前都需要压缩.用 ...