Unity敌人AI故障:添加停止追击代码后完全停止追击
嘿,我帮你揪出问题根源了——你的代码里有几个容易忽略的小错误,直接导致敌人完全停止追击,咱们一个个说:
1. 致命的拼写错误
在EnemyAgro脚本里,你定义的生命值变量是curentHealth(少了个字母'r'),但在Update的停止追击判断里却写了currentHealth <= 0。这会让Unity把currentHealth当成一个未初始化的新变量,默认值是0,所以这个条件永远为真!不管玩家是不是在仇恨范围内、敌人活没活着,都会触发StopChasingPlayer(),这就是敌人直接躺平的核心原因。
2. EnemyHealth组件获取方式完全错了
在EnemyAgro的Start方法里,你写了:
enemyHealth = enemyHealth.GetComponent<EnemyHealth>();
这相当于用一个还没赋值的null变量去调用GetComponent,结果enemyHealth还是null,根本拿不到敌人的生命值数据。正确的做法分两种:
- 如果
EnemyHealth和EnemyAgro脚本挂在同一个敌人GameObject上,直接这么写:enemyHealth = GetComponent<EnemyHealth>(); - 如果你的
Enemy变量是在Inspector里拖拽赋值的敌人对象,就用这个变量获取组件:enemyHealth = Enemy.GetComponent<EnemyHealth>();
3. 生命值没有实时同步
就算前面两个问题修复了,你现在的curentHealth只在Start里赋值了一次,之后敌人掉血时,这个变量不会自动同步EnemyHealth里的真实生命值。敌人死了它还是初始的20,根本触发不了停止追击的条件。所以得在Update里实时拉取最新的生命值,或者用事件监听(更高效)。
修复后的完整EnemyAgro脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemyAgro : MonoBehaviour { public GameObject Enemy; // 不需要的话可以删掉,要留的话记得在Inspector赋值 private EnemyHealth enemyHealth; private int currentHealth; // 修正拼写错误! [SerializeField] Transform player; [SerializeField] float agroRange; [SerializeField] float moveSpeed; public Rigidbody2D rb2d; public void Start() { // 修复组件获取:假设两个脚本在同一个对象上 enemyHealth = GetComponent<EnemyHealth>(); // 如果用Enemy变量,就替换成下面这行: // enemyHealth = Enemy.GetComponent<EnemyHealth>(); currentHealth = enemyHealth.health; rb2d = GetComponent<Rigidbody2D>(); } void Update() { float distToPlayer = Vector2.Distance(transform.position, player.position); // 实时同步生命值,确保拿到最新状态 currentHealth = enemyHealth.health; // 优化判断逻辑:只有玩家在范围内且敌人活着,才追击 if(distToPlayer < agroRange && currentHealth > 0){ ChasePlayer(); } else { Debug.Log("Chase Stopped"); StopChasingPlayer(); } } private void ChasePlayer(){ if(transform.position.x < player.position.x){ rb2d.velocity = new Vector2(moveSpeed,0); transform.localScale = new Vector2(1,1); } else if(transform.position.x > player.position.x){ rb2d.velocity = new Vector2(-moveSpeed,0); transform.localScale = new Vector2(-1,1); } } public void StopChasingPlayer(){ rb2d.velocity = Vector2.zero; } }
额外优化建议(可选)
如果你想让代码更高效,可以用EnemyHealth里的OnHealthChanged事件来监听生命值变化,不用在Update里每帧都拉取:
在EnemyAgro的Start方法里加一行:
enemyHealth.OnHealthChanged += EnemyHealth_OnHealthChanged;
然后添加事件处理方法:
private void EnemyHealth_OnHealthChanged(object sender, System.EventArgs e){ currentHealth = enemyHealth.health; }
记得在脚本销毁时移除监听,避免内存泄漏:
private void OnDestroy(){ if(enemyHealth != null){ enemyHealth.OnHealthChanged -= EnemyHealth_OnHealthChanged; } }
另外,你的EnemyHealth脚本里有重复的Health()和GetHealth()方法,建议删掉其中一个,避免自己混淆。
这样修复后,敌人就会正常工作:玩家在仇恨范围内时追击,离开范围或者死亡后立刻停止。
内容的提问来源于stack exchange,提问作者ISavageFreak24

