Unity子弹生成系统
子弹系统和粒子系统比较类似,为了创建和五花八门的子弹,例如追踪,连续继承,散弹等,需要一个拥有众多参数的子弹生成器,这里叫它Shooter好了。
Shooter负责把玩各类子弹造型和参数,创建出子弹,创建完了之后接下来就交给子弹自己来管理自己了。
所以,一个子弹系统包含:
1.ShooterSystem类
一个能生成各种类型子弹的发射器。
2.Bullet类
按照给定的初始参数不断向前飞行的子弹个体。
先思考每一个单独的子弹需要有哪些物理参数:
1 //目标 2 public GameObject Target { get; set; } 3 //瞬时速度 4 public float Velocity { get; set; } 5 //剩余生命周期 6 public float LifeTime { get; set; } 7 //角速度 8 public float Palstance { get; set; } 9 //线性加速度 10 public float Acceleration { get; set; } 11 //最大速度 12 public float MaxVelocity { get; set; }
这些参数不需要子弹自己来配置,而是交给把玩它们的Shooter来进行,但是子弹自身需要知道这些参数。
其中指得一提的是角速度,正常的子弹是没有追踪功能的,生成之后就只能自动向前飞,但一旦设置了子弹的目标后,子弹就必须根据角速度转向目标位置的向量,保证自己的前向能尽快和目标向量对齐;而这一对齐的过程,就需要用角速度来描述。
子弹在生命周期到了之后要自动销毁,因为它经常反复创建和销毁,最好使用对象池来进行这一过程:
https://www.cnblogs.com/koshio0219/p/11572567.html
调用如下:
1 public IEnumerator AutoRecycle() 2 { 3 yield return new WaitForSeconds(LifeTime); 4 ObjectPool.Instance.RecycleObj(gameObject); 5 }
子弹每一帧的状态都会有所变化,例如位置,速度的更新,向前运行的方向的更新等:
1 private void Update() 2 { 3 float deltaTime = Time.deltaTime; 4 //由当前子弹位置指向目标位置的向量,记为瞬时偏移向量 5 Vector3 offset = (Target.transform.position - transform.position).normalized; 6 //子弹的当前前进方向与瞬时偏移向量之间的夹角 7 float angle = Vector3.Angle(transform.forward, offset); 8 //夹角除以角速度计算需要转到相同方向所需要的总时间 9 float needTime = angle*1.0f / Palstance; 10 //插值运算出当前帧的前向方向向量,也即是需要偏移的角度 11 transform.forward = Vector3.Lerp(transform.forward, offset, deltaTime / needTime).normalized; 12 //处理线性加速度对于速度的增量 13 if (Velocity < MaxVelocity) 14 { 15 Velocity += deltaTime * Acceleration; 16 } 17 //按当前速度向前移动一帧的距离,赋值给当前位置 18 transform.position += transform.forward * Velocity * deltaTime; 19 }
如果不想让子弹追踪,也很简单,把角速度传为0即可,float除数为0也是没有问题的。
子弹生成器主要是创建子弹,所以需要包含子弹类的所有参数,除此之外,还需要有一些其他的参数:
1 public bool bAuto = false; 2 3 public GameObject bulletPrefab; 4 //子弹目标 5 public GameObject target; 6 //初速度 7 public float velocity = 0f; 8 //加速度 9 public float acceleration = 30f; 10 //总生命周期 11 public float lifeTime = 3f; 12 //初始方向 13 public Vector2 direction = Vector2.zero; 14 //最大速度 15 public float maxVelocity = 600; 16 //角速度 17 public float palstance = 120; 18 //角度波动范围 19 public float angelRange = 0f; 20 //延迟 21 public float delay = 1f; 22 //是否循环 23 public bool bLoop = false; 24 //时间间隔 25 public float timeCell = .1f; 26 //生成数量 27 public int count = 1; 28 //伤害 29 public float damage; 30 //碰撞类型 31 public CollisionType collisionType; 32 //是否有子系统 33 public bool bChildShooter = false; 34 //子系统是谁 35 public GameObject childShooter;
初始方向就是子弹生成后的前向方向,如果想制造散弹效果,则子弹就需要在一定的角度波动范围内生成前向方向,但生成的位置依然是统一的。
生成器还需要能循环生成子弹,能够在生成的子弹飞行过程中继续生成不一样效果的分裂子弹,所以还需要子系统,子系统和父系统可以写为同一个生成器类。需要注意的就是,子系统的生命周期需要依赖父系统生成的子弹的生命周期。
生成单个子弹的方法:
1 private void Creat(Transform parent) 2 { 3 //从对象池中取对象生成到指定物体下,复位坐标 4 var ins = ObjectPool.Instance.GetObj(bulletPrefab, parent.transform); 5 ins.transform.ResetLocal(); 6 7 //对子弹的属性赋值 8 var bullet = ins.GetComponent<Bullet>(); 9 bullet.Target = target; 10 bullet.Velocity = velocity; 11 bullet.Acceleration = acceleration; 12 bullet.LifeTime = lifeTime; 13 bullet.MaxVelocity = maxVelocity; 14 bullet.Palstance = palstance; 15 16 //确定子弹生成方向的范围 17 float x = Random.Range(direction.x - angelRange / 2, direction.x + angelRange / 2); 18 float y = Random.Range(direction.y - angelRange / 2, direction.y + angelRange / 2); 19 bullet.transform.eulerAngles = new Vector3(x, y, 0); 20 21 parent.DetachChildren(); 22 23 //开启子弹自动回收 24 StartCoroutine(bullet.AutoRecycle()); 25 26 //判断子生成器并自动运行 27 if (bChildShooter) 28 { 29 var cscs = childShooter.GetComponent<ShooterSystem>(); 30 if (lifeTime > cscs.delay) 31 StartCoroutine(cscs.AutoCreat(bullet.transform, this)); 32 else 33 Debug.Log("子发射器延迟时间设置有误!"); 34 } 35 }
对于子生成器来说,它也同样可能拥有自己的子生成器,在AutoCreat的方法中需要传递它的父生成器是谁,默认情况下为空:
1 IEnumerator AutoCreat(Transform parent, ShooterSystem parShooter = null) 2 { 3 yield return new WaitForSeconds(delay); 4 if (bLoop) 5 { 6 if (parShooter != null) 7 { 8 //子生成器需要计算循环的次数,父生成器则是无限循环 9 int loopCount = (int)(parShooter.lifeTime - delay / timeCell); 10 for (; loopCount > 0; loopCount--) 11 { 12 //每次循环生成的子弹数量 13 for (int i = 0; i < count; i++) 14 Creat(parent); 15 yield return new WaitForSeconds(timeCell); 16 } 17 } 18 else 19 { 20 for (; ; ) 21 { 22 for (int i = 0; i < count; i++) 23 Creat(parent); 24 yield return new WaitForSeconds(timeCell); 25 } 26 } 27 } 28 else 29 { 30 for (int i = 0; i < count; i++) 31 Creat(parent); 32 } 33 }
这里的伤害和碰撞类型不在此篇讨论范围内。
原文地址:https://www.cnblogs.com/koshio0219/p/11573546.html
- SDP(9):MongoDB-Scala - data access and modeling
- 数据清理的遗留问题处理(r6笔记第87天)
- 一次DB time抖动发现的expdp的bug(r6笔记第86天)
- Python中map函数
- 10g,11g中数据库静默安装中的细小差别(r6笔记第85天)
- SDP(8):文本式数据库-MongoDB-Scala基本操作
- SDP(7):Cassandra- Cassandra-Engine:Streaming
- TensorFlow实现神经网络入门篇
- 27.反射,类加载器,设计模式,jdk新特性
- SDP(6):分布式数据库运算环境- Cassandra-Engine
- 配置dg broker的问题分析及修复(r6笔记第84天)
- SDP(5):ScalikeJDBC- JDBC-Engine:Streaming
- SDP(4):ScalikeJDBC- JDBC-Engine:Updating
- SDP(3):ScalikeJDBC- JDBC-Engine:Fetching
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 栅格化系统的原理以及实现
- vue-qr二维码插件使用简介
- Codeforces Round #547 (Div. 3)F1. Same Sum Blocks (Easy)
- 手机软键盘弹起导致页面变形的一种解决方案
- Codeforces Round #547 (Div. 3)F2. Same Sum Blocks (Hard)
- 《 动态规划_ 入门_最大连续子序列 》
- docker搭建elasticsearch集群
- 用canvas实现手写签名功能
- Codeforces Round #547 (Div. 3)G. Privatization of Roads in Treeland
- 《 动态规划_ 入门_最大连续子序列_HDU_1003 》
- 2015 09CCF计算机软件能力认证试题第三题
- 《内蒙古自治区第十二届大学生程序设计竞赛试题_D: 正品的概率》
- Elasticsearch: Painless script编程
- mysql实现定时全量备份
- 在浏览器调起本地应用的方法