文章目录
Hello大家好我是开罗小8,今天我来给大家带来Unity常用子弹弹幕类型的实现,功能的实现方式有很多种,在实现效果中,我会尽可能用简单的代码实现,文章的示例项目文件在文章底部
前言
本文子弹始终朝向其前进方向移动(在2D中红轴为前进方向,3D中蓝轴为前进方向),可以将坐标轴切换为local来查看当前物体的朝向
子弹的基类脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BaseBullet : MonoBehaviour
{
public float Speed=1;
public GameObject ExpFX;
protected Rigidbody2D rb;
protected Transform m_tansform;
// Update is called once per frame
private void Awake()
{
rb = gameObject.AddComponent<Rigidbody2D>();
rb.gravityScale = 0;
rb.drag= 0;
rb.freezeRotation = true;
rb.bodyType = RigidbodyType2D.Dynamic;
rb.constraints = RigidbodyConstraints2D.FreezeRotation;
m_tansform = transform;
}
protected virtual void Update()
{
m_tansform.position= m_tansform.position+ m_tansform.right*Speed*Time.deltaTime;
//m_tansform.Translate(Vector3.right * Speed * Time.deltaTime);
}
public void Explode()
{
Destroy(Instantiate(ExpFX, m_tansform.position,Quaternion.identity),2f);
Destroy(gameObject);
}
}
- 脚本中Update两行代码均可实现让子弹沿自身的红轴(X轴)移动
- 获取物体当前的轴向
- transform.right 红轴(X轴)
- transform.up 绿轴(Y轴)
- transform.forward 蓝轴(Z轴)
- transform.right与Vector3.right的区别
- Vector3.right始终等于new Vector3(1,0,0)
- transform.right为当前物体红轴的朝向,受到物体旋转的影响
transform.Translate方法如果只传入一个Vector3类型的,它会以自身的轴来进行移动
例如transform.Translate(new Vector3(1,0,0))表示物体朝自身的X轴方向移动1米
为了避免子弹相互碰撞,需要将子弹设置一个新的layer,命名为Bullet,layer设置完后还需要在Edit->ProjectSetting->Physics2D中取消勾选Bullet与Bullet之间的碰撞
一、各种类型子弹以及武器的实现
1.向鼠标方向发射子弹
using UnityEngine;
public class Weapon : MonoBehaviour
{
public GameObject FireFX;
public GameObject Bullet;
private Transform m_transform;
// Start is called before the first frame update
Camera cam;
void Start()
{
cam=Camera.main;
m_transform = transform;
}
// Update is called once per frame
void Update()
{
Vector3 mousePos= cam.ScreenToWorldPoint(Input.mousePosition);
Vector3 weaponDir=mousePos- m_transform.position;
weaponDir.z = 0;
weaponDir.Normalize();
m_transform.right=weaponDir;
//float zAngle = Mathf.Atan2(weaponDir.y, weaponDir.x) * Mathf.Rad2Deg;
//m_transform.localEulerAngles=new Vector3(0,0,zAngle);
if(Input.GetKeyDown(KeyCode.Space))
{
//GameObject fireFX = Instantiate(FireFX);
//fireFX.transform.position= m_transform.position;
//Destroy( fireFX ,2f);
GameObject bullet= Instantiate(Bullet);
bullet.transform.position= m_transform.position;
bullet.transform.right= m_transform.right;
}
}
}
1.使用本地变量缓存主摄像机和transform,使用transform获取变换和使用Camera.main获取摄像机比较消耗性能
2.将鼠标位置从屏幕空间转换到世界空间,使用cam.ScreenToWorldPoint(Input.mousePosition);传入当前鼠标的屏幕位置
注:屏幕位置为左下角为(0,0),右上角为屏幕分辨率,如(1920,1080)
3.计算向量,两个物体的位置相减,得到的方向指向被减的位置,示例中的代码可以得到武器位置指向鼠标的方向。
4.计算武器的旋转角,调整武器的朝向,同时在生成子弹时调整子弹的位置和旋转。
注:直接对transform.right赋值改变物体旋转只适合在2D中使用,不推荐在3D情况下使用,可能会导致其他轴的不正确旋转
2.子弹撞墙反弹
using UnityEngine;
public class BounceBullet : BaseBullet
{
public int BounceCount = 3;
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Wall"))
{
--BounceCount;
if (BounceCount <= 0)
{
Explode();
return;
}
Vector2 outDir = Vector2.Reflect(m_tansform.right, collision.GetContact(0).normal);
m_tansform.right = outDir;
}
}
}
- Vector2.Reflect第一个参数传入当前子弹的朝向,第二个参数传入碰撞的法向,会返回反射后的新向量
- collision.GetContact(0).normal来获取碰撞点的法向
- 只有在OnCollisionEnter2D中才可以获取碰撞点的法向,OnTriggerEnter2D中无法获取碰撞点的法向
- 子弹需要有Rigidbody2D组件,且刚体类型为Dynamic,否则碰撞函数不会被触发
- 此处使用CompareTag方法比较碰撞体的标签,如果是Wall就反弹,使用CompareTag比直接gameObject.tag==“Wall”要更节省性能
- 应当保证传入的参数都是归一化(向量的模为1)后的向量,可以使用vector3.Normalize();方法使向量归一化,否则计算出的方向可能会不正确
- 可以直接给transform.right赋值来改变物体的朝向
3.子弹追踪敌人
简单版,这样写子弹会固定指向敌人,视觉效果并不好
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TargetingBullet : BaseBullet
{
Transform target;
private void Start()
{
target = GameObject.Find("Target").transform;
}
// Update is called once per frame
protected override void Update()
{
Vector3 targetDir=target.position-transform.position;
targetDir.Normalize();
transform.right= targetDir;
base.Update();
}
}
调整方法1:使用插值函数,子弹每次调整一定的角度
using UnityEngine;
public class TargetingBullet : BaseBullet
{
Transform target;
public float TurnSpeed=2;
float lifeTime=0;
private void Start()
{
target = GameObject.Find("Target").transform;
}
// Update is called once per frame
protected override void Update()
{
Vector3 targetDir=target.position-transform.position;
targetDir.z = 0;
targetDir.Normalize();
lifeTime += Time.deltaTime;
m_tansform.right= Vector3.Slerp(m_tansform.right,targetDir,Mathf.Clamp01(Time.deltaTime*(lifeTime)* TurnSpeed));
base.Update();
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Enemy"))
{
Explode();
}
}
}
lifeTime的作用:子弹存在的时间越长,转向速度越快,如果不增加转向速度,会导致子弹速度大于转向速度时,子弹会一直绕着敌人转圈,无法命中敌人
Vector3.Slerp:前两个参数传入两个Vector3类型,第三个参数传入插值,当插值为0时返回第一个向量,插值为1时返回第二个向量,插值在0~1时返回两向量的过渡值
4.散弹枪
public void FireShotGun(float angle,int bulletCount)
{
int mid = bulletCount >> 1;
for(int i=0;i<bulletCount; i++)
{
Vector3 dir = Quaternion.Euler(new Vector3(0,0, (i - mid) * angle))*m_transform.right;
GameObject bullet = Instantiate(Bullet);
bullet.transform.position = m_transform.position;
bullet.transform.right = dir;
}
}
angle为每个子弹的角度,bulletCount为子弹的个数,示例中传入的参数为10,4
1.使用位运算计算子弹数量的中位数,buttonCount>>1等价于buttonCount/2,位运算的计算效率比除法要高,但是位运算的优先级低于加减法,如果有加法要注意加括号
2. Quaternion.Euler传入的Vector3类型相当于旋转的的欧拉角度,乘以一个向量的返回值等于该向量在对应轴上旋转后的向量,注意四元数在乘号左边,向量在右边,位置不能交换,上面的代码在计算transform.right绕自身的z轴旋转一个角度后的向量
5.圆环弹幕
public void FireCircle(int bulletCount,float angleOffset)
{
float angle=360/bulletCount;
for (int i = 0; i < bulletCount; i++)
{
Vector3 dir = Quaternion.Euler(new Vector3(0, 0, i*angle+angleOffset)) * m_transform.right;
GameObject bullet = Instantiate(Bullet);
bullet.transform.position = m_transform.position;
bullet.transform.right = dir;
}
}
每次发射增加angleoffset即可产生不同的角度偏移
其他类型的弹幕会持续更新……
项目文件下载:
子弹和武器.unitypackage文章来源:https://www.toymoban.com/news/detail-752760.html
总结
本文介绍了常用的2D游戏子弹以及武器的实现方式,为了方便,直接对transform.right赋值来调整旋转,这个操作只能保证transform.right这个轴朝向给定的方向,在3D中可能会导致奇怪的旋转,我会在下一篇文章中详细介绍使用数学以及四元数的方法计算旋转文章来源地址https://www.toymoban.com/news/detail-752760.html
到了这里,关于Unity常用2D子弹弹幕以及枪械类型的实现:可实现霰弹枪,Boss弹幕,子弹反弹,追踪弹等的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!