Unity 2D近战战斗系统优化求助:现有代码存在多类BUG
修复后的流畅近战战斗系统方案
原代码核心问题分析
- 用
FixedUpdate处理输入:FixedUpdate是固定间隔执行,会导致输入检测不精准,要么错过按键要么重复触发 - 使用
Input.GetKey检测攻击:按住按键时会持续触发攻击,不符合近战单次攻击的逻辑 - 冷却时间重置逻辑错误:无论是否触发攻击都会重置冷却,导致冷却机制完全失效
- 无攻击判定去重/无敌帧:同一敌人在攻击判定帧内会被多次检测到,造成重复伤害
修复后的Weapon Script
using UnityEngine; public class Weapon : MonoBehaviour { [Header("攻击参数")] public float attackCooldown = 0.5f; // 攻击冷却时间 public Transform attackPos; public float attackRange = 0.5f; public LayerMask enemyLayer; public int damage = 40; public int lifeStealAmount = 20; [Header("引用")] public PlayerHealth playerHealth; private float _currentCooldown; void Update() { // 更新冷却时间 if (_currentCooldown > 0) { _currentCooldown -= Time.deltaTime; } // 仅在冷却结束时,检测单次按键触发攻击 if (Input.GetKeyDown(KeyCode.F) && _currentCooldown <= 0) { PerformAttack(); _currentCooldown = attackCooldown; // 触发攻击后才重置冷却 } } void PerformAttack() { // 检测攻击范围内的敌人 Collider2D[] hitEnemies = Physics2D.OverlapCircleAll(attackPos.position, attackRange, enemyLayer); foreach (var enemyCollider in hitEnemies) { EnemyHealth enemyHealth = enemyCollider.GetComponent<EnemyHealth>(); if (enemyHealth != null && !enemyHealth.IsInvulnerable) { enemyHealth.TakeDamage(damage); // 仅在成功命中敌人时触发吸血 playerHealth.LifeSteal(lifeStealAmount); } } } // Gizmos绘制攻击范围,方便调试 void OnDrawGizmosSelected() { if (attackPos != null) { Gizmos.color = Color.red; Gizmos.DrawWireSphere(attackPos.position, attackRange); } } }
修复后的Enemy Health Script
using UnityEngine; public class EnemyHealth : MonoBehaviour { [Header("生命值参数")] public int maxHealth = 100; public float invulnerabilityDuration = 0.3f; // 受伤后的无敌时间 private int _currentHealth; private float _invulnerabilityTimer; public bool IsInvulnerable => _invulnerabilityTimer > 0; void Start() { _currentHealth = maxHealth; } void Update() { // 更新无敌帧计时器 if (_invulnerabilityTimer > 0) { _invulnerabilityTimer -= Time.deltaTime; } } public void TakeDamage(int damage) { if (IsInvulnerable) return; // 无敌状态下不接受伤害 _currentHealth -= damage; Debug.Log("受到伤害,当前生命值:" + _currentHealth); // 触发无敌帧 _invulnerabilityTimer = invulnerabilityDuration; if (_currentHealth <= 0) { Die(); } } void Die() { Debug.Log("敌人死亡"); // 这里可以添加死亡动画、销毁物体等逻辑 Destroy(gameObject, 0.1f); } }
关键优化点说明
- 输入检测移至Update:保证输入响应精准,避免FixedUpdate的时间步导致的输入延迟或重复
- 使用Input.GetKeyDown:仅在按键按下的第一帧触发攻击,解决按住连续攻击的问题
- 冷却逻辑修正:只有成功触发攻击后才重置冷却时间,确保冷却机制正常工作
- 无敌帧机制:敌人受伤后短时间内不会再次受击,彻底解决重复伤害问题
- 攻击判定去重:通过无敌帧状态过滤已受击的敌人,避免同一攻击动作多次触发伤害
- 调试辅助:添加Gizmos绘制攻击范围,方便可视化调试攻击区域
内容的提问来源于stack exchange,提问作者itsmuffintime
相关产品推荐
相关产品推荐

