0

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 .

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.

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.

  • If it's a coroutine, the `Thread.Sleep` doesn't belong there - `yield return` will return once per frame. If you really want to wait, use `yield return new WaitForSeconds(time);` – Manfred Radlwimmer Mar 13 '18 at 08:10
  • 1
    Why did you remove the `Thread.Sleep` in your Edit? That's really important. Don't do that. To wait, simply use `yield return new WaitForSeconds(2);`. Check duplicate for other ways to wait in Unity – Programmer Mar 13 '18 at 08:12
  • 1
    Here is the official documentation for coroutines: https://docs.unity3d.com/Manual/Coroutines.html – Manfred Radlwimmer Mar 13 '18 at 08:13
  • because I remove from my code before I forgot to remove that before post . WaitForSeconds can't delay millisecond . – William Pesido Chelin Mar 13 '18 at 08:15
  • It can. Just pass `0.xx` to it. See other ways to also delay from the duplicate which involves `Time.deltaTime` and coroutine – Programmer Mar 13 '18 at 08:17
  • Sorry but my problem is indexof will not return valid value sometimes in while , The point is not at coroutine delay WaitForSeconds... – William Pesido Chelin Mar 13 '18 at 08:20
  • Please edit the question to clearly explain your issue so that I can reopen it. Hopefully, you have removed the Thread.Sleep code. Explain what is currently happening and what you expect to happen from that piece of code – Programmer Mar 13 '18 at 08:24
  • I re edit it , I use sleep before to let list.indexof have buffer time to run , but it dosen't solve my problem indexof still can't keep up with music playing time. – William Pesido Chelin Mar 13 '18 at 08:30

1 Answers1

0

Chances are that you are correct. You might miss some if statement because you don't match the millisecond exactly. 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. 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).

A solution to this is remember the last time the Execute function was called and check everything in between:

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.

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. 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. It is really slow and shouldn't be used every frame

  • GetComponent looks for all your scripts and is slow as well. 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;
Basile Perrenoud
  • 4,039
  • 3
  • 29
  • 52
  • Thank you very much. But there's apart of code I'm don't really understand . `// here your code must check all the event between _lastTime and Time.time` <-this line , Could you please explain more detail for me or some example please. Thanks – William Pesido Chelin Mar 13 '18 at 14:50
  • Well it is your code. It is impossible for me to code a working example because I don't know your code. For example I don't know what is in the `result` variable. I'll edit my answer to add what I think you should do, but you will likely have to modify it a bit to work – Basile Perrenoud Mar 13 '18 at 15:28
  • Thanks , I see . `result` is variable `list` that I filled the time data for compare with music playing time variable. I just doesn't know how to “check the time between lastTime and Time.time” with my code. You've been such a great help. – William Pesido Chelin Mar 13 '18 at 15:48