NokiMo
Megan Fox
Megan Fox

patreon


How to dodge in a dense, physical world

First, let's define the problem. Typical 3rd person action games have a lot of spacing between enemies, even in hoardes. There's a lot of reasons for this. It gives them room for animations, makes them visually discernable, and makes it possible to manuever between them. For references, here's hours of DmC (which is a really good DMC game by the way, despite the reviews at the time):

https://www.youtube.com/watch?v=LfeFPHgNRS4

Now, if you look, dodge movements tend to arc around enemies. It finds the closest reasonable path, and takes that. This works because there's gaps, and given the physical simulation in question, you can actually do that.

Now what happens if enemies are denser, and there aren't gaps? What happens if enemies are bigger? What happens if you need to warp through a solid ring of enemies around you? What happens if, horror of horrors, you're making a first-person brawler, which does drastic things to optimal enemy spacing?

Basically, you're shit out of luck with that approach. If you try to find an open path to a point, good luck, because it probably doesn't exist. Sufficiently large gaps in the middle probably don't exist either. If you go for the "just nudge them away" approach, well you probably can't do that safely, because when you've got two rows of dudes you're nudging into eachother, that isn't a nudge, that just became a settling problem. Insanity to solve. It'd be nice if physics would do that for you, but you're probably using a PhysX-based engine, and... you know as well as I do how poorly it depentrates. You can try blasts, and turn your dodge into a charge that blasts anything out of the way, but now that dodge is a pretty dang OP move that you can't just use as a dodge anymore.

So, what to do? Well, here's my solution: http://pastebin.com/5kDRruUm

This is Unity code, and the comments should make it pretty self-explanatory. What you've got here is a teleporter that is aware of environment it SHOULDN'T warp through, and does some increasingly crazy things to avoid going through it. In Unity land, if you setpos somewhere and are in contact with ANY collider, poof, that's it, you go through it. So hence, a lot of safety checks there.

That in and of itself covers most of the edge cases, but the trick to "how not to teleport inside enemies" is separate. There, the issue is that CharacterController vs CharacterController has no depentration logic. They can't push eachother either, for a lot of reasons - it's just like walking into a brick wall. What to do? Well, it's actually pretty easy! Mount a Kinematic RigidBody childed off your NPCs, with a pill collider, set to IDENTICAL OR SMALLER SIZE AS YOUR CONTROLLER. Put it in a layer that collides with player only. Tada! So, why does this work?

This, basically: https://docs.unity3d.com/ScriptReference/CharacterController-enableOverlapRecovery.html (I experimented for hours to figure out that Unity COULD do this, for some reason, then @AnthonyYakovlev confirmed that what I was seeing was in fact designed behavior, and pointed me at that doc)

What you've got now is a collider that the player only hits in teleport situations, and it immediately pushes them out. In the event of a cluster of colliders? It favors pushing up, meaning at worst, you're standing on top of the cluster of enemies. Which, rather than feeling buggy, feels empowering. Jump and slam down, and punish those fools.

Note, I'm very serious about making that be player-only on collision. While you can do IgnoreCollision and mount a RigidBody that depentrates anything, player or no, and think "gosh now enemies can teleport too!", the depenetration logic of the two CharacterControllers will then spiral out of control. Basically, they'll push eachother up. Then up. Then up. It's hilarious, but very buggy, and you can end up in the stratosphere before they break apart.

I'm also serious about the RigidBody being no larger than your CharacterController. If it's bigger than the CharacterController, and you walk into IT (stationary), you're fine. You stop. But if it walks into YOU, you depentrate, usually by popping on top of it. Bad news. Kind of funny too. I'm curious to see if, for that reason, you actually need it slightly smaller than the CharacterController, so it doesn't ever collide instead, but no issues yet.

Now, what you've got here is really only half of it. This pops you, instantly, to a reasonable dodge-to position. Unless you're a sci-fi game with a literal teleporter, you PROBABLY also want to add a camera lerp from where you were, to where you are now? Particles? Lag the character mesh and move it across? Maybe arc it up and over to avoid moving it through stuff? Ghost it so that moving through doesn't matter (remember Fable 1's dash-through-enemy move? worked great there)? Lots of options there. But that's all fun stuff, the harder bit was "where the heck CAN I move", and that's done, so, yay!

So, there you go. Have fun!


Related Creators