Good Idea Games‎ > ‎

Time Throttle: POC 3 Bug Fix

posted Mar 26, 2018, 11:17 PM by Good Idea Games   [ updated Aug 1, 2018, 10:45 AM ]
Here's a lesson for you: 
Don't modify a list while iterating over it.

I had an exciting bug in Time Throttle that would only show up when I tried to play the game with friends.
Sometimes a player would end up with a permanent boost to their speed and rate of fire. And some players would *occasionally* end up with permanently reduced speed and rate of fire. It was terrible, and it ruined every game demo I tried to run over the holidays.

These things are controlled by their player object's 'time_mod' value, so *clearly* there was something going on that was not restoring this value properly.

It turns out, while destroying a Time sphere, IF it's because the lifespan ran out, I was doing it wrong.

///When Lifespan runs Out, Destroy Time Sphere, Undo effects

if life_span <= 0   {
    //iterate through affected objects, and undo the time mod
    show_debug_message("Time Sphere "+string(id)+" has died of natural causes")
    //only check if the list has affected objects...
    if(ds_exists(affected_object_list, ds_type_list)){
        var i;
        for (i = 0; i< ds_list_size(affected_object_list); i++) { //ALT: remove i++.
            var object_instance_id = ds_list_find_value(affected_object_list,i);
            //Confirm that the affected object still exists...
            if (instance_exists(object_instance_id))    {
                 with (object_instance_id)  {                                        
                    //remove object_id from list of affected objects                    
                    ds_list_delete(other.affected_object_list,i)   
                    //restore object physics motion
                    phy_speed_x *= (1/other.time_factor)
                    phy_speed_y *= (1/other.time_factor)
                    phy_angular_velocity *= (1/other.time_factor)
                    //image_speed *= (1/other.time_factor)   /*note: this causes player sprites to flash*/
                    
                    //restore object's time_mod
                    time_mod *= (1/other.time_factor)                    
                    }
                }
            }
            //NOTE: affected objects do NOT need to be removed from the list, since the entire list is destroyed.               
        }
    //Destroy List and Object
    //Note: affected object list destroyed in 'destroy' step
    instance_destroy()   
    }

In the case above, the first object affected by the time (object [0]) would be handled just fine. This is why my solitary troubleshooting didn't detect the bug. But as soon as you add more affected objects (players in particular), shit gets real.

Let's say object[1] is another player, now with a hefty speed boost. 
I enter my for loop, with i==0, I delete object[0] from the list, and restore it's physical properties. Then I increment i.

UNFORTUNATELY... object[1] is not the first item in the list. It's object[0].
And I go to town on object[1]. I delete object[1] from the list, and restore it's physical properties.
Iterate over every object effected by a time sphere, and fully half the objects that were in the thing won't get their rightful properties restored.

Whoops!

BUT! Now with this fixed, I can focus again on tuning the game play, because even though Time Throttle has been "complete" for 3 months, it's only been "playable" for 14 minutes.

[EDIT: fixed some typos]
Comments