You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 13:52:05