Thank you for this long explanation of what happened and how the game works with a step by step story, instead of just saying the game doesn´t work because reasons. Great detective skills!
Progress Report (23/05)
Progress Report (23/05)
This week I was supposed to finish version 0.2.0 of the game, however an unexpected bug popped-up while I was working on the second song mapping.
It took me some time to fix this bug. Time that I couldn't use to prepare and properly test the second song map.
I'm aiming to release version 0.2.0 next week! (fingers crossed)
If you'd like to read more about the bug and the process I followed to diagnose and fix it, keep reading. Warning: lots of text ahead.
About the bug
Basically, the bug caused the game to stay on the play screen even after the song had ended.
The bug would not show up in relatively slow songs, but since the song I'm working on has a faster pacing, I noticed it after a couple of test runs. It took me some hours to isolate and reproduce the issue and then think of a way to fix it.
Analyzing the problem and potential causes
At first, what seemed to be happening was that the game couldn't properly detect when a song had ended, so it would stay on the play screen forever, not transitioning to the result screen.
After taking a closer look, I noticed that after the song had ended, some notes were still hanging around. This was not supposed to happen, since all notes are removed from the game either when the player presses the corresponding button or when they leave the play zone (they go out of the screen).
At this moment, I considered a number of potential points of failure:
- Could it be the pooling system I had implemented was flawed? Maybe the pool sizes were too small and somehow there was a problem when recycling the notes.
- Could it be a timing issue? Maybe I had a note show up in a specific moment that was causing it to not be removed.
- Maybe the player input was not detected properly?
- Did I mess up something while working on the new features?
I quickly discarded the player input as a cause of the bug by letting the game run without me touching any buttons... the same exact notes were still active at the end of the song. Every time.
The chance of having introduced the bug when working on the new features (leaderboard and fanart slideshow) was also quickly discarded as I had not touched any code related to the play screen, since these new features were added to the main menu code.
So, at this point it was either the pool system or something related to timing.
I did some tests by changing the pool sizes: double them, halve them, make them large enough to not need to recycle the notes at all... and got the same result every time. If the bug was related to the pool, I should have seen a different note be left behind at the end in these tests, but nope, it was the exact same two notes.
I took a closer look at these two notes. What did they have in common?
Oh, they are both hold notes. Specifically, the notes signaling the start of a hold.
But... the song had a lot more hold notes than these two. Why would these specific two cause the bug?
After spending a while thinking about this, I finally came to the conclusion that it HAD to be a timing issue. The bug only happened to these specific two notes because something was happening at a certain time, under certain specific conditions.
My next step was to decompose step-by-step the sequence of events that happen in the game when a note reaches the 'target zone' where the player has to hit the correct key to score points.
The sequence goes like this:
- When the note enters the target zone, it sets itself as the active note.
- When the player presses the key, the game calculates the distance of the active note to the target position and determines if it was a hit or a miss.
- If the note was hit, it is removed from play.
- If the note was not hit, it is removed from play when it leaves the target zone.
There is an exception to steps 3 and 4: Hold start notes. These notes will stay in the play area until their corresponding hold end note is removed.
Aha! That looks like something that could go wrong! Something probably was preventing the hold end note from removing its corresponding hold start note!
Finding the root cause and fix
There was a previous bug I fixed, where if the notes were placed very close to each other, in a quick sequence, it could cause two notes to be inside the target zone at the same time, therefore making the game lose track of one of them. This was fixed by making the game remember all the notes that went into the zone, instead of just the last one.
Hold notes were not included in this fix since it was impossible to have two hold start notes inside the target zone at the same time. Holds have to be at least 1 beat long, and there must be a gap between the end of one hold and the start of the next, so the minimum distance between hold start notes is never less than 1.25 beats. The target zone is 1 beat long, so this is totally fine.
It took me a moment to realise what was the issue. I had to watch the game in slow motion as the notes moved down the screen to notice a particular situation where things didn't work as expected.
If there's a sequence of two consecutive holds, as in, hold-start -> hold-end, hold-start -> hold-end, it is possible that in the same frame the end of the first hold exits the zone, the start of the next hold enters the zone.
Then, it is a matter of how the engine processes the events:
If the exit event is processed first, everything works as expected. The first hold-start note is removed together with the exiting hold-end note, and then the second hold-start note is set as the active note. (See 3a below)
However, if the processing order is reversed, the bug happens. The second hold-start note is set as active and then the first hold-end note mistakenly removes it. Then, the first hold-start note is never removed. (See 3b below)
The fix was relatively simple: keep track of all the active hold start notes in a FIFO queue, so that when a hold end note is removed, the oldest active hold start note is removed with it.
Hmm... I guess I need to consider more carefully the edge cases when designing the game logic, hahaha.
If you like what I do and maybe found this long article interesting, please consider sending a donation. I really appreciate all the support: https://ko-fi.com/softdevwu
Thank you for reading and see you next week!
(hopefully there will be no more bugs and I can finally release v0.2.0...)