You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity射击系统异常:未瞄准物体时射速过快致音效闪屏问题

问题根源

你当前的代码里,只有Raycast命中物体时才重置timeSinceLastShot,没命中目标(比如对准天空)时,timeSinceLastShot会持续累加,每次Update都会满足CanShoot()的条件,导致Shoot()被高频调用,进而AfterShoot()反复触发枪声、枪口闪,出现噪音和频闪问题。

解决方案

核心是不管是否命中目标,只要触发射击动作(满足射速条件),就重置timeSinceLastShot,保证射速控制逻辑始终生效。同时可以做一些小优化提升代码效率:

1. 修正Shoot()方法的重置逻辑

把timeSinceLastShot = 0;移到Raycast判断之外,确保每次触发Shoot()都重置计时:

private void Shoot() {
    RaycastHit hitInfo;
    // 重置射击计时,不管是否命中都生效
    timeSinceLastShot = 0;

    if(Physics.Raycast(cam.transform.position, cam.transform.forward, out hitInfo, maxDistance)){
        if (hitInfo.transform != null){
            IDamageable damageable = hitInfo.transform.GetComponent<IDamageable>();
            damageable?.TakeDamage(damage);

            GameObject instantiatedImpact = Instantiate(impactEffect, hitInfo.point, Quaternion.LookRotation(hitInfo.normal));
            instantiatedImpact.transform.SetParent(hitInfo.transform);
        }
    }

    AfterShoot();  
}

2. 缓存射速间隔,避免重复计算

每次调用CanShoot()都计算1f/(fireRate/60f)会浪费性能,建议在Awake()里提前计算并缓存:

private float fireInterval; // 新增变量存储射速间隔

private void Awake(){
    maxDistance = gunData.maxDistance;
    fireRate = gunData.fireRate;
    damage = gunData.damage;
    // 提前计算射击间隔,避免每次CanShoot重复计算
    fireInterval = 60f / fireRate;

    InputManager.startShootInput += IsShooting;
    InputManager.stopShootInput += NotShooting;
    InputManager.afterShoot += MuzzleFlash;
    InputManager.afterShoot += GunSoundEffect;
}

private bool CanShoot(){
    // 直接用缓存的fireInterval判断
    return (isShooting && (timeSinceLastShot > fireInterval));
}

3. 额外优化建议(可选)

  • 对于impactEffect,频繁实例化销毁会占用性能,建议使用对象池复用实例;
  • 可以给AfterShoot()加个判断,比如只有在isShooting为true时才触发,但核心问题解决后这个不是必须的。

内容的提问来源于stack exchange,提问作者Newebe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 04:25:25