Unity3d 动画不';当coroutine正在运行时,请不要玩

Unity3d 动画不';当coroutine正在运行时,请不要玩,unity3d,animation,loading,coroutine,Unity3d,Animation,Loading,Coroutine,当我的场景开始时,我启动一个协同程序,生成一个向用户显示的谜题。有时,这一代可能需要几秒钟,但通常相当快。因为用户也可以从场景中刷新拼图,所以我不想来回跳转到单独的加载场景,而只是在协同程序运行时显示一个简单的动画。我在同一个精灵上测试了两个动画:精灵的动画师和更新时的简单旋转。然而,正如标题所说,当协同程序运行时,这两个程序都没有运行。我可以看到该动画是有效的,因为在协同程序完成后,两个动画都开始了(请参见下面注释的SetActive(false))。我怎样才能让这个动画工作 结构如下: -游

当我的场景开始时,我启动一个协同程序,生成一个向用户显示的谜题。有时,这一代可能需要几秒钟,但通常相当快。因为用户也可以从场景中刷新拼图,所以我不想来回跳转到单独的加载场景,而只是在协同程序运行时显示一个简单的动画。我在同一个精灵上测试了两个动画:精灵的动画师和更新时的简单旋转。然而,正如标题所说,当协同程序运行时,这两个程序都没有运行。我可以看到该动画是有效的,因为在协同程序完成后,两个动画都开始了(请参见下面注释的SetActive(false))。我怎样才能让这个动画工作

结构如下:

-游戏场景

--帆布

---拼图控制游戏对象(带有拼图控制脚本)

----动画游戏对象(带有精灵渲染器和动画师组件)

---加载屏幕游戏对象(带有加载动画脚本)

公共类控制:单一行为
{
私人建筑商;
void Start()
{
builder=this.gameObject.AddComponent();
LoadingScreen.SetActive(真);
start例程(builder.Refresh());
}
公共空间重建混乱()
{
LoadingScreen.SetActive(真);
start例程(builder.Refresh());
}
public void BuildComplete()
{
//这将由我们的生成器调用--当前已关闭
//LoadingScreen.SetActive(设置激活)(错误);
}
}
公共类加载动画:MonoBehavior
{
公共游戏对象动画;
专用浮球旋转速度=200f;
//每帧调用一次更新
无效更新()
{
animation.GetComponent().Rotate(新矢量3(0f,0f,rotateSpeed*Time.deltaTime));
}
}

这是一个常见的误解,协同程序实际上并不是在一个单独的线程上运行的,所以如果你有大量的计算要做,你需要将它移动到一个任务中,并在线程池上运行,否则Unity在执行这项工作时仍然会冻结。协同路由仅在它们屈服时返回对cpu的控制,每个帧unity将重新进入它停止的协同路由,这给了代码同时运行的错觉,而实际上它只是使用yield关键字被切成块

将内容移动到线程中的一个限制是,作为一般规则,您实际上无法触摸Unity引擎的任何部分,因此您需要收集所需的数据,然后将其发送到线程进行计算,然后在完成后将更改应用于场景

下面是一个关于如何发送长时间运行的计算的快速示例,以便一个单独的线程(或者至少将其并行化,因为C#会将其发送到一个线程池来处理分发):

使用System.Threading.Tasks;
void Start()
{   
//发送它
var taskHandle=Task.Run(DoLongBuildCalculation).ContinueWith(OnBuildComplete);
}
MapBuildData DoLongBuildCalculation()
{
//做长时间的计算。
返回结果;
}
void OnBuildComplete(任务buildTask)
{
if(buildTask.IsFaulted | | buildTask.IsCanceled)
{
//处理它。
}
//在buildTask.Result中执行某些操作
} 

编辑:为了澄清,您不应该在DoLongBuildCalculation()中与Unity对象交互。

谢谢您的解释。不幸的是,我的构建器正在创建游戏对象,因此这对我的情况不起作用。也许动画可以以某种方式放到一个单独的线程中?不幸的是,这是不可能的。我的建议是只保存一个列表,其中列出了在完成后生成对象的位置,并将其发送回主线程。如果你的地图构建过程依赖于对引擎中的重叠之类的事情做出响应,那么我恐怕你就不走运了。你当然可以将构建步骤分解成更小、更易于管理的块,并将控制权交还给引擎。因此,如果你迭代1000个对象,每50个左右你就会产生一个,这给了CPU时间来更新动画。谢谢!这就是我需要的提示。我有一个特别沉重的片段导致了延迟,在内部循环中添加一个收益回报实际上导致了整个过程在我的动画愉快地运行时受到了重大的性能冲击。我通过将收益率放在外部循环中,做出了妥协。现在我得到了一个不稳定的动画和体面的加载时间。不完美,但我可以从这里开始。现在我对结果很满意,感谢你们,我对合作项目有了更好的理解。很高兴能提供帮助!这肯定是其中一件事,一旦你开始思考,就会打开一个全新的理解:)
public class PuzzleControl : MonoBehaviour
{
    private PuzzleBuilder builder;
    void Start()
    {
        builder = this.gameObject.AddComponent<PuzzleBuilder>();
        LoadingScreen.SetActive(true);
        StartCoroutine(builder.Refresh());
    }

    public void RebuildPuzzle()
    {
        LoadingScreen.SetActive(true);
        StartCoroutine(builder.Refresh());
    }

    public void BuildComplete()
    {
        // This will be called by our builder -- currently turned off
        //LoadingScreen.SetActive(false);
    }
}


public class LoadingAnimation : MonoBehaviour
{
    public GameObject animation;
    private float rotateSpeed = 200f;

    // Update is called once per frame
    void Update()
    {
        animation.GetComponent<Transform>().Rotate(new Vector3(0f,0f, rotateSpeed * Time.deltaTime));
    }
}
using System.Threading.Tasks;

void Start()
{   
    // send it 
    var taskHandle = Task<MapBuildData>.Run(DoLongBuildCalculation).ContinueWith(OnBuildComplete);
}

MapBuildData DoLongBuildCalculation()
{
    // do long calculation.
    return result;
}

void OnBuildComplete(Task<MapBuildData> buildTask)
{
    if(buildTask.IsFaulted || buildTask.IsCanceled)
    {
        // handle it.
    }

    // do something in with buildTask.Result
}