【unity实战】实现实体子弹射击

简介: 【unity实战】实现实体子弹射击

射击脚本

public class Weapon : MonoBehaviour
{
  public GameObject bulletPrefab; // 子弹预制体
  public Transform bulletSpawn; // 子弹生成位置
  public float bulletVelocity = 30f; // 子弹速度
  public float bulletPrefabLifeTime = 3f; // 子弹存在时间
  
  void Update()
  {
      // 按下鼠标左键
      if (Input.GetKeyDown(KeyCode.Mouse0))
      {
          FireWeapon(); // 开火
      }
  }
  
  private void FireWeapon()
  {
      // 实例化子弹
      GameObject bullet = Instantiate(bulletPrefab, bulletSpawn.position, Quaternion.identity);
  
      // 发射子弹
      bullet.GetComponent<Rigidbody>().AddForce(bulletSpawn.forward.normalized * bulletVelocity, ForceMode.Impulse);
  
      // 一段时间后销毁子弹
      StartCoroutine(DestroyBulletAfterTime(bullet, bulletPrefabLifeTime));
  }
  
  private IEnumerator DestroyBulletAfterTime(GameObject bullet, float delay)
  {
      yield return new WaitForSeconds(delay);
      Destroy(bullet);
  }
}

新增子弹预制体

如果没有子弹模型,可以新建一个胶囊体缩小尺寸代替

子弹挂载脚本,实现触碰销毁

public class Bullet : MonoBehaviour
{
    private void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.CompareTag("Target"))
        {
            // 打中目标并输出信息
            print("Hit " + collision.gameObject.name + "!");
            
            // 销毁目标物体
            Destroy(collision.gameObject);
        }
    }
}

子弹添加拖尾效果

新增拖尾材质Particles/Standard Unlit,配置参数

绑定材质

扩展

分享一个实体子弹射击脚本,一个脚本就可实现

public class ProjectileGunTutorial : MonoBehaviour
{
    //子弹
    public GameObject bullet;

    //发射力量
    public float shootForce, upwardForce;

    //枪支状态
    public float timeBetweenShooting, spread, reloadTime, timeBetweenShots;
    public int magazineSize, bulletsPerTap;
    public bool allowButtonHold;

    int bulletsLeft, bulletsShot;

    //布尔值
    bool shooting, readyToShoot, reloading;

    //引用
    public Camera fpsCam;
    public Transform attackPoint;

    //图形
    public GameObject muzzleFlash;
    public TextMeshProUGUI ammunitionDisplay;

    //修复bug:D
    public bool allowInvoke = true;

    private void Awake()
    {
        //确保弹夹是满的
        bulletsLeft = magazineSize;
        readyToShoot = true;
    }

    private void Update()
    {
        MyInput();

        //设置弹药显示,如果存在的话:D
        if (ammunitionDisplay != null)
            ammunitionDisplay.SetText(bulletsLeft / bulletsPerTap + " / " + magazineSize / bulletsPerTap);
    }
    private void MyInput()
    {
        //检查是否允许按住按钮并采取相应的输入
        if (allowButtonHold) shooting = Input.GetKey(KeyCode.Mouse0);
        else shooting = Input.GetKeyDown(KeyCode.Mouse0);

        //重新装填
        if (Input.GetKeyDown(KeyCode.R) && bulletsLeft < magazineSize && !reloading) Reload();
        //尝试在没有子弹的情况下射击时自动重新加载
        if (readyToShoot && shooting && !reloading && bulletsLeft <= 0) Reload();

        //射击
        if (readyToShoot && shooting && !reloading && bulletsLeft > 0)
        {
            //将射出的子弹数设为0
            bulletsShot = 0;

            Shoot();
        }
    }

