Unity弹药碰撞脚本弹药耗尽仍可摧毁小行星问题
问题现象
Unity开发弹药系统时出现逻辑异常:初始弹药值设为10,弹药耗尽后本应跳转死亡界面,实际仍可触发碰撞逻辑持续摧毁小行星,原始实现代码如下:
using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class ExplosionOnTouch : MonoBehaviour { // Start is called before the first frame update public int Ammo = 10; void Start() { } // Update is called once per frame void Update() { } private void OnCollisionEnter2D(Collision2D collision) { if (Ammo > 0) { Ammo = Ammo - 1; Destroy(gameObject); } else { SceneManager.LoadScene("DeathScreen", LoadSceneMode.Single); } } }
问题原因
- 核心问题是
Ammo是实例字段:如果这个脚本挂在子弹预制体上,每生成一颗新子弹,该子弹实例的Ammo都会重置为Inspector里配置的初始值10,碰撞时仅扣减当前子弹自己的弹药计数,扣完1就销毁自身,永远不会触发弹药归零的分支,全局总弹药数根本没有被累计扣减。 - 没有做碰撞对象校验:只要碰到任何带碰撞体的物体都会触发弹药扣减/场景跳转逻辑,容易误触发。
- 销毁目标错误:代码里
Destroy(gameObject)销毁的是挂载脚本的当前物体,没有显式销毁碰撞到的小行星,逻辑和预期不符。
修复方案
- 优先把弹药计数逻辑从子弹实例剥离,单独做全局/玩家维度的弹药管理;如果暂时不想拆分脚本,可把
Ammo设为静态字段,让所有实例共享同一个总弹药计数。 - 增加碰撞层判断,仅当碰撞对象是小行星时才触发弹药逻辑。
- 修正销毁目标,碰撞后同时销毁小行星和子弹(如果脚本挂在子弹上),弹药归零时正常跳转死亡场景。
- 增加弹药重置方法,避免静态值跨局残留。
修复后的参考代码:
using UnityEngine; using UnityEngine.SceneManagement; public class ExplosionOnTouch : MonoBehaviour { // 静态字段所有实例共享,全局统一扣减总弹药 public static int Ammo = 10; // 配置小行星所在层,在Inspector面板选择对应层即可 public LayerMask asteroidLayer; private void OnCollisionEnter2D(Collision2D collision) { // 非小行星碰撞直接忽略,不触发逻辑 if (((1 << collision.gameObject.layer) & asteroidLayer) == 0) { return; } if (Ammo > 0) { Ammo--; // 销毁碰撞到的小行星 Destroy(collision.gameObject); // 销毁当前子弹(脚本挂在子弹上时保留这行,挂在其他物体上可删除) Destroy(gameObject); } else { SceneManager.LoadScene("DeathScreen", LoadSceneMode.Single); } } // 重开游戏时调用该方法重置弹药,避免静态值跨局残留 public static void ResetAmmo() { Ammo = 10; } }
额外优化建议
- 长期维护建议单独实现单例模式的弹药管理器,把弹药扣减、数值校验、事件触发逻辑统一收口,不要把全局状态存在子弹这类临时生成的物体上。
- 可以给弹药数增加UI更新事件,每次弹药变化时主动刷新UI显示,避免UI和实际数值不一致。
内容的提问来源于stack exchange,提问作者RRTropical
相关产品推荐
相关产品推荐

