[Unity3D入门]入门级游戏项目"坦克狙击手"更新

上一篇中我分享了一个尚未完全写好的入门级unity3d项目"坦克狙击手"。

本文介绍最新版的"坦克狙击手"相关情况。

需要源代码和发布的Windows版、网页版程序的同学麻烦支付100元留下你的邮箱~

关于调节粒子系统参数的经验

如你所见,我对导弹尾焰的粒子效果进行了调节。这里学到的一个经验是,分析然后模仿现实生活中的物理化学现象,才能做出逼真的效果。一个粒子就是火焰中的一个点。我们都知道蜡烛的火焰分为内焰中焰外焰三层。符合一个粒子从诞生到熄灭、从中心位置到边沿位置、从白色到黄色到金色(颜色方面我就不细琢磨了,毕竟 导弹和蜡烛不完全一样)的变化过程。根据这些知识去设定粒子系统的参数就可以得到比较好的效果。

使用第三方包Detonator的爆炸效果

本篇更新的导弹爆炸效果用的是Detonator提供的示例prefab,只稍微调节了一下大小和爆炸时间。Detonator很好用,其效果很赞,包内自带的示例场景Detonator-TestWall和PDF说明文档一目了然。唯一需注意的一点是,导入Detonator包时,在"NormalMap settings"窗口中一定要选择"Ignore"按钮,否则,你会看到爆炸烟雾的正方形边沿,爆炸效果就显得假了。

哦对了,发布的时候也要注意一点,就是必须把示例场景Detonator-TestWall也加入到发布列表,否则爆炸效果是无法显示的。原因,暂时不知道。

导弹杀伤一定半径范围内的所有坦克

上一篇中,导弹只能对命中的坦克造成杀伤。这一篇中通过使用"Physics.OverlapSphere()"方法,导弹可以对一定半径范围内的所有坦克造成杀伤,更具真实性。

     public float explosionRadius = ;
public float maxPower = ;
public float maxForce = ;
void OnCollisionEnter(Collision collision) {
var point = collision.contacts[].point;//获取导弹击中(爆炸)的位置
Collider[] colliders = Physics.OverlapSphere(point, explosionRadius);//获取导弹爆炸范围内所有的碰撞体
Destroy(this.gameObject);//导弹已经不复存在
foreach (Collider hit in colliders) {
if (hit == null) { continue; }
if (hit.rigidbody == null) { continue; }
if (hit.gameObject.tag != "Tank") { continue; }
var tank = hit.gameObject.GetComponent<TankMove>();
if (tank != null) {//这个碰撞体是一个坦克
tank.Damage(maxPower);//坦克被杀伤(暂时认为杀伤半径内的杀伤力是相同的,简化计算)
if (tank.hp <= ) {//坦克挂掉了
hit.rigidbody.AddExplosionForce(maxForce, point, explosionRadius);//坦克被爆炸冲击波冲走
}
}
}
ExplosionEffectHelper.Instance.Explode(ExplosionEffectHelper.ExplosionEffect.MissileExplosion, point);//Detonator爆炸效果
SoundEffectHelper.Instance.MakeExplosionSound();//爆炸声音
}

PS:在我知道"Physics.OverlapSphere()"这个方法前,我在导弹爆炸后创建了一个Sphere,让它代表导弹爆炸的球形冲击波,通过这个Sphere在膨胀过程中与周边坦克的OnCollisionEnter事件对坦克计算杀伤。这样虽然也有周边杀伤的能力,但是计算冲击波的力量有点繁琐;且爆炸瞬间的杀伤变成了Sphere膨胀若干个帧之后的杀伤,不太真实。

坦克撞坦克问题

上一篇中,后面速度快的坦克撞上前面速度慢的坦克,它俩就可能飞起来。本篇解决了这个问题。方法如下:

如图所示,在坦克prefab中,在其前后左右分别放置一个Cube,将其包围起来(并取消勾选Cube的Mesh Renderer,选中Is Trigger),做成"围墙"。在坦克prefab前方的Cube(命名为Front)中设置OnTriggerEnter()等方法。

     TankMove tankMoveScript;
