AudioSettings.dspTime
instead of Time.timeSinceLevelLoad
to track the position in a song.SongManager
class to track the position in a song, create notes, and other song management functions. // ( ) float songPosition; // ( ) float songPosInBeats; // float secPerBeat; // ( ) float dsptimesong;
Start()
function: void Start() { // // bpm secPerBeat = 60f / bpm; // dsptimesong = (float) AudioSettings.dspTime; // GetComponent<AudioSource>().Play(); }
bpm
to secPerBeat
. Later secPerBeat
will be used to calculate the position in the song in the beats, which is very important for creating notes.dsptimesong
. We use AudioSettings.dspTime
instead of Time.timeSinceLevelLoad
, because Time.timeSinceLevelLoad
updated only in each frame, and AudioSettings.dspTime
updated more often, as this is an audio system timer. To keep track of the song, you need to use the audio timer. In this way, we can avoid the delay caused by the time difference between frame updates and audio updates.Update()
function calculates the position in a song using AudioSettings.dspTime
: void Update() { // songPosition = (float) (AudioSettings.dspTime - dsptimesong); // songPosInBeats = songPosition / secPerBeat; }
dsptimesong
) from the current AudioSettings.dspTime
. We got the position in seconds, but in the music world the notes are recorded in beats. Therefore, it is better to convert the position in seconds to position in beats. Dividing the songPosition
by secPerBeat
(second / (second / hit)), we get the position in beats.songPosition == 1.75
), then we know that we are in the position 1.75 ( songPosition
) / 0.5 ( secPerBeat
) = 3.5 beats, and it is necessary to create a beat note 3.5. // float bpm; // float[] notes; // , int nextIndex = 0;
bpm
is the number of beats per minute. As we have seen, for convenience they are converted to secPerBeat
.notes
is an array in which all positions of notes in beats are stored. For example, for the notes presented in the figure, the notes array will contain {1f, 2f, 2.5f, 3f, 3.5f, 4.5f}
:nextIndex
is an integer needed to traverse the array. It is initialized to 0, because the next note to be created will be the first note of the song. When creating a note, the counter nextIndex
incremented by one.Update()
function. However, you first need to determine how many strokes will be shown in advance.songPosInBeats = songPosition / secPerBeat;
, the following lines: if (nextIndex < notes.Length && notes[nextIndex] < songPosInBeats + beatsShownInAdvance) { Instantiate( /* */ ); // nextIndex++; }
nextIndex < notes.Length
). If the notes still remain, then we check if the song reached the beat at which the next note should be created ( notes[nextIndex] < songPosInBeats + beatsShownInAdvance
). If reached, create a note and increment nextIndex
to keep track of the next note you want to create.MusicNote
class and leave only the Update()
function, in which we move every note: // void Update() { transform.position = Vector2.Lerp( SpawnPos, RemovePos, (BeatsShownInAdvance - (beatOfThisNote - songPosInBeats)) / BeatsShownInAdvance ); }
notes
arrays, deleting notes is performed by checking the position relative to the deletion line, long-duration notes are implemented by tracking the initial and final stroke, etc.Source: https://habr.com/ru/post/324798/
All Articles