自制Unity小游戏TankHero-2D(2)制作敌方坦克
自制Unity小游戏TankHero-2D(2)制作敌方坦克
我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm)这个游戏制作的。仅为学习Unity之用。图片大部分是自己画的,少数是从网上搜来的。您可以到我的github页面(https://github.com/bitzhuwei/TankHero-2D)上得到工程源码。

本篇主要记录制作敌方坦克(Tank1)的一些重点。
原本制作敌方坦克是很简单的,只要把TankHero复制一份,改改贴图就差不多了。不过考虑到代码的简洁和可重用,本篇花了些心思在重构上。
关于自定义鼠标箭头
上一篇介绍了如何自定义鼠标箭头的事。这里补个漏。经过上一篇的研究,已经可以显示自定义的鼠标样式了,但是原有的鼠标箭头仍然存在,这怎么办?容易,只需制作一个1*1像素的全透明的png图片,赋给Default Cursor即可。实际上就是让默认鼠标样式透明掉。

敌方坦克模型

这个模型依旧是用PPT做的。SmartArt+“形状”解决问题。具体技巧可参考上一篇。


敌方坦克结构

如上图所示,使用Duplicate从TankHero复制一个,重命名为Tank1。Tank1就是我们要做的敌方坦克了。其炮塔、底座、炮弹起始点这些结构都是一样的。
重构坦克运动代码
玩家坦克和敌方坦克有很多共同点,比如坦克对象的结构。也有一些特征(移动、旋转、开炮等)既相似又不同。具体来说,玩家坦克是由鼠标键盘指挥的,敌方坦克则要由AI指挥。指挥者不同,但是指挥的效果都是移动旋转开炮,是可以用同样的代码处理的。所以我在这里抽象出一个专门保存指挥信息的Movement类,这样就隔开了指挥者与执行者。

PlayerMovement接收用户输入的信息,存到基类的字段。Tank1Movement用AI获取指挥信息,存到基类的字段。


这样一来,在其它地方(不同类型的坦克的炮塔、底座)就都可以用 Movement m = this.GetComponentXXX<PlayerMovement>(); 这样统一的方式获取平移、旋转、目标、目的地等信息了。
下面我们来详细介绍。
底座的旋转和轮子滚动
两种坦克的底座部分,只有轮子滚动部分是不同的。两者使用的脚本则都是TankBaseRotation和WheelMovement。

WheelMovement代码没有任何改变,只不过在Inspector里的Wheels数组元素不同而已。
在TankBaseRotation中则出现了这样的代码:
private Movement movementScript;
void Awake()
{
movementScript = this.GetComponentInParent<Movement> ();
}
有了 movementScript 就可以得到坦克的移动方向 movementScript.baseDirection ,就可以更新坦克底座的旋转角度了。
void Update () {
if (movementScript == null) { return; }
var angle = Mathf.Atan2 (movementScript.baseDirection.y, movementScript.baseDirection.x) * Mathf.Rad2Deg;
if (Mathf.Abs(angle - this.targetAngle) > 0.01f)
{
this.targetAngle = angle;
this.targetRotation = Quaternion.Euler (, , angle);
}
this.transform.rotation = Quaternion.Slerp (
this.transform.rotation,
Quaternion.Euler (, , angle),
rotationSpeed * Time.deltaTime);
}
炮塔的旋转和武器管理
这样就无需为两种坦克写两套旋转底座的脚本了。以后添加了新型坦克也仍然只需这一个脚本。

TankHero和Tank1的炮塔旋转中心(Rotation Center)和武器(Weapons)不同,但他们使用了相同的脚本(TankHeadRotation和WeaponManager)。这两个脚本中也都有如下的代码。
private Movement movementScript;
void Awake()
{
this.movementScript = this.GetComponentInParent<Movement> ();
}
在movementScript中保存着目标的位置( fireTarget ),旋转炮塔也很容易。
void Update () {
if (this.movementScript == null) { return; }
var y = this.movementScript.fireTarget.y - this.transform.position.y;
var x = this.movementScript.fireTarget.x - this.transform.position.x;
if (Mathf.Abs(y) > Quaternion.kEpsilon || Mathf.Abs(x) > Quaternion.kEpsilon)
{
this.targetAngle = Mathf.Atan2(y, x) * Mathf.Rad2Deg;
var angle = this.targetAngle - this.transform.rotation.eulerAngles.z;
this.transform.RotateAround (this.rotationCenter.position, new Vector3 (, , ), angle);
}
}
TankHero是玩家用鼠标开炮的,敌方坦克是自动开炮的。用 autoFire 标记坦克是否自动开炮即可。
void Update () {
passedInterval += Time.deltaTime * ;
if (passedInterval >= currentWeaponConfig.interval)
{
if (this.autoFire || Input.GetButton("Fire1"))
{
passedInterval = ;
var bullet = Instantiate(currentBullet, bulletStartPosition.position, this.transform.rotation) as Transform;
bullet.renderer.enabled = true;
var bulletFly = bullet.GetComponent<BulletFly>();
bulletFly.undying = false;
bulletFly.velocity = currentWeaponConfig.velocity;
bulletFly.shooter = this.gameObject;
bulletFly.targetPosition = movementScript.fireTarget;
}
}
}
武器系统

有了新的坦克,我们需要给它设计新的武器。只需Duplicate一下NormalBulletWeapon,再在WeaponConfig组件里调整一下敌方坦克武器的参数(炮弹速度调慢一点,不然敌人就太厉害了)。将新武器EnemyNormalBulletWeapon赋给Tank1的炮塔即可。

炮弹仍然是原有的那个,只需换一个贴图即可。

多种炮弹
玩过(http://game.kid.qq.com/a/20140221/028931.htm)的会发现有多种炮弹。其速度、攻击形式都不一样。

就是说,在不同类型的炮弹碰撞到某物时,会发生不同的事。因此我对控制炮弹飞行的脚本进行了抽象,在具体的子类里编写 Trigger 碰撞事件,用以处理不同的炮弹。

注意:如果在子类(NormalBulletFly)你添加了 void Update(); 方法,那么Unity就不会调用父类(BulletFly)的Update方法了。这对 Awake 等都适用。就是说,Unity引擎只查找那些在继承层次上离MonoBehaviour最远的事件函数,找到之后就不再理会其它层上的同名函数了。
为什么是最远的?因为一个gameobject,其具有NormalBulletFly这个组件,意思是此gameobject拥有一个类型为NormalBulletFly的实例。很自然地,Unity会选中此类型的方法表中的Update方法。只有在NormalBulletFly中不存在时,才会轮到其父类的方法表。
当然目前为止只有1种炮弹,所以只有1个具体的NormalBulletFly脚本。这样,以后无论有多少种炮弹,只需一个Bullet的prefab即可。

总结
坦克的运动和炮弹的攻击,我都进行了重构。重构的目的是为了将重复的代码(平移、旋转、开炮、飞行)合并到一处,不同的代码(用户输入vs AI控制,不同的攻击方式)分别写如不同的脚本。重构的技术就是面向对象设计。
您可以到我的github页面(https://github.com/bitzhuwei/TankHero-2D)上得到工程源码。
请多多指教~
自制Unity小游戏TankHero-2D(2)制作敌方坦克的更多相关文章
- 自制Unity小游戏TankHero-2D(1)制作主角坦克
自制Unity小游戏TankHero-2D(1)制作主角坦克 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm)这个游戏制作的. ...
- 自制Unity小游戏TankHero-2D(3)开始玩起来
自制Unity小游戏TankHero-2D(3)开始玩起来 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm)这个游戏制作的.仅 ...
- 自制Unity小游戏TankHero-2D(5)声音+爆炸+场景切换+武器弹药
自制Unity小游戏TankHero-2D(5)声音+爆炸+场景切换+武器弹药 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm ...
- 自制Unity小游戏TankHero-2D(4)关卡+小地图图标+碰撞条件分析
自制Unity小游戏TankHero-2D(4)关卡+小地图图标+碰撞条件分析 我在做这样一个坦克游戏,是仿照(http://game.kid.qq.com/a/20140221/028931.htm ...
- 教你用Python自制拼图小游戏,一起来制作吧
摘要: 本文主要为大家详细介绍了python实现拼图小游戏,文中还有示例代码介绍,感兴趣的小伙伴们可以参考一下. 开发工具 Python版本:3.6.4 相关模块: pygame模块: 以及一些Pyt ...
- Unity小游戏制作 - 暗影随行
用Unity制作小游戏 - 暗影惊吓 最近玩了一个小游戏,叫做暗影惊吓,虽然是一个十分简单的小游戏,但是感觉还是十分有趣的.这里就用Unity来实现一个类似的游戏. 项目源码:DarkFollow 主 ...
- Java自制人机小游戏——————————剪刀、石头、布
package com.hello.test; import java.util.Scanner; public class TestGame { public static void main(St ...
- c++小游戏--五子棋
大家好,我是芝麻狐! 这是我自制的小游戏,目前仅支持devc++. 如果你没有c++软件, 请打开网站GDB online Debugger | Compiler - Code, Compile, R ...
- c++小游戏———扫雷
大家好,我是芝麻狐! 这是我自制的小游戏,目前仅支持devc++. 如果你没有c++软件, 请打开网站GDB online Debugger | Compiler - Code, Compile, R ...
随机推荐
- 解决Tomcat数据连接池无法释放
近段时间,公司的检测中心报表系统(SMC)的开发人员时不时找到我,说用户老是出现无法登录的情况.前些日子因为手头上 有Jboss集群的测试工作,发现用户不能登录时,都是在Tomcat中将这个项目Rel ...
- hashcode深入理解
带着问题去理解: 1. Object类HashCode方法是如何实现的,和String类有什么区别? 2.HashCode和Equals之间的关系? 一.hashCode作用 hashCode方法返回 ...
- MySQL Create Table创建表
表的创建命令需要: 表的名称 字段名称 定义每个字段(类型.长度等) 语法 下面是通用的SQL语法用来创建MySQL表: CREATE TABLE table_name (column_name co ...
- 升级到iOS9之后的相关适配
iOS9AdaptationTips(iOS9开发学习交流群:458884057) iOS9适配系列教程[中文在页面下方]转自@iOS程序犭袁 (截至2015年9月26日共有10篇,后续还将持续更新. ...
- tomcat详情
[转载]http://grass51.blog.51cto.com/4356355/1123400
- Android adb命令 一
adb的全称为Android Debug Bridge,就是起到调试桥的作用.通过adb我们可以在Eclipse中方面通过DDMS来调试Android程序,说白了就是debug工具.adb的工作方式比 ...
- FMDB读取Datetime类型值为1970的问题
1.问题 今天使用FMDB做一个例子程序,新建的一张表有一个datetime字段,数据库有默认值,大概如下 CREATE TABLE [ConsumptionType] ([id] INTEGER P ...
- :尝试加载 Oracle 客户端库时引发 BadImageFormatException。如果在安装 32 位 Oracle 客户端组件的情况下以 64 位模式运行,将出现此问题。 ---> System.BadImageFormatException: 试图加载格式不正确的程序。
iis有程序池有一个属性 是否启用32位应用程序默认是true的特别注意windows2008 服务器系统iis默认的是true 这样发布一下也是必须要做的
- kafka及zookeeper安装
kafka_2.9.2-0.8.1.tgzzookeeper-3.4.8.tar.gz 安装 zookeeper1 export PATH=$PATH:/usr/local/zookeeper/bin ...
- css+js回到顶部
.backToTop { display: none; width: 18px; line-height: 1.2; padding: 5px 0; background-color: #000; c ...