Programmer Mail Bag: Lava Glitch

Andy here. I’m the game design/programming end of Golden Ruby. We recently got a bug report from Erick Beard about an issue in Worm Run where the player could be killed by running really fast into a wall with lava on the other side. We fixed it in the most recent update and he was wondering exactly what we did to rectify the issue. So welcome to the first and possibly only issue of GOLDEN RUBY PROGRAMMER MAIL BAG.

The Bug:

(image captured by Eric Beard)

Eric got going good and fast in the temple area, hit that wall up there and was burned to a crisp. Not good.

Why It Happened

The issue lies with how Worm Run deals with collisions. I wrote the physics system myself, but it’s not at all unusual in how it handles things. So let’s brace ourselves for some Programmer Art and dive in.

In this image, the stick figure is Zeke, the plain rectangle is a wall, and the rectangle with the lines is lava. There is a reason we brought in Nick to do the art for this game.

Every frame, the player moves according to their velocity (1). After they move, the game checks to see if they are somewhere they shouldn’t be (such as inside a wall). In (2) up there, you can see that the player is in the wall. When this happens, the game pushes them back out until they are no longer touching the wall (3). This all happens before the player sees anything, so to them it will appear that Zeke hit the wall and stayed there, as physics would dictate.

This check is done by using several nodes that surround the player’s body (which can be seen in this screencap of Worm Run with some of my debug tools on). Worm Run uses 6 of these nodes, four to check walls and such, and an extra two to see when the player is adjacent to a wall. In the game, players can slide and hang onto walls, so it is important to know if they are “touching.” This can be tricky, because the way the game handles collisions is to push the player away from the wall until the four main nodes are no longer in the wall. So on a technical level, Zeke is never touching a wall, just incredibly close. That’s why the extra two nodes are needed. They’re just a bit further away, so when the four main nodes are pushed away from a wall, the extra node on that side will still be touching, and the game knows that the player is up against the wall.

So that’s how the collisions work, but why does the bug happen?

Well previously, checking for deadly things like lava and spikes occurred several times during this process. Usually it was fine because it is very difficult for the player to travel more than 1 block’s distance in a single frame, so if they hit lava they died. No problem (at least for the player; Zeke might have a problem with it). But if something happened like in panel 2 in the illustration, the game would register that one of their nodes was in lava, killing them before moving them back against the wall. Not good.

Fixing It

An obvious solution is to just not check those nodes for contact with deadly things until after the player has been moved, but this leads to its own issues. Remember that after the player has been moved back, they are not technically touching anything, even the floor. As far as the game is concerned, they are hovering a little less than a pixel above the ground.

When the check was made after moving the player, it always found that the player was NOT touching lava, even if they appeared to be standing right on top of it. Technically, the node was not in the lava block; it had just been moved out of it.

Having the player able to stand on lava wasn’t really working for us. While there are many potential solutions, I wound up modifying the function that checks to see if the player’s nodes are touching lava or spikes. I already had two nodes that still could be in lava on the left and right, so the current version uses those two to check if the player is touching lava after the game has moved them away from any solid blocks they may be touching. For the top and bottom, I could have included additional nodes, but that seemed like overkill when they were really only needed for a single check. Instead, when the game checks for lava, it adds or subtracts one pixel from their location so that the new position will be in lava that is directly above or below the player. And then it will kill them.

So that’s it! The newest version of the game includes these changes and a few others that folks have pointed out to us since we released. Thanks to people like Eric Bears and others who have written to us with issues and questions they have!

Maybe we’ll see you again with another edition of GOLDEN RUBY PROGRAMMER MAIL BAG.