void Awake() {
this.tankMoveScript = this.GetComponentInParent<TankMove>();
} void OnTriggerEnter(Collider other)
{ if (other.gameObject.tag == "Back")//other是前面的一辆坦克的“围墙”
{
this.tankMoveScript.SetForward(false);//撞到了前面的坦克的“围墙”,就暂时不要继续走了
}
} void OnTriggerExit(Collider other)
{
if (other.gameObject.tag == "Back")//other是前面的一辆坦克的“围墙”
{
this.tankMoveScript.SetForward(true);//前面的坦克走开了,那么我也继续走
}
}

在坦克prefab后方的Cube(命名为Back)中也设置OnTriggerEnter()等方法。

     private GameObject other;
void OnTriggerEnter(Collider other)
{ if (other.gameObject.tag == "Front")//other是后面的一辆坦克的“围墙”
{
this.other = other.gameObject;//我挡住后面的一辆坦克了
}
} void OnTriggerExit(Collider other)
{
if (other.gameObject.tag == "Front")
{
this.other = null;//我不再继续挡着后面那辆坦克了
}
} void OnDestroy() {
var o = other;
if (o != null) {//要是在我挡住后面一辆坦克的时候,我挂了,我得通知人家
o.GetComponentInParent<TankMove>().SetForward(true);
}
}

显示一些信息

例如,我想在屏幕上显示出当前我击杀了多少坦克。

很简单,创建一个脚本"DisplayKilledTankCount.cs",编写代码如下。

     public int killedTank = ;
void OnGUI() {
GUI.Label(new Rect(, , , ), string.Format("Killed tank: {0}", killedTank));
}

将这个脚本作为一个component添加到Main Camera上。

在"TankMove.cs"的"Damage()"方法中添加2行代码:

     public float hp = ;
public void Damage(float damageCount) {
hp -= damageCount;
if (hp <= ) {
this.gameObject.rigidbody.freezeRotation = false;//挂掉了,可以被导弹冲击到任何角度
var display = Camera.main.GetComponent<DisplayKilledTankCount>();
display.killedTank += ;//击杀的坦克增加1
Destroy(gameObject, );
}
}

坦克的布娃娃效果

布娃娃效果就是人死的时候会呈现各种姿式,不会像以前一样,跟一棍似的直不楞登一倒~

坦克挂掉了,不应该立即被Destroy()掉,那样太突兀了。我想做的效果是坦克在挂掉时被导弹冲击波击飞,落地,然后掉入地面下消失,然后才Destroy()。

实际上上文中的代码已经顺带显示了如果实现这一效果。

首先,导弹击杀掉坦克的时候,在Damage()方法中设定20秒(经验值)后被Destroy()。

然后,在TankMove.cs中添加字段"deadTime",记录坦克挂掉后经过了多久。在坦克挂掉10秒(经验值)后,我们让坦克具备陷入地下的能力。

     private float deadTime = ;
private bool sinking = false;
// 每帧调用一次,用于更新游戏场景和状态(和物理状态有关的更新应放在FixedUpdate里)
void Update () {
if ((!sinking) && (hp <= )) {
deadTime += Time.deltaTime;
if (deadTime >= ) {
this.gameObject.collider.isTrigger = true;//这样,物理引擎就不会对坦克生效。(当然,仍会触发OnTriggerXxx()事件)
sinking = true;
}
}
}

最后,坦克挂掉之后就不应该有动力了。

     // 每个固定物理时间间隔(physics time step)调用一次,用于物理状态的更新
void FixedUpdate() {
if (hp <= ) { return; }//挂了,就别自己动了,随遇而安吧。
if (this.forward) {
this.rigidbody.velocity = new Vector3(, rigidbody.velocity.y, zSpeed);
}
else {
this.rigidbody.velocity = new Vector3(, rigidbody.velocity.y, );
}
}

需要源代码和发布的Windows版、网页版程序的同学麻烦支付100元留下你的邮箱~

[Unity3D入门]入门级游戏项目"坦克狙击手"更新的更多相关文章

  1. [Unity3D入门]分享一个自制的入门级游戏项目"坦克狙击手"

    [Unity3D入门]分享一个自制的入门级游戏项目"坦克狙击手" 我在学Unity3D,TankSniper(坦克狙击手)这个项目是用来练手的.游戏玩法来自这里(http://ww ...

  2. Unity3D入门其实很简单

    在上次发布拙作后,有不少童鞋询问本人如何学习Unity3D.本人自知作为一名刚入门的菜鸟,实在没有资格谈论这么高大上的话题,生怕误导了各位.不过思来想去,决定还是写一些自己的经验,如果能给想要入门U3 ...

  3. Unity3D入门之JavaScript动态创建对象

    接着上一篇Unity3D入门文章,这里继续使用JavaScript脚本语言. 调试:Unity集成了MonoDevelop编辑器,在代码某行的左侧点击,即可下一个断点.然后先关闭Unity编辑器,在M ...

  4. Unity3D 入门 游戏开发 Unity3D portal game development

    Unity3D 入门 游戏开发 Unity3D portal game development 作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555@qq.com ...

  5. [0]尝试用Unity3d制作一个王者荣耀(持续更新)->游戏规划

    太得闲了于是想写个农药,虽然可能会失败但是还是要试一试. 因为是自学的不是Unity专业的可能表达语言会有些不标准!望见谅! 结构: 以组件式(比如说摇杆控制和玩家部分的编写是分离的,可以自由拼装)作 ...

  6. Mybatis入门教程之新增、更新、删除功能_java - JAVA

    文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 上一节说了Mybatis的框架搭建和简单查询,这次我们来说一说用Mybatis进行基本的增删改操作: 一. 插入一条数据 ...

  7. (转载)李剑英的CSLight入门指南结合NGUI热更新

    原地址:http://www.xuanyusong.com/archives/3075 李剑英的CSLight入门指南文档撰写者:GraphicQQ: 1065147807 一. CSLIGHT 作者 ...

  8. Unity3D入门(一):环境搭建

    1.Unity3D 目前最新正式版本是4.2.1f  官网下载,以前的版本安装时候需要序列号激活,新版本4.2.1f 不需要,完全免费,但发布的时候需要许可证 2.要学习的同学,下载频道可以找到破解补 ...

  9. Unity3D入门之JavaScript

    刚刚接触Unity3D游戏引擎,这里做点学习笔记.下面是我建立的简单场景,左侧的Hierarchy(层次)视图里显示了场景中所有游戏对象,这些基本对象可以从Create下拉菜单里创建.当你点击某个对象 ...

随机推荐

  1. ASP.NET c# textbox 正则表达式 文本框只允许输入数字(验证控件RegularExpressionValidator )

    <input type="text" name="test" onKeyUp="test1.value=(this.value=this.val ...

  2. 找出一个二维数组中的"鞍点",即该位置上的元素在该行中最大,在该列中最小(也可能没有"鞍点"),打印有关信息.(提示:注意特殊情况:没鞍点或多个鞍点)

    #import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { ][] = {}; ;i < ...

  3. c#下调用dll动态链接库[转]

    C# 调用传统的 API 动态链接库,是.NET开发经常被讨论的问题. 比如有这么一个动态链接库(delphi 语言): library DelphiDLL; uses SysUtils, Class ...

  4. 安装双系统window +ubuntu

    在网上,试过很多种方法,有U盘制作安装,感觉好复杂,这边有一个简便的方法就是使用Ubuntu 的 wubi安装. 一直想安装双Ubuntu 系统很久了,可是以前在大学时期的时候一直努力,好像都不行,这 ...

  5. Ansible常用模块

    http://liumissyou.blog.51cto.com/4828343/1749121

  6. swift基础语法(四) 函数、闭包(Closures)

    //函数基本定义 func 函数名(参数名:参数类型=默认值) ->返回值类型{代码块} //无参无返回值函数 func hsmin(){ } //单参无返回值函数 func prin(st:S ...

  7. command not found,系统很多命令都用不了 ,修改环境变量

    bash: ***: command not found,系统很多命令都用不了,均提示没有此命令. 突然之间linux很多命令都用不了,均提示没有此命令. 这应该是系统环境变量出现了问题导致的. 解决 ...

  8. 【动态规划】bzoj1642 [Usaco2007 Nov]Milking Time 挤奶时间

    区间按左端点排序,dp. #include<cstdio> #include<algorithm> using namespace std; #define N 1001 st ...

  9. android中布局文件中 layout_weight 的属性详解

    在不同的情况下,layout_weight属性作用是不同的.主要有两种属性: 1.当布局中的控件的尺寸(宽和高)都有指定时,它所表示的该控件在父容器中的比重,及它在父容器中所占的比例,数值越大,比重越 ...

  10. berkeley db中 dirty read的实现

    dirty reader怎样 不被writor block住? 如数据库支持dirty read, 则 所有打开的dbhandle都配置 DB_READ_UNCOMMITTED; 在线程拿到 writ ...