Unity2D敌人未触发攻击问题及敌我击退功能实现求助
Unity2D敌人攻击逻辑修复与双向击退实现
问题描述
使用Unity2D v2022.3.17f1开发游戏时,敌人可在追踪范围内正常跟随玩家,但接触玩家时无法停止并发起攻击。玩家与敌人均挂载BoxCollider2D和RigidBody2D组件,需同时实现敌人攻击玩家时的双向击退功能。
原代码
using System.Collections.Generic; using UnityEngine; public class EnemyController : MonoBehaviour { public Player player; public float speed = 3f; public float damage = 2f; public float attackDistance = 1f; public float followDistance = 5f; private bool isAttacking = false; void Update() { Vector2 direction = player.transform.position - transform.position; float distance = direction.magnitude; if (distance < followDistance) { if (distance < attackDistance && !isAttacking) { Debug.Log("Enemy is attacking"); StartCoroutine(Attack()); } else { if (distance > attackDistance) { MoveTowardsTarget(direction); } else { StopMoving(); } } } } void MoveTowardsTarget(Vector2 direction) { direction.Normalize(); transform.Translate(direction * speed * Time.deltaTime); } void StopMoving() { Rigidbody2D rb = GetComponent<Rigidbody2D>(); rb.velocity = Vector2.zero; } IEnumerator Attack() { isAttacking = true; StopMoving(); player.TakeDamage(damage); yield return new WaitForSeconds(1.0f); isAttacking = false; MoveTowardsTarget(player.transform.position - transform.position); } private void OnCollisionEnter2D(Collision2D collision) { if (collision.gameObject.CompareTag("Player")) { StopMoving(); } } }
修复方案与双向击退实现
修改后代码
using UnityEngine; using System.Collections; public class EnemyController : MonoBehaviour { public Player player; public float speed = 3f; public float damage = 2f; public float attackDistance = 1.2f; // 建议设为两者碰撞器半径之和 public float followDistance = 5f; public float knockbackForce = 6f; // 双向击退的力度参数 private bool isAttacking = false; private Rigidbody2D rb; void Awake() { rb = GetComponent<Rigidbody2D>(); // 提前获取组件,减少性能消耗 } void Update() { Vector2 direction = player.transform.position - transform.position; float distance = direction.magnitude; // 仅在非攻击状态、且在追踪范围内时处理逻辑 if (distance < followDistance && !isAttacking) { if (distance <= attackDistance) { StartCoroutine(Attack(direction)); } else { MoveTowardsTarget(direction); } } } void MoveTowardsTarget(Vector2 direction) { direction.Normalize(); rb.velocity = direction * speed; // 改用Rigidbody控制移动,适配物理系统 } void StopMoving() { rb.velocity = Vector2.zero; } IEnumerator Attack(Vector2 direction) { isAttacking = true; StopMoving(); // 触发玩家受伤 player.TakeDamage(damage); // 执行双向击退:敌人向后退,玩家向相反方向被推开 rb.AddForce(-direction.normalized * knockbackForce, ForceMode2D.Impulse); player.GetComponent<Rigidbody2D>().AddForce(direction.normalized * knockbackForce, ForceMode2D.Impulse); yield return new WaitForSeconds(1.0f); isAttacking = false; } }
关键修改说明
- 移动逻辑优化:替换
transform.Translate为Rigidbody2D.velocity,让敌人移动遵循Unity物理规则,避免和碰撞组件冲突,确保接触玩家时能稳定停止。 - 攻击触发调整:
- 提前在
Awake中获取Rigidbody2D组件,避免重复调用GetComponent。 - 收紧Update条件判断,确保只有非攻击状态下才会触发移动或攻击。
- 攻击时传入方向参数,用于计算击退方向。
- 提前在
- 双向击退实现:在攻击协程中,给敌人和玩家施加相反方向的冲量,实现双向击退效果(需确保玩家Rigidbody2D的约束设置允许受力)。
- 移除冗余碰撞逻辑:原
OnCollisionEnter2D中的停止逻辑会和Update的距离判断冲突,直接移除后用攻击范围判断控制敌人行为更合理。
额外注意事项
- 调整
attackDistance参数:建议设置为敌人与玩家碰撞器的半径之和,确保敌人在即将接触玩家时触发攻击,而非重叠后才触发。 - 检查Layer设置:确保玩家和敌人的Layer设置正确,碰撞检测规则正常生效。
- 玩家
TakeDamage方法:需确保该方法已正确实现生命值扣减等逻辑。
内容的提问来源于stack exchange,提问作者Nova
相关产品推荐
相关产品推荐

