脚本在一个游戏对象上正常工作,但在另一个游戏对象上却不行

Posted

技术标签:

【中文标题】脚本在一个游戏对象上正常工作,但在另一个游戏对象上却不行【英文标题】:Script working properly on one gameobject, but not on another 【发布时间】:2018-06-10 15:48:48 【问题描述】:

我有一个很奇怪的问题。

我使用 navmesh 工具和自定义脚本创建了一个 AI,一旦到达旧目的地,它就会不断为 navmesh 代理分配一个新目的地。

我不得不为这个 AI 替换模型(之前是一个胶囊),所以我这样做了,复制了几乎所有的组件,调整了一些参数,比如代理高度等,然后运行它。

胶囊 AI 正常工作,但具有正确模型的 AI 显然没有。调试后,我发现建模 AI 的目标列表包含 Vector3.zero 的,而胶囊 AI 在其目标列表中有正确的 vector3s。

这是我的 AI 目标脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;

public class AIMovement : MonoBehaviour


private NavMeshAgent _navMeshAgent;                         //reference to the navmesh agent
private MapController _mapControllerScript;                 //reference to the map controller script to access waypoints
private List<Vector3> _wayPoints = new List<Vector3>();
private Vector3 _destination;

// Use this for initialization
void Start()

    _mapControllerScript = GameObject.Find("Map_01").GetComponent<MapController>();
    SetWayPointLocations();
    _navMeshAgent = this.GetComponent<NavMeshAgent>();

    Debug.Log(_mapControllerScript.ToString());
    Debug.Log(_mapControllerScript.HealthPickUpPositions.ToString());
    Debug.Log(_navMeshAgent);
    Debug.Log(_wayPoints);
    foreach (Vector3 waypoint in _wayPoints)
    
        Debug.Log(waypoint);
    


// Update is called once per frame
void Update()

    MoveAroundMap();


void MoveAroundMap()

    if (_navMeshAgent.transform.position.x == _destination.x &&
        _navMeshAgent.transform.position.z == _destination.z
        || _destination == new Vector3(0, 0, 0)
        )
    
        Debug.Log("Acquiring new position");
        _destination = _wayPoints[Random.Range(0, _wayPoints.Count-1)];
    

    _navMeshAgent.SetDestination(_destination);


void SetWayPointLocations()

    foreach (Vector3 waypoint in _mapControllerScript.HealthPickUpPositions)
    
        _wayPoints.Add(waypoint);
    
    foreach (Vector3 waypoint in _mapControllerScript.AmmoPickUpPositions)
    
        _wayPoints.Add(waypoint);
    


这是控制台:你可以清楚地看到胶囊 AI 的坐标是正确的,而破碎的 AI 的坐标是 (0, 0, 0)

这是层次结构窗口:Capsule 是工作的 AI,Character_Piccolo 是不工作的。

这是胶囊的检查员工作的人工智能

这是模型的inspector破碎的AI

抱歉,拖了这么久,但我想确保你们了解所有需要的信息。

提前致谢!

【问题讨论】:

哪个字段有零,_destination 或 _wayPoints?另外,在 MapController 组件中,pickUpPosition 是设置在 Start 上还是 Awake 上?最后,我认为问题可能出在 MoveArroundMap 方法中的 if 语句中。你能在里面放一个日志,看看你能不能到达那里吗? _wayPoints 数组有 5 个 Vector3 为 (0,0,0)。由于是这种情况,_destination 也是 (0,0,0),因为 _destination 将保存 _wayPoint Vector3 之一的值。 PickUpPositions 在 MapController.cs 的 Start() 中设置我在 MoveAroundMap 方法中有一个 Debug.Log,表示“获取新位置”。这会一直被调用,因为 _destination 是 (0,0,0)。 您可以尝试在 MapController 的 Awake 方法上设置 PickUpPositions 吗? 先生,您是救生员。这正是让它发挥作用的原因,这太神奇了。我整个晚上都在这个该死的虫子上!您能否详细说明我的代码到底出了什么问题?如果我可能猜到:这是我试图在一个脚本中填充 PickUpPositions 的事实,然后它存在于另一个脚本中?无论如何,非常感谢! 我要写一个正确的答案 【参考方案1】:

问题 - 也是解决方案 - 不在您的 AIMovement 脚本中,也不在您从胶囊更改为新模型时所做的任何编辑中,甚至不在您在问题中提供的任何脚本和组件中.问题是你 MapController 类的一个微妙之处,它一直存在(甚至在你的更改之前),而你之前没有遇到这个错误的事实是偶然的。

正如您在 cmets 中所说,您正在其 Start() 方法中设置 MapController 类的 HealthPickUpPositionsAmmoPickUpPositions 属性。您正在组件类的 Start() 方法上读取这些属性的值。问题是:一旦在加载的场景上设置了游戏对象,启动消息就会运行,但是对象开始的顺序不取决于您的游戏逻辑(它取决于场景层次结构、预制件、对象实例编号和其他东西,无论如何...)并且应该被认为是随机的

在您的特定情况下,您的AIMovementStart()MapControllerStart() 之前被调用,即在设置属性的正确值之前 - 因此,您读取的所有内容都是零向量(默认值)。

因此,unity 在游戏对象上有一个类似的消息,名为 Awake()。您也不知道唤醒对象的顺序,但您可以确保只有在所有Awake() 消息都已发送后才会发送任何Start() 消息。更多关于 here、here、here 和 here 的信息。

解决方案:将类的所有内部初始化逻辑都放在Awake方法中;以及 Start 方法上与其他游戏对象的所有连接(假设它们已初始化)。

【讨论】:

谢谢,我现在明白了。我在一个类的 start 函数中填充了数组,而我在另一个类的 start 函数中引用了它,但不知道首先调用哪个 start 函数。解释的很好,非常感谢。最后一个问题:一直在我的所有类中使用 Awake 方法来初始化这些类的所有变量有什么缺点吗?我想防止这种情况在未来发生,但不以糟糕的编码习惯为代价。 是的,有一个问题:你不应该尝试从 Awake 内部查询或获取其他类的状态 - 你不知道它们是否已经初始化(你最多可以引用其他游戏对象,像 getComponent 和其他东西,但不是它们的字段或方法)。一般规则是:将自己设置为 Awake 并在 Start 上与其他课程相关。

以上是关于脚本在一个游戏对象上正常工作,但在另一个游戏对象上却不行的主要内容,如果未能解决你的问题,请参考以下文章

无法更改附加到游戏对象的脚本上的公共变量。值在播放时恢复

使用字符串 Unity 从游戏对象获取脚本

我的 Unity 游戏在测试轨道中运行,但在生产轨道中无法运行

Unity脚本生命周期与执行顺序

Laravel 视图显示在一台服务器上的缓存中,但在另一台服务器上工作正常

如何通过 GetComponent 从另一个游戏对象中的另一个脚本访问变量?