【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;
    }
}

目录
相关文章
|
6月前
|
图形学
【unity实战】时间控制 昼夜交替 四季变化 天气变化效果
【unity实战】时间控制 昼夜交替 四季变化 天气变化效果
164 0
|
4月前
|
开发者 图形学 Java
揭秘Unity物理引擎核心技术:从刚体动力学到关节连接,全方位教你如何在虚拟世界中重现真实物理现象——含实战代码示例与详细解析
【8月更文挑战第31天】Unity物理引擎对于游戏开发至关重要,它能够模拟真实的物理效果,如刚体运动、碰撞检测及关节连接等。通过Rigidbody和Collider组件,开发者可以轻松实现物体间的互动与碰撞。本文通过具体代码示例介绍了如何使用Unity物理引擎实现物体运动、施加力、使用关节连接以及模拟弹簧效果等功能,帮助开发者提升游戏的真实感与沉浸感。
124 1
|
3月前
|
图形学 C++ C#
Unity插件开发全攻略:从零起步教你用C++扩展游戏功能,解锁Unity新玩法的详细步骤与实战技巧大公开
【8月更文挑战第31天】Unity 是一款功能强大的游戏开发引擎,支持多平台发布并拥有丰富的插件生态系统。本文介绍 Unity 插件开发基础,帮助读者从零开始编写自定义插件以扩展其功能。插件通常用 C++ 编写,通过 Mono C# 运行时调用,需在不同平台上编译。文中详细讲解了开发环境搭建、简单插件编写及在 Unity 中调用的方法,包括创建 C# 封装脚本和处理跨平台问题,助力开发者提升游戏开发效率。
307 0
|
4月前
|
开发者 图形学 API
从零起步,深度揭秘:运用Unity引擎及网络编程技术,一步步搭建属于你的实时多人在线对战游戏平台——详尽指南与实战代码解析,带你轻松掌握网络化游戏开发的核心要领与最佳实践路径
【8月更文挑战第31天】构建实时多人对战平台是技术与创意的结合。本文使用成熟的Unity游戏开发引擎,从零开始指导读者搭建简单的实时对战平台。内容涵盖网络架构设计、Unity网络API应用及客户端与服务器通信。首先,创建新项目并选择适合多人游戏的模板,使用推荐的网络传输层。接着,定义基本玩法,如2D多人射击游戏,创建角色预制件并添加Rigidbody2D组件。然后,引入网络身份组件以同步对象状态。通过示例代码展示玩家控制逻辑,包括移动和发射子弹功能。最后,设置服务器端逻辑,处理客户端连接和断开。本文帮助读者掌握构建Unity多人对战平台的核心知识,为进一步开发打下基础。
159 0
|
4月前
|
开发者 图形学 C#
揭秘游戏沉浸感的秘密武器:深度解析Unity中的音频设计技巧,从背景音乐到动态音效,全面提升你的游戏氛围艺术——附实战代码示例与应用场景指导
【8月更文挑战第31天】音频设计在游戏开发中至关重要,不仅能增强沉浸感,还能传递信息,构建氛围。Unity作为跨平台游戏引擎,提供了丰富的音频处理功能,助力开发者轻松实现复杂音效。本文将探讨如何利用Unity的音频设计提升游戏氛围,并通过具体示例代码展示实现过程。例如,在恐怖游戏中,阴森的背景音乐和突然的脚步声能增加紧张感;在休闲游戏中,轻快的旋律则让玩家感到愉悦。
128 0
|
6月前
|
存储 JSON 关系型数据库
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
【unity实战】制作unity数据保存和加载系统——大型游戏存储的最优解
194 2
|
6月前
|
人工智能 定位技术 图形学
【unity实战】制作敌人的AI,使用有限状态机、继承和抽象类多态 定义不同状态的敌人行为
【unity实战】制作敌人的AI,使用有限状态机、继承和抽象类多态 定义不同状态的敌人行为
177 1
|
6月前
|
图形学
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统(下)
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统
93 0
|
6月前
|
图形学 容器
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统(上)
【unity实战】Unity中基于瓦片的网格库存系统——类似《逃离塔科夫》的库存系统
100 0
|
6月前
|
存储 JSON 图形学
【unity实战】制作unity数据保存和加载系统——小型游戏存储的最优解
【unity实战】制作unity数据保存和加载系统——小型游戏存储的最优解
203 0