如何防止我的代码产生每一帧? [英] How can I prevent my code from yielding every frame?

查看:25
本文介绍了如何防止我的代码产生每一帧?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在调用一种方法,该方法调用自身以爬过地形并创建区域.然而,当区域变大时,进程以堆栈溢出结束.通过强制代码让步并花时间它成功完成并爬行我地图中的 3 个区域.然而,我使用的方法是产生每一帧,我不知道如何让它每 100 帧产生一次,导致它完成得非常慢.这是我为可读性所做的伪代码:

I am calling a method that call itself to crawl through terrain and create zones. However when the zones become to large the process ends in a stack overflow. By forcing the code to yield and take its time it finishes to completion successfuly and crawls the 3 zones in my map. However the method I am using is yielding EVERY single frame and I don't know how to make it yield just every 100 frames, causing it to be extremely slow to finish. Here is the pseudo code of what I am doing for readability:


 
public int timer = 0;
 
void Awake(){
 
StartCoroutine(crA);
}
 
public IEnumerator crA(){
//stuff
 
yield return StartCoroutine(crB());
 
//stuff that needs to happen only after crB finishes
}
 
public IEnumerator crB(){
 
timer = 0;
 
yield return StartCoroutine(crC());
 
}
 
public IEnumerator crC(){
//Crawiling code, crawls terrain to create a zone
 
if(x){ yield break;}
 
timer++;
 
//vv I WANTED IT TO YIELD ONLY IN HERE
if (timer ==100){
timer = 0;
yield return null;
}
//^^
 
yield return StartCoroutine(crC());
yield return StartCoroutine(crC());
yield return StartCoroutine(crC());
yield return StartCoroutine(crC());
yield return StartCoroutine(crC());
 
}
 

似乎 yield return startcoroutine 导致了 yield 但我不知道该用什么来代替.任何帮助将不胜感激.

it seems yield return startcoroutine is causing a yield but I don't know what to use instead. Any help would be appreciated.

推荐答案

一般来说,只要你使用 yield 它至少会 yield 一帧像

As said in general as long as you use yield it will at least yield for one frame like

yield return null;

确实如此.

您可以做的是使用 IEnumerator.MoveNext 手动"不屈服.如果您使用 StartCoroutine,这基本上就是 Unity 协程每帧调用一次的内容.

What you could do instead is use the IEnumerator.MoveNext "manually" without yielding it. This is basically what the Unity coroutine is calling once per frame if you used StartCoroutine.

然后只在你想要的时候屈服.鉴于您的伪代码类似于例如

And then only yield when you want to do so. Given your pseudo code something like e.g.

private void Awake()
{
    StartCoroutine(crA);
}

public IEnumerator crA()
{
    //stuff

    yield return crB();

    //stuff that needs to happen only after crB finishes
}

public IEnumerator crB()
{ 
    timer = 0;

    // "Manually" run the routine instead of using Unity Coroutine interface
    var crc = crC();
    while(crc.MoveNext())
    {
        if(timer >= 100)
        {
            yield return null;
            timer = 0;
        }  
    } 
}

public IEnumerator crC()
{
    //Crawiling code, crawls terrain to create a zone

    if(x) yield break;

    timer++;

    yield return crC();
    yield return crC();
    yield return crC();
    yield return crC();
    yield return crC();
}

然后如上所述,您可以基于时间而不是使用帧/调用计数器而不是使用例如StopWatch

And then as said you could do it time based instead of using a frame/call counter rather using e.g. a StopWatch

private const float TARGET_FRAMERATE = 60;

public IEnumerator crB()
{ 
    var targetMilliseconds = 1000f / TARGET_FRAMERATE;
    var sw = new StopWatch();
    sw.Start();

    // "Manually" run the routine instead of using Unity Coroutine interface
    var crc = crC();
    while(crc.MoveNext())
    {
        if(sw.ElapsedMilliseconds >= targetMilliseconds)
        {
            yield return null;
            sw.Restart();
        }  
    } 
}

所以只要最后一次执行超过目标帧率,它就会产生一帧.您将不得不稍微调整一下价值……根据您的用例,30 甚至 24 可能已经足够了.

So whenever the last execution exceeded the target frame-rate it will yield one frame. You'll have to play a bit with the value .. probably something like 30 or even 24 might already be enough depending on your usecase.

它基本上是帧速率和实际实时持续时间之间的权衡.

It basically is a tradeoff between frame-rate and actual realtime duration.

注意:在智能手机上打字,但我希望思路清晰

这篇关于如何防止我的代码产生每一帧?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