2D Shooting
子弹 && 射线
- 预制件 prefabs
- 创建Bullet Prefabs,每次射击都创建一个新的子弹实例
- 子弹本体控制射出等动作、伤害、效果等属性
- 射线 raycasts
- 由射击点射出一条射线,检测是否存在碰撞物
开火点 FirePoint
在Player层级下创建空对象FirePoint,
用于对开火点坐标进行标注。
需要注意的是,在控制角色移动的脚本CharacterController2D中,
实现角色水平移动时翻转的函数是这样的:
1 | private void Flip() |
通过反转Player在x轴方向的缩放值进行翻转。
这种方式能够在不影响Player坐标系的情况下对它的贴图进行翻转。
但是Player下的FirePoint的坐标系是动态的,
在Player进行翻转时,FirePoint坐标系也需要跟随翻转,
这样才能保证子弹一直朝Player面向的方向进行射击,
通过将Player沿y轴方向旋转180°的方式能够实现这一点:
1 | private void Flip(){ |
Prefab射击
使用prefab方式,就要做bullet的prefab:
BulletPrefab脚本:
- Bullet 为子弹自定义行为的脚本
- Circle Collider 2D 碰撞体积
- isTrigger = true 仅用于触发
- Rigidbody 2D
- Graivity Scale = 0 无重力
- Collision Detection = Continuous 持续检测
- Freeze Rotation Z = true 无z轴旋转
将做好的BulletPrefab拖动到Assets目录下,即作为预制件使用。
创建子弹
子弹已经做好,那么只要在Player射击的时候创建出子弹即可,
因此需要为Player创建新的Weapon脚本,
Weapon脚本要实现在用户射击时创建BulletPrefab的功能:
1 | using System.Collections; |
创建实例的方法:
1 | // 创建对象 位置 旋转 |
子弹移动
通过为Bullet添加初始速度来时其保持移动,
这要通过子弹的Rigidbody2D.velocity属性来控制:
1 | public class Bullet : MonoBehaviour |
子弹伤害
现在子弹已经能射出,接下来要实现的:
- 检测子弹是否碰撞到物体
- 检测到碰撞,产生子弹冲击效果,子弹消失
- 碰撞物是否是敌人
- 使敌人,造成伤害
- 敌人脚本要实现的动作
- 收到伤害
- 生命值为0时,死亡
- 死亡
- 敌人消失
- 出现消失特效
- 收到伤害
为敌人添加的Enemy脚本如下:
1 | public class Enemy : MonoBehaviour |
其中的TakeDamage方法的调用时机是:当子弹碰撞到Enemy时,
这一步在Bullet预制件脚本中进行,
因此需要用public暴露出来。
之前已经打开了Bullet预制件Collider2D的isTrigger选项,
因此当子弹碰撞到物体时,会触发Unity提供的OnTriggerEnter2D函数,
这个函数提供一个Collider2D类的参数,表示碰撞物信息。
1 | public class Bullet : MonoBehaviour |
Raycast射击
raycast射线检测
raycast和prefab不同的地方是:
- prefab碰撞的逻辑需要再子弹上实现
- raycast碰撞的逻辑在Player上就能实现
为Player添加WeaponRaycast脚本:
1 | public class WeaponRaycast : MonoBehaviour |
创建raycast并返回射线探测物:
1 | RaycastHit2D hitInfo = Physics2D.Raycast(firePoint.position, firePoint.right); |
原本在Prefab方法里,会在OnTriggerEnter2D方法中提供一个Collider2D类型的参数,
这里对应RaycastHit2D中的参数为:
1 | Enemy enemy = hitInfo.transform.GetComponent<Enemy>(); |
而碰撞点的坐标值则从hitInfo.point里取得
射线绘制
使用Line(Effect/Line)来作为射线效果,
在Player下创建Line实例,
开启Line的Use World Space属性
1 | public class WeaponRaycast : MonoBehaviour |
Top Down Shooting 俯视角射击
这里俯视角下玩家的移动涉及到跟随鼠标移动的旋转:
1 | public class PlayerMovement : MonoBehaviour |
- Input.GetAxisRaw(“Horizontal|Vertical”) 获取横向/纵向移动距离
- Camera.ScreenToWorldPoiint(Vector2D var) 将鼠标相对屏幕的坐标转换为世界坐标系下的坐标
最后需要根据玩家当前坐标和鼠标位置计算旋转的角度:
- Mathf.Atan2(y,x) 获取正弦值为y/x的弧度
- Mathf.Rad2Deg 将弧度转为角度需要乘上的数
Shooting脚本需要在玩家触发子弹发射行为时,
- 获取开火点
- 创建子弹实例
- 给子弹一个推动力:
1 | public class Shooting : MonoBehaviour |
最后是子弹自身检测到碰撞后的逻辑:
1 | public class Bullet : MonoBehaviour |