Unity 2D敌人AI射线检测追踪玩家失效问题求助
2D平台游戏敌人AI问题排查与修复建议
问题概述
- 敌人唤醒Trigger功能正常,但玩家进入Raycast检测范围后,敌人未执行追逐逻辑
- Raycast前方存在“Action”层物体时,无法保持
isAgro为true的状态 - 怀疑问题出在
isAgro变量的逻辑处理上
敌人子物体层级结构:
问题代码
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class Presentsaswehear : MonoBehaviour { // Start is called before the first frame update // trigger code ignore private Animator Enemtestone; public GameObject FirstTrig; public static bool Izintyloip; private bool Thecheckert; // trigger code ignore //Enemy part tracking blablablaaaaa [SerializeField] Transform Player; [SerializeField] float agroRange; [SerializeField] Transform castPoint; [SerializeField] float moveSpeed; Rigidbody2D rb2det; bool isFacingLeft; //true private bool isAgro = true; private bool isSearching; void Start() { Enemtestone = GetComponent<Animator>(); //FirstTrig.SetActive(true); Izintyloip = false; rb2det = GetComponent<Rigidbody2D>(); Thecheckert = false; } // Update is called once per frame void Update() { // trigger code ignore if (Izintyloip == true) { Enemtestone.SetInteger("Wakeup", 1); Thecheckert = true; } // trigger code ignore if (CanSeePlayer(agroRange)) { isAgro = true; //ChasePlayer(); uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu } else { if (isAgro) { //isSearching = true; if(!isSearching) { isSearching = true; Invoke("StopChasingPlayer", 5); } } } if (isAgro) { ChasePlayer(); } } bool CanSeePlayer(float distance) { bool val = false; float castDist = distance; if (isFacingLeft) { castDist = -distance; } Vector2 endPos = castPoint.position + Vector3.right * castDist; RaycastHit2D hit = Physics2D.Linecast(castPoint.position, endPos, 1 << LayerMask.NameToLayer("Action")); if(hit.collider != null) { //(hit.collider.gameObject.CompareTag("Player")) if (hit.collider.gameObject.CompareTag("Player")) { val = true; } else { val = false; } Debug.DrawLine(castPoint.position, hit.point, Color.yellow); } else { Debug.DrawLine(castPoint.position, endPos, Color.blue); } return val; } void ChasePlayer() { if(transform.position.x < Player.position.x) { rb2det.velocity = new Vector2(moveSpeed, 0); transform.eulerAngles = new Vector3(0, 180, 0); isFacingLeft = false; } else { rb2det.velocity = new Vector2(-moveSpeed, 0); transform.eulerAngles = new Vector3(0, 0, 0); isFacingLeft = true; // if(transform.position.x > player.postion.x) } Enemtestone.SetBool("GFW", true); } void StopChasingPlayer() { isAgro = false; rb2det.velocity = new Vector2(0, 0); isSearching = false; Enemtestone.SetBool("GFW", false); } }
问题分析
isAgro初始值错误:默认设为true,但唤醒逻辑未关联agro状态,导致敌人初始就处于追逐状态,不符合“唤醒后才响应视线”的设计逻辑。- LayerMask检测范围不足:
CanSeePlayer函数仅检测“Action”层,玩家不在该层时无法被检测到;同时遇到“Action”层物体时直接返回false,导致isAgro被重置。 isFacingLeft未初始化:初始值未显式设置,可能导致Raycast方向与敌人实际朝向不符。- 搜索状态未及时重置:重新检测到玩家时,未取消之前触发的
StopChasingPlayer调用,导致isAgro被错误设为false。
修复方案
1. 修正isAgro初始值与唤醒逻辑绑定
将isAgro初始值改为false,确保敌人唤醒后才具备响应视线的能力:
// 初始化改为 private bool isAgro = false; // Update中的唤醒逻辑保持原有唤醒动画逻辑即可
2. 修复CanSeePlayer函数的检测逻辑
扩展LayerMask范围,同时处理“Action”层物体的检测逻辑,保持当前isAgro状态:
bool CanSeePlayer(float distance) { bool val = false; float castDist = distance; if (isFacingLeft) { castDist = -distance; } Vector2 endPos = castPoint.position + Vector3.right * castDist; // 同时检测Player层和Action层 int layerMask = (1 << LayerMask.NameToLayer("Player")) | (1 << LayerMask.NameToLayer("Action")); RaycastHit2D hit = Physics2D.Linecast(castPoint.position, endPos, layerMask); if(hit.collider != null) { Debug.DrawLine(castPoint.position, hit.point, Color.yellow); if (hit.collider.gameObject.CompareTag("Player")) { val = true; } else if (hit.collider.gameObject.layer == LayerMask.NameToLayer("Action")) { // 检测到Action层物体,保持当前agro状态 val = isAgro; } else { val = false; } } else { Debug.DrawLine(castPoint.position, endPos, Color.blue); val = false; } return val; }
3. 初始化isFacingLeft
在Start函数中添加初始朝向设置,确保Raycast方向正确:
void Start() { Enemtestone = GetComponent<Animator>(); Izintyloip = false; rb2det = GetComponent<Rigidbody2D>(); Thecheckert = false; // 根据敌人初始朝向设置,示例为朝右 isFacingLeft = false; }
4. 重置搜索状态
当重新检测到玩家时,取消之前的StopChasingPlayer调用:
if (CanSeePlayer(agroRange)) { isAgro = true; // 取消正在进行的停止追逐调用 if(isSearching) { CancelInvoke("StopChasingPlayer"); isSearching = false; } }
内容的提问来源于stack exchange,提问作者Cyber studios
相关产品推荐
相关产品推荐

