Writing a fun steering algorithm

The cornerstone of Death Boulder Bones’s uniqueness is how you control the character, or rather how you don’t control him. Drawing walls nearby to encourage him to turn this way is a mechanic that hasn’t, as far as I know, been used in any game to date. But, Dr. Indie Bones is a stubborn guy and is also pretty heedless of danger, so he makes little to no decisions on his own. I guess that’s what happens when you’ve had a benevolent spirit preventing you from getting harmed during your entire life.

Most players aren’t going to read that little bit of story, however, so instead they’ll just have this guy in their hands who seems to make all the worse choices. Why does he blindly run into lava, traps, and certain death? In our current implementation of the game, the player often wonders this. For the most part, that’s okay. Assuming our tutorials are good enough, players are generally willing to accept certain tropes and idiosyncrasies as part of the gameplay. Okay, this guy is going to just go blindly ahead, and I’m the only thing stopping him from death. That’s cool. How would the game be any fun if Bones was able to navigate the level entirely on his own?

But. This really breaks down when the character tries to get Bones to do one thing, and they expect him to do that thing, but then he goes and does something else entirely. Defiance of a player’s expectations is 100% a bad thing unless it’s done purposefully to accomplish some other thing. In our case, it’s pretty random, and no bueno. One thing we’ve constantly been told by people who play the game is that there are instances when Bones will, for no clear reason at all, go the “wrong” way.

Well, what is the wrong way? Good question. That might be sensitive to context, or it might be an overall feeling. As a result, I’ve spent a lot of time and talked with a lot of smart people to try to get a feeling for what they expect. Because then even if Bones does some totally wonky stuff, as long as the player expects it then that’s totally okay. Before I go into the approach I decided on, let me lay out the past.

The History of the Steering, and of Death Boulder Bones

Believe it or not, this 3 raycast approach, albeit with a little tweaking, is the exact one currently in Death Boulder Bones and is what we used when competing on The Next Game Boss. Why? Because, or the most part, it works. But, it works only when the walls are drawn close to or out of Bones’s vision (in other words, beyond the reach of the raycasts). If you draw a wall very close to him, it’s likely all 3 raycasts will hit, and then the way he turns can be determined entirely by minute angles in the wall or in Bones himself. That means that, every once in a while, he’ll do something you don’t expect and it will drive you crazy.

A Better Approach
Because Bones is the only one at any time who is pathfinding, I can make him do it in a far more complex manner and not care about performance. As a result, I’m not worrying so much about how many rays I’m casting or how complex the logic is. He needs to be predictable, and he needs to just work. So for this next implementation, I’m going for a more usual steering approach.

Usually, steering is combined with something like A* to get several destination nodes and then steer between them. The thing about Bones is that he has no destination. In parts of some levels he has a “preferred” rotation that he sort of rounds to, but otherwise he has absolutely no knowledge about where he is going or why. That means that finding the edges of obstacles he raycasts against and choosing the shortest way around just doesn’t make any sense to do. Because maybe he doesn’t want to go around the wall? What if we want to make him turn to the left or right instead?

This means I can’t use the usual way of steering at all. Instead, it needs to be something that causes course adjustment but doesn’t rely on having a goal of any kind. In the previous iteration, Bones would turn away from walls that were on his left or right but not in front of him, due to those 45° rays. This allowed for course adjustment without directly inhibiting his movement, which was a definite plus.

I’ve decide to experiment with losing that, and instead only making him turn if something is directly in his way. This means a few raycasts pointing straight forward and at the full width of Bones (so he can’t squeeze through spaces smaller than his waist). If those casts see nothing, he continues forwards. If they do see something, then he sends casts in a full 360° arc around him. Whichever direction is the most clear – left or right – is the way he turns.

At the very least, this approach should be predictable. No matter what, Bones will go towards the nearest empty path. It also allows me to play more interesting animations, like an “aaahh I’m surrounded!” animation when he’s completely enclosed in walls, and a “ouch I ran into a wall” animation when one suddenly sprouts in front of him. It will also allow him to run closely parallel to walls, which he couldn’t do before. This could cause weird seesawing when walking in narrow passageways (move to the left to get away from the right, now move to the right to get away from the left, over and over again), and other problematic stuff.

My main worry is that he loses some of the “flee” steering response that he previously had with 45° rays. Will it be annoying to need to completely obstruct Bones’s path to make him move, or will it feel more natural? The only answer is to try it out. If it is a problem, then I’ll just have to try a combination of the old approach and the new one.

What we went with

Eventually, we settled on combination approach. Bones casts out a bunch of ray pairs in a 360° arc around him, currently there are 8 separate pairs (so at 45° angles). He then uses a combination of whether the rays hit obstacles, how far they hit, and which way he is currently facing versus what way the ray is going, to create a single weighted cost value. Eventually, he decides which value has the lowest cost, and he turns towards that angle!

Walls have a huge cost – if a direction hits a wall, he’s not going to want to head that way. Angle changes are also costly, but not as much. In general he wants to keep going straight, but if there is a wall in his way he’ll definitely turn to try an alternate route. When he’s completely surrounded by walls, he’ll basically just go towards whichever area has a wall that’s farther away.

This didn’t quite work, so I actually added one last step. Once he has chosen a direction, if he’s facing that direction or almost facing it (in other words, if he’s freely running with nothing in front of him), then he’ll cast out a couple rays to his sides. If either ray hits a wall, he’ll eke a little bit away. This encourages him not to hug walls, but instead to keep a reasonably distance from them.

Leave a Reply

Your email address will not be published. Required fields are marked *