Unity如何实现敌人攻击动画过程中仅对玩家造成一次伤害
解决方案
方案1:使用动画事件实现(最稳定,推荐)
该方式可以完全和攻击动画的播放进度绑定,不受动画速度、状态切换延迟影响:
- 在Unity编辑器中打开敌人的攻击动画Clip,在时间轴上找到你需要重置攻击标记的位置(攻击动画起始帧/结束帧均可),添加动画事件,选择调用脚本中的
ResetAttackFlag方法 - 在你的逻辑脚本中添加如下方法,原有代码中判断
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
相关产品推荐
相关产品推荐

