chimerror

I'm Kitty (and so can you!)

  • she/her

Just a leopard from Seattle who sometimes makes games when she remembers to.


hthrflwrs
@hthrflwrs

//Start is called before the first frame update


johnnemann
@johnnemann

//Update is called once per frame


Webster
@Webster

when i was in college i took an unelective game development class that taught unity to students. the final assignment was to create "duck hunt" from scratch (the irony is not lost on me). i wrote some code that would make the duck change directions every 500ms or so and i wrote the script to kill the duck when it was clicked. i didn't understand OOP very well yet, but one of the requirements was to instantiate an object, so i put some conditional logic on the update method that would instantiate a new Duck() if the current one was dead.

the result of this was that, upon killing the first duck, 60 ducks would infinitely spawn per second, flooding the screen and filling the heap like a cosmic horror emerging to exact it's revenge.


outrider
@outrider

so I had a pet project that was basically a top-down procgen dungeon crawler. I had a fairly well working dungeon generator but then decided for Aesthetic reasons I wanted rooms to be double-walled (ie. two directly adjacent rooms would have two wall tiles between them, rather than a single "shared" one). Like so:

     #.....#
     ###.###
     ###.###
     #.....#

Rather than the roguelike standard of

     #.....#
     ###.###
     #.....#

This of course also meant doubling up the doors - whenever I'd generate a door between rooms, I'd have to make it two tiles wide or tall.

For Reasons, I decided the way to do this was not to have double-height/width objects, but to have two independent Door objects adjacent to each other that would communicate to keep their status in sync.

This was the first of my mistakes.

When a Door spawned, it would query the Map manager object to find a Door immediately adjacent to it, by simply looping over all eight adjacent tiles, checking if there was a Door at that coordinate and assuming the first tile with a Door object on it to be its "other side".

Door objects always spawned in state 0 (open), with additional states being 1 or 2 (closed and locked respectively).

When a Door spawned, it would decide randomly (based on Map configuration weights) whether it should remain open, or switch to locked or closed states. So, when a Door spawned its "other side" in the adjacent door space it had found, it would then have to call its script functions to set its state to locked or closed to match its own state.

When the player interacts with a Door, it would reference its other side Door object and also call its activate function with the same parameters it itself was given, so that if a player opens/closes/locks/unlocks a door from one side it goes and tells its buddy what state to go into as well. The activate function checked the door's current state to make sure that a closed door doesn't try and run code to close itself if something tells it, because that's how you do safe programming. I even muted the audio for a few frames after starting the level to hide the sound of two thirds of the doors on the map slamming shut simultaneously and another third locking on the following frame once the level starts.

With a bit of testing this all seemed to be working fine.

There was, however, one scenario I had not considered.

It took a bunch of tries on the level generator for this scenario to actually occur, thanks to the blessings of random generation, so at some point a few days after implementing Buddy Doors, I started a game only to find myself flooded with INCREDIBLE NOISE and the frame rate on the game absolutely tanking. I reflexively muted my laptop audio. Then I realised that I already had positional audio and audio attenuation implemented, so I could figure out what was making the unholy noise by just plugging in some speakers, turning them on but Vewwy Vewwy Quiet, and slowly shambling around the level at 5fps to locate the source.

Eventually I found it.

   #.......
   ##-#####
#####-#####
...++......
...##......
...##......

A room with two doors on tiles directly adjacent to a corner of the room they were in. One door open, one door closed. Both doors constantly flipping open and closed every single frame. I had created...

The Infinite Door Slam

If one of the doors on the "far" side of the corner spawned in closed state, it would send a signal to the first adjacent door it would find to also close, assuming (correctly) that door to be its buddy.

That door, however, would then go "oh I've changed state", loop through the tiles around itself clockwise... find the door on the other wall around the corner before finding its own buddy, find that that door was in a different state from itself, and tell it to close.

That door would then loop clockwise through the tiles around it, starting Northeast, find the other door on the wall around the corner before its own buddy, and go "hey buddy, I've just changed state!"

At this point, these two doors would just assume they're each others' buddies, and so every time one of them changed state, it would tell the other door to do the same. Except they were stuck in opposing states because they weren't, in fact, buddies, so one of them was always open and the other always closed. And so, they were stuck in an infinite loop of each door telling the other on every single frame to toggle state.


You must log in to comment.

in reply to @Webster's post:

complete, no bugs, thank you for playing lol

ah wait I think I got it, if you managed to kill a second duck, it would then generate two ducks per frame lol, because the logic is per duck, and said duck continues to be dead every frame?

in reply to @outrider's post:

"8 tiles" can only mean every neighbour including diagonals on a square grid. why would it need to check the diagonals? you can't walk through that. it should only be checking the 4 tiles touching it