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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 03:05:48