Unity RPG游戏切换玩家角色后敌人检测异常问题求助
问题描述
我正在用Unity开发一款RPG游戏,包含敌人和可通过菜单切换的多名玩家角色。目前遇到的问题是:敌人只会检测追踪其中一名角色,通过游戏内菜单切换操控角色后,敌人并非每次都能检测到新玩家,只有偶尔小概率成功。
敌人检测玩家脚本片段:
GameObject player; NavMeshAgent agent; Animator anim; float timePassed; float newDestinationCD = 0.5f; void Start() { player = GameObject.FindWithTag("Player"); agent = GetComponent<NavMeshAgent>(); anim = GetComponent<Animator>(); } void Update() { anim.SetFloat("speed", agent.velocity.magnitude / agent.speed); if (timePassed >= attackCD) { if (Vector3.Distance(player.transform.position, transform.position) <= attackRange) { anim.SetTrigger("attack"); timePassed = 0; } } timePassed += Time.deltaTime; if (newDestinationCD <= 0 && Vector3.Distance(player.transform.position, transform.position) <= aggroRange) { newDestinationCD = 0.5f; agent.SetDestination(player.transform.position); } newDestinationCD -= Time.deltaTime; transform.LookAt(player.transform); }
玩家选择脚本:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class PlayerSelection : MonoBehaviour { private GameObject[] characterList; private int index; private void Start() { index = PlayerPrefs.GetInt("selectedCharacter"); characterList = new GameObject[transform.childCount]; for (int i = 0; i < transform.childCount; i++) characterList[i] = transform.GetChild(i).gameObject; foreach (GameObject go in characterList) go.SetActive(false); if (characterList[index]) characterList[index].SetActive(true); } public void NextCharacter() { characterList[index].SetActive(false); index++; if (index == characterList.Length) { index =0; } characterList[index].SetActive(true); } public void PreviousCharacter() { characterList[index].SetActive(false); index--; if (index < 0) { index = characterList.Length - 1; } characterList[index].SetActive(true); } public void startGame() { PlayerPrefs.SetInt("selectedCharacter", index); SceneManager.LoadScene(1); } }
测试情况:
首次启动选择Chonon(第3名角色)时,敌人可检测到;切换到Maria(第2名)后敌人无法检测;切换到Ganfaul(第1名)时敌人可检测;再次切回Chonon则无法检测,但Ganfaul始终能被敌人检测到。
问题根源与修复方案
核心问题
敌人脚本仅在Start()方法中执行一次GameObject.FindWithTag("Player")获取玩家对象,后续切换角色时:
- 旧角色可能仍保留
Player标签,导致敌人持续追踪旧角色 - 新角色可能未被正确赋予
Player标签,或者敌人没有更新玩家引用
修复步骤
1. 优化玩家选择脚本:切换角色时同步更新Player标签
修改角色切换逻辑,确保激活的角色拥有Player标签,未激活角色移除该标签:
public void NextCharacter() { // 移除旧角色的Player标签 characterList[index].tag = "Untagged"; characterList[index].SetActive(false); index++; if (index == characterList.Length) { index = 0; } // 给新角色添加Player标签 characterList[index].tag = "Player"; characterList[index].SetActive(true); } public void PreviousCharacter() { // 移除旧角色的Player标签 characterList[index].tag = "Untagged"; characterList[index].SetActive(false); index--; if (index < 0) { index = characterList.Length - 1; } // 给新角色添加Player标签 characterList[index].tag = "Player"; characterList[index].SetActive(true); } private void Start() { index = PlayerPrefs.GetInt("selectedCharacter"); characterList = new GameObject[transform.childCount]; for (int i = 0; i < transform.childCount; i++) characterList[i] = transform.GetChild(i).gameObject; foreach (GameObject go in characterList) { go.SetActive(false); go.tag = "Untagged"; // 初始化所有角色为无标签 } if (characterList[index]) { characterList[index].tag = "Player"; // 给初始角色添加Player标签 characterList[index].SetActive(true); } }
2. 优化敌人检测脚本:定期更新玩家引用
避免仅在Start()中获取玩家,改为定期检查并更新玩家对象,确保追踪当前激活的玩家:
GameObject player; NavMeshAgent agent; Animator anim; float timePassed; float newDestinationCD = 0.5f; float playerCheckCD = 1f; // 每隔1秒检查一次玩家 float playerCheckTimer = 0f; void Start() { agent = GetComponent<NavMeshAgent>(); anim = GetComponent<Animator>(); UpdatePlayerReference(); // 初始获取玩家 } void Update() { // 定期更新玩家引用 playerCheckTimer += Time.deltaTime; if (playerCheckTimer >= playerCheckCD) { UpdatePlayerReference(); playerCheckTimer = 0f; } if (player == null) return; // 防止空引用报错 anim.SetFloat("speed", agent.velocity.magnitude / agent.speed); if (timePassed >= attackCD) { if (Vector3.Distance(player.transform.position, transform.position) <= attackRange) { anim.SetTrigger("attack"); timePassed = 0; } } timePassed += Time.deltaTime; if (newDestinationCD <= 0 && Vector3.Distance(player.transform.position, transform.position) <= aggroRange) { newDestinationCD = 0.5f; agent.SetDestination(player.transform.position); } newDestinationCD -= Time.deltaTime; transform.LookAt(player.transform); } // 封装更新玩家引用的方法 void UpdatePlayerReference() { player = GameObject.FindWithTag("Player"); }
额外建议
- 可以使用单例模式管理当前玩家,比如创建
PlayerManager单例维护激活玩家对象,敌人直接从单例获取引用,比标签查找更高效可靠。 - 检查所有玩家角色的初始标签设置,确保初始状态下只有选中角色带有
Player标签。
内容的提问来源于stack exchange,提问作者Scar Fia
相关产品推荐
相关产品推荐

