Unity 2D平台游戏敌人无法向玩家移动攻击的问题求助
Unity 2D敌人跳跃后追踪玩家功能失效的排查与修复
问题说明
在2D平台游戏中设置的敌人,预期跳跃后会向玩家当前位置移动,但代码中的transform.position = Vector2.MoveTowards(transform.position, playerPosition, JumpAttackSpeed * Time.deltaTime);语句未生效,导致追踪功能失败。
核心问题分析
- 协程重复触发:Update函数中
if (distance < AttackRange || canAttack)的条件会每帧启动Attack协程,多个协程同时运行会频繁修改canAttack状态,干扰跳跃后的移动逻辑。 - 位置判断精度问题:直接用
transform.position != playerPosition判断到达目标位置,由于浮点精度误差,这个条件几乎永远为真,会提前触发冷却,打断移动。 - 冷却协程重复启动:Update的else分支每帧都会启动AttackCooldawn协程,导致
canAttack被提前设为true,跳跃移动阶段被强制终止。 - 状态流转不完整:Attack协程结束后没有正确衔接冷却流程,导致状态逻辑混乱。
修复方案与代码调整
修复关键点
- 新增
isCooldownRunning标志位,避免冷却协程重复启动。 - 用距离阈值判断是否到达目标位置,替代直接的Vector3相等比较。
- 调整攻击触发逻辑,仅当
canAttack为true且距离符合条件时启动Attack协程。 - 完善Attack协程的流程,在跳跃攻击结束后主动启动冷却。
修复后的完整代码
using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemyScript : MonoBehaviour { public Rigidbody2D rb; public GameObject player; private Vector3 playerPosition; public float NormalSpeed; private float distance; private bool canAttack = true; private bool isCooldownRunning = false; // 防止冷却协程重复启动 public float AttackRange; public float JumpAttackRange; public float JumpForce; public float JumpAttackPreTime; public float JumpAttackTime; public float JumpAttackSpeed; public float AttackCooldawnTime; public float PositionCheckThreshold = 0.1f; // 位置判断的误差阈值 void Update() { distance = Vector2.Distance(transform.position, player.transform.position); // 跳跃攻击阶段:向目标位置移动 if (!canAttack) { float distanceToTarget = Vector2.Distance(transform.position, playerPosition); if (distanceToTarget > PositionCheckThreshold) { transform.position = Vector2.MoveTowards(transform.position, playerPosition, JumpAttackSpeed * Time.deltaTime); } else { // 到达目标后启动冷却 if (!isCooldownRunning) { StartCoroutine(AttackCooldawn()); } } } else { // 可攻击状态:检查是否满足跳跃攻击条件 if (distance < AttackRange && distance < JumpAttackRange) { StartCoroutine(Attack()); } } } private IEnumerator Attack() { canAttack = false; isCooldownRunning = false; // 执行跳跃 rb.velocity = new Vector2(rb.velocity.x, JumpForce); yield return new WaitForSeconds(JumpAttackPreTime); // 停止垂直移动并关闭重力 rb.velocity = new Vector2(0, 0); float normalGravity = rb.gravityScale; rb.gravityScale = 0; // 记录当前玩家位置作为追踪目标 playerPosition = player.transform.position; // 保持追踪状态一段时间 yield return new WaitForSeconds(JumpAttackTime); // 恢复重力 rb.gravityScale = normalGravity; // 启动冷却流程 StartCoroutine(AttackCooldawn()); } private IEnumerator AttackCooldawn() { isCooldownRunning = true; yield return new WaitForSeconds(AttackCooldawnTime); canAttack = true; isCooldownRunning = false; } }
内容的提问来源于stack exchange,提问作者Simone Bernardini
相关产品推荐
相关产品推荐

