Unity3d从计时器

时间:2017-09-11 15:25:18

标签: c# multithreading unity3d timer

尝试从这样的计时器访问gameobjects位置时:

public static void Start()
{
    if(!timerStarted)
    {
        timerStarted = true;
        timer = new Timer();
        timer.Interval = 1000;

        timer.Elapsed += CheckEarnings;
        timer.AutoReset = true;
        timer.Enabled = true;
    }            
}

private static void CheckEarnings(object sender, ElapsedEventArgs e)
{
    foreach (BuildingData building in BuildingRegistry.registeredBuildings)
    {
        MonoBehaviour.print(building.attachedGameObject.transform.position);
    }
}

(如果这有任何区别,则在静态类中)

...抛出以下错误:

  

get_transform只能从主线程调用。   加载场景时,将从加载线程执行构造函数和字段初始值设定项。   不要在构造函数或字段初始值设定项中使用此函数,而是将初始化代码移动到Awake或Start函数。   UnityEngine.GameObject:get_transform()   PlayerManagement:CheckEarnings(Object,ElapsedEventArgs)(在Assets / Scripts / PlayerManagement.cs:53)   System.Timers.Timer:回调(对象)

对我来说,看起来还有另一个为计时器创建的线程无法访问主线程。 我该如何解决这个问题?

2 个答案:

答案 0 :(得分:0)

最初没有针对交叉线程操作的保护。最终结果不是最优的,而且通常是非确定性的。因此添加了CrossThreadExceptions。避免它们的正确方法是invoke。但是我的知识是关于C#.NET,而不是Unity。在Unity中,可能会有不同的名字命名。

请注意,不同的“Timer”类可能会有完全不同的行为。也就是说,.NET实际上不少于4个'Timer'类,其行为不会更加不同。写这篇文章时解释它们只有3: https://web.archive.org/web/20150329101415/https://msdn.microsoft.com/en-us/magazine/cc164015.aspx

答案 1 :(得分:0)

你认为问题是计时器在一个单独的线程上运行是正确的,它说有很多不同的解决方案。我假设您根据语法使用System.Timers.Timer,这在您的实例中意味着计时器在ThreadPool上运行已过去的事件。

如果您打算使用C#定时器而不是使用Time.deltaTime创建自己的计时器,那么问题就变成了如何在单独的线程上使用UnityAPI,简单的事实是您不能。 Unity在设计时是线程安全的,因此您必须创建一个系统,通过创建Delegates列表来运行主线程上的函数,然后在运行该列表的主线程上执行它们。

最简单的解决方案是简单地存储经过的总时间的浮点值,每帧增加Time.deltaTime,浮点值将代表传递的秒数,您可以很容易地根据该值调用函数