    private void Shoot()
    {
        readyToShoot = false;

        //使用射线投射找到精确的命中位置
        Ray ray = fpsCam.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0)); //只是通过当前视图中间的射线
        RaycastHit hit;

        //检查射线是否击中物体
        Vector3 targetPoint;
        if (Physics.Raycast(ray, out hit))
            targetPoint = hit.point;
        else
            targetPoint = ray.GetPoint(75); //只是远离玩家的一个点

        //计算从攻击点到目标点的方向
        Vector3 directionWithoutSpread = targetPoint - attackPoint.position;

        //计算散射
        float x = Random.Range(-spread, spread);
        float y = Random.Range(-spread, spread);

        //计算带有散射的新方向
        Vector3 directionWithSpread = directionWithoutSpread + new Vector3(x, y, 0); //只需将散射添加到最后的方向

        //实例化子弹/抛射物
        GameObject currentBullet = Instantiate(bullet, attackPoint.position, Quaternion.identity); //将实例化的子弹存储在currentBullet中
        //将子弹旋转到射击方向
        currentBullet.transform.forward = directionWithSpread.normalized;

        //为子弹添加力量
        currentBullet.GetComponent<Rigidbody>().AddForce(directionWithSpread.normalized * shootForce, ForceMode.Impulse);
        currentBullet.GetComponent<Rigidbody>().AddForce(fpsCam.transform.up * upwardForce, ForceMode.Impulse);

        //实例化枪口火焰,如果有的话
        if (muzzleFlash != null)
            Instantiate(muzzleFlash, attackPoint.position, Quaternion.identity);

        bulletsLeft--;
        bulletsShot++;

        //调用resetShot函数(如果尚未调用),使用timeBetweenShooting
        if (allowInvoke)
        {
            Invoke("ResetShot", timeBetweenShooting);
            allowInvoke = false;
        }

        //如果超过一个bulletsPerTap,请确保重复射击函数
        if (bulletsShot < bulletsPerTap && bulletsLeft > 0)
            Invoke("Shoot", timeBetweenShots);
    }
    private void ResetShot()
    {
        //允许再次射击和调用
        readyToShoot = true;
        allowInvoke = true;
    }

    private void Reload()
    {
        reloading = true;
        Invoke("ReloadFinished", reloadTime); //使用reloadTime作为延迟调用ReloadFinished函数
    }
    private void ReloadFinished()
    {
        //填充弹夹
        bulletsLeft = magazineSize;
        reloading = false;
    }
}

目录
相关文章
|
2天前
|
图形学
【unity实战】时间控制 昼夜交替 四季变化 天气变化效果
【unity实战】时间控制 昼夜交替 四季变化 天气变化效果
7 0
|
2天前
|
存储 JSON 关系型数据库
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
11 2
|
2天前
|
人工智能 定位技术 图形学
【unity实战】制作敌人的AI,使用有限状态机、继承和抽象类多态 定义不同状态的敌人行为
【unity实战】制作敌人的AI,使用有限状态机、继承和抽象类多态 定义不同状态的敌人行为
45 1
|
2天前
|
安全 图形学
【unity实战】事件(Event)的基本实战使用
【unity实战】事件(Event)的基本实战使用
6 1
|
2天前
|
Rust 图形学
【unity实战】使用unity制作一个类似Rust的3D生存建造建筑系统,具有很好的吸附性(附项目源码)
【unity实战】使用unity制作一个类似Rust的3D生存建造建筑系统,具有很好的吸附性(附项目源码)
8 1
|
2天前
|
图形学
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统(下)
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统
7 0
|
2天前
|
图形学 容器
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统(上)
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统
5 0
|
2天前
|
存储 JSON 图形学
【unity实战】制作unity数据保存和加载系统——小型游戏存储的最优解
【unity实战】制作unity数据保存和加载系统——小型游戏存储的最优解
6 0
|
2天前
|
图形学
【unity实战】3D水系统,游泳,潜水,钓鱼功能实现
【unity实战】3D水系统,游泳,潜水,钓鱼功能实现
3 0
|
2天前
|
图形学
【unity小技巧】FPS简单的射击换挡瞄准动画控制
【unity小技巧】FPS简单的射击换挡瞄准动画控制
4 0