简体   繁体   English

在while循环列表中,协程有时无法正常工作-C#Unity3D Rhythm Game

[英]In while loops list compare of coroutine not work sometimes - C# Unity3D Rhythm Game

I'm going to make a rhythm game. 我要做一个节奏游戏。

music playing time is variable which change by music playing in millisecond 音乐播放时间是可变的,它随毫秒的播放而变化

List is a float list which have the time(float second) I filled , let me to access it and use for compare with music playing time to instance object . List是一个浮动列表,具有我填充的时间(浮动秒),让我可以访问它,并用于与实例对象的音乐播放时间进行比较。

when list time = music time then instant object. 当列表时间=音乐时间,然后是即时对象。

but sometimes will missing(not found value in list but value is really exist in list). 但有时会丢失(列表中未找到值,但列表中确实存在值)。

Here is my assumption. 这是我的假设。

I think List.indexOf performance are not good and thread have some delay. 我认为List.indexOf性能不好,线程有一些延迟。

Music playing time change every millisecond , a little delay from unity or others will cause missing(doesn't entering if statement) 音乐播放时间每毫秒变化一次,从团结到其他的一点延迟会导致丢失(如果声明则不会进入)

I don't know if it's correct. 我不知道这是正确的。

Could any one help me. 谁能帮我。

Here is my code. 这是我的代码。

IEnumerator Execute(MethodDelegate Start,MethodDelegate Stop)
    {
        while (true) {
            int res = result.IndexOf ((float)System.Math.Round (GameObject.Find ("Music").GetComponent<AudioSource> ().time, DigitalAdjust)-TimeAdjust);
            if (res!=-1) {
                if (res == result.Count-2) {
                    Stop.Invoke ();
                    print ("CoroutineStop");
                    StopCoroutine (_Execute);
                }
                //execute
                num=Positoin[res];
                print (res);
                Start.Invoke();
            }
            yield return null;
        }
    }

Thanks. 谢谢。

Chances are that you are correct. 您可能是正确的。 You might miss some if statement because you don't match the millisecond exactly. 您可能会错过一些if语句,因为您不完全匹配毫秒。 Here are some things that could help: 以下是一些有帮助的内容:

It you game reaches 60 FPS (the usual rate for a smooth rendering), each frame will take around 16 milliseconds. 如果您的游戏达到60 FPS(平滑渲染的通常速率),则每个帧大约需要16毫秒。 If you have events that must trigger at exact milliseconds you will miss some because your Execute function calls are separated by around 16ms (a coroutine is called once per frame). 如果您的事件必须在精确的毫秒内触发,则您会错过一些事件,因为Execute函数调用之间的间隔约为16毫秒(每帧调用一次协程)。

A solution to this is remember the last time the Execute function was called and check everything in between: 一个解决方案是记住上一次调用Execute函数并检查之间的所有内容:

private float _lastTime;

IEnumerator Execute(MethodDelegate Start,MethodDelegate Stop)
{
    while (true) {            
        // here your code must check all the event between _lastTime and Time.time
        var lastTimeMilliseconds = (int)(_lastTime*1000);
        var currentTimeMilliseconds = (int)(Time.time*1000);
        for(int time = lastTimeMilliseconds+1; time <= currentTimeMillisedons; time++)
        {
            // let's say last frame was at time 1000ms
            // This frame occurs at time 1016ms
            // we have to check your list for events that have occured since last frame (at time 1001, 1002, 1003, ...) 
            // so we have a for loop starting at 1001 until 1016 and check the list
            int res = result.IndexOf ((float)System.Math.Round (time, DigitalAdjust)-TimeAdjust);
            if (res!=-1) 
            {
                if (res == result.Count-2) 
                {
                    Stop.Invoke ();
                    print ("CoroutineStop");
                    StopCoroutine (_Execute);
                }
                //execute
                num=Positoin[res];
                print (res);
                Start.Invoke();
            }
        }            

       // At the end, remember the time:
       _lastTime = Time.time;

        yield return null;
    }
}

Check the Time class, you also have access to Time.deltaTime to know the time elapsed between two frames, if that helps. 检查Time类,您还可以访问Time.deltaTime以了解两个帧之间经过的时间,如果有帮助的话。

EDIT : As you requested in comment, I added some bit of code from your example to explain better this idea. 编辑 :根据您的评论要求,我在您的示例中添加了一些代码以更好地解释这一想法。 Note that I don't know what your variables do so you will have to adapt. 请注意,我不知道您的变量会做什么,因此您将不得不适应。 For instance, Time.time gives that time since app start. 例如,Time.time给出自应用程序启动以来的时间。 You will likely need to adapt this use the time since you started the audio 自开始播放音频以来,您可能需要调整使用时间

Another important thing: 另一个重要的事情:

  • GameObject.Find must look in all the objects. GameObject.Find必须查看所有对象。 It is really slow and shouldn't be used every frame 这真的很慢,不应该每帧都使用

  • GetComponent looks for all your scripts and is slow as well. GetComponent查找您所有的脚本,而且速度也很慢。 It shouldn't be used every frame. 不应在每一帧使用它。

Instead, do this: 相反,请执行以下操作:

private AudioSource _audioSource;

private void Start()
{
     _audioSource = GameObject.Find ("Music").GetComponent<AudioSource> ();
}

This will retrieve the source only once. 这将仅检索一次源。 Then in your code you simply call 然后在代码中,您只需调用

_audioSource.time;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM