If you’re a regular reader then you might’ve noticed that I’ve been struggling to fix an annoying bug in Bubblision for a couple of sprints.
Initially the bug manifested itself as a graphical glitch where the two particle systems that are used when the player bubble hits an NPC bubble were played at the same time. Collisions would occasionally produce particles of two different colours. Later on I realised that occasionally I’d also get collisions that produced far more particles than should be emitted (even though these were the same colour).
When I added score text to the collisions I started to get some corrupted text at the same time as the particle problem. The trouble was that the problem happened only very rarely. Once it had started happening though, it would persist for the rest of the current game.
Eventually, by pausing the game in the editor and inspecting each game object when we had the problem, I found that the issue was a duplicated player bubble. The two player bubbles overlapped precisely. The text corruption was actually two score messages being printed on top of each other. The particle problem arose from collision detection running on both player bubbles colliding with the same NPC bubble. Since the two player bubbles were often different colours then one might match the NPC bubble and the other didn’t. This led to the two different particle systems playing at the same time or more particles of one colour being emitted than you’d expect.
In the game, when the player bubble collides with an NPC (Non-Player Character) bubble (or the spikes) I destroy the player bubble and instantiate a new one. When creating a new player bubble the Start() function sets the position and colour of the player bubble. The method for creating the player bubble is attached to the MainCamera object. When the player bubble and NPC bubbles collide the collision code on the NPC bubble destroys the player bubble and calls the creation method on the MainCamera.
The problem seems to be that if the player bubble happens to collide with two NPC bubbles at the same time then the create method is called by each NPC bubble. This results in two player bubbles.
This turned out to be quite frustrating to fix. I tried a number of things that didn’t work:
- Only calling the create method if no player bubble could be found.
- Testing for a property on the player bubble showing it had been created and was in the cup ready to launch.
- Explicitly naming the player bubble so that only one instance could exist at any one time. Unity just created a clone…
- Testing for more than one player bubble and deleting one.
- Using FixedUpdate()
As far as I can tell, within a frame (single Update) of the game, if the same piece of code is triggered it’s as if he two bits of code are called at precisely the same time. This means that tests to see if the code has already run will fail and you can get multiple executions of the same code.
Solution
In the end I rewrote the code so that rather that destroy and recreate the player bubble it’s just reset. From a positioning perspective this is straightforward but it makes the randomisation of the player bubble colour harder.
Originally I set the colour by adding the four different colour materials to the materials array on the player bubble prefab. The colour taken by the object is the material in the highest position in the array. I could then just change the colour when the player bubble was created by re-ordering the materials in the array. Since I knew the starting index of the selected material, and it was always reset to the same order when the bubble was created afresh, I could record this before re-ordering the array and use the index to see if the player bubble colour and NPC bubble colours match during collisions.
When I decided to rewrite the code this caused a problem with the colours as the materials array was already shuffled and I couldn’t use the starting index position to test for colour matches. In the end I decided to stop using the materials array and link the materials to the player bubble game object instead. This allows me to pick a colour for the bubble (at random), record what it will be and then set the material to match:
gameObject.renderer.material = blueMaterial;