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

Unity如何实现敌人攻击动画过程中仅对玩家造成一次伤害

解决方案

方案1:使用动画事件实现(最稳定,推荐)

该方式可以完全和攻击动画的播放进度绑定,不受动画速度、状态切换延迟影响:

  1. 在Unity编辑器中打开敌人的攻击动画Clip,在时间轴上找到你需要重置攻击标记的位置(攻击动画起始帧/结束帧均可),添加动画事件,选择调用脚本中的ResetAttackFlag方法
  2. 在你的逻辑脚本中添加如下方法,原有代码中判断normalizedTime > 0.7f重置标记的逻辑可以直接删除:
// 供动画事件调用,重置攻击标记
public void ResetAttackFlag()
{
    alreadyAttacked = false;
}

方案2:修改现有代码逻辑修复

如果不想使用动画事件,可调整原有判定逻辑,优先校验当前是否处于攻击动画状态,避免其他动画状态干扰判定:

void FixedUpdate()
{
    playerInSightRange = Physics.CheckSphere(transform.position, sightRange, playerMask);
    playerInAttackRange = Physics.CheckSphere(transform.position, attackRange, playerMask);

    if (!playerInSightRange && !playerInAttackRange) Patroling();
    if (playerInSightRange && !playerInAttackRange) Chasing();
    if (playerInSightRange && playerInAttackRange) Attacking();
}

private void Attacking()
{
    animator.SetInteger("Condition", 2);
    agent.SetDestination(player.position);

    AnimatorStateInfo currentState = animator.GetCurrentAnimatorStateInfo(0);
    // 替换双引号内的名称为你实际的攻击动画状态名称
    if (currentState.IsName("Attack"))
    {
        if (currentState.normalizedTime > 0.4f 
            && currentState.normalizedTime < 0.6f 
            && !alreadyAttacked)
        {
            // 提前缓存Player的Health组件可优化性能,无需每次判定都调用GetComponent
            player.GetComponent<Health>().healthValue -= damage / 100f;
            alreadyAttacked = true;
        } 

        // 攻击动画播放完整一轮后重置标记
        if (currentState.normalizedTime >= 1f )
        {
            alreadyAttacked = false;
        }  
    }
}

额外注意事项

  • 动画更新逻辑走Unity的Update生命周期,FixedUpdate为物理帧,和动画帧频率不一致,建议将攻击判定逻辑移至Update中执行,避免漏判/多判
  • 若攻击动画设置了循环播放,建议取消循环,或在状态机中配置攻击完成后自动切回Idle/Chase状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 08:18:03