XaiJu
Megan Fox
Megan Fox

patreon


Moving the CharacterMovementComponent procedurally, without root motion

Right, so, let's set the stage: you're doing a sword swing animation, and we want it to feel like a concise movement instead of a button mash you hit while randomly moving around. To pull that off, we need to block player movement input for a sec. Except, oh no! Now the attack animation freezes you in place while it plays. That feels bad, attack animations need to close distance for a whole bunch of reasons. So how do we do that?

Root Motion

Well, one way is root motion! Which, to be fair, does work pretty well in Unreal. It's more flexible than in other engines. MotionWarping in particular, plus root motion, can get you combat that feels a bit like Assassin's Creed Unity (you know the French one?), or any of those in that AC3/AC4 era. Trouble is, that era of combat felt kinda shitty, due to how you and the enemy would sorta schlorp over terrain regardless of how your target moved. So I'm not doing this, but if you do want that style? Stop here. Do that. You'll just have to build a ton of special case animations to fix all the cases where if you did nothing, your guy would magnet themselves to the enemy and invalidate any evasive maneuvers they attempted.

But Don't Ignore Root Motion Even If You Don't Use It

There's also ways of putting root motion animation data into all your animations but then not actually using it to drive motion. You end up having the root motion data there, just available, as a hint to your own code. This is rad! Setting this up is just two settings you toggle in your sequences, look for Root Motion Root Lock and Force Root Lock (you'll have to fiddle a bit with both probably). This isn't really a method for movement as such, but I want to mention it here to drive a particular point home: you can have root motion which doesn't actually drive your motion, but is just present as data accessible to the animation processing that can make your procedural movement system more powerful. Comes up a lot in foot planting for instance. In fact, you HAVE to have the root motion data present to use Unreal's built-in foot planting system (which is very very good), and you might think that means you have to use root motion for movement too. Nope! So just remember this part.

Moving Without Root Motion

So what does that leave? Well, what I do is actually block player input for a while, and pipe my own input data into the CMC. For all it knows, it thinks the player is still pressing buttons to move around, I'm just generating the movement input vector myself based on curves.

Artificial Player Input

I'm not bothering to present code here because it's just, like,

This, you know? Almost all the work is being done in the data, and how you set that up will be your own thing. Check my prior posts about Montages and how I drive things like i-frames via AnimNotifyStates. Movement is just another type of frame I set. That's where the data feeding this curve ultimately comes from.

Ultimately all I'm doing here is grabbing player input, and then going "wait, is there an override?", applying that over top if necessary, and then tada, here you go CMC, here's your input. Easy. And this works! It produces reliable, precisely controlled movement that you can do just about anything with.

But This Doesn't Always Work

Where you run into problem is, well, have you ever tried making a CMC move really quickly? You'll find it just can't. Because of how the friction logic works, you'll find the CMC can move slowly, or reasonably quickly at about a run speed, or blindingly friction-brakingly fast when you cross a certain very high threshold. And I do mean literal threshold, it amounts to you overcoming the (incredibly high) per-frame friction coefficient, so when you goose the movement that hard, it simply goes from "a brisk run" to "flying fast enough to warp through things."

As you might imagine, this presents something of a problem for attack movements, because. Say for instance you wanted to do a warp-strike. Or a dodge. Those are pretty fast movements. What to do.

Fast Grounded Movement

As it happens, there's a pretty straightforward solution: set Flying mode on your CMC. This essentially shuts down the friction logic that gets in the way, and gives you VERY precise control of the character velocity. Downside? Well, now you have to drive the literal velocity, and that includes pushing down if you want to emulate gravity. Flying mode doesn't do any of that for you.

Blessedly, this is pretty easy. Same logic you just saw? It's already there.

You just apply the player movement differently. Note how I'm sourcing the MaxWalkSpeed off the CharacterMovementComponent (CMC)? That's because elsewhere, I'm doing this:

I already had the logic to change the CMC's WalkSpeed as part of my normal piping in fake input to procedurally move around logic, so I can just use that data pipe to drive my flying speed too. Easy peasy.

Now then, this will cover you for most things. This gets you lunges forward as part of attacks, this gets you fast dodges, any short burst movement. It won't do gravity (unless you pipe in fake gravity), but mostly that's fine! Player expectation when you do a forward lunge kind of attack off a ledge is that you still lunge straight forward until the attack finishes, then gravity starts applying. Almost all games do that. So this gets you, that, for free. I don't bother applying gravity as a result. Makes my life easier. This works for almost everything!

What About Leaps

Except, leaps. Let's say you want one of those cool sideways strafe flip kinda motions like what happens in Ratchet and Clank when you're aiming forward and jump sideways. You want a clean arc.

For this, it's probably better to apply a single instance of force at the start of the motion and let the CMC take over from there. So long as you're pushing mostly upward, you can skip the Flying Mode stuff. The friction is only a problem for scraping, grounded motions, like side dodges. So if you want an arc? I'd use SuggestProjectileVelocity to get you the desired perfect velocity to land you at a desired position, and apply it once at the start of your side leap or whatever it is. Still block or damp player input so they can't mess with the movement too much, but again, so long as the force/velocity is mostly up, you can reliably launch the CMC without changing movement mode and get very consistent results. Use the LaunchCharacter node to apply the return from SuggestProjectileVelocity, and you'll be in business. If that doesn't get you the kind of motion you want? Then use Flying mode and drive the precise arc yourself via a velocity curve, probably include the option to fake gravity, and yeah it'll be a lot more annoying, but that's what it'll take to get you the precision you want.

Anyways, yeah! That's about it. This is what lives at the core of my increasingly Souls-ish combat system. Seems to cover all the bases, so far. If that changes, I'll probably do another of these, or add a comment, but pretty dang happy with it so far!

If You Use GAS, You Won't Need This

One tiny addendum: if you use GAS, you won't have to do this, because it has a very specific node for doing procedural movement. I have no idea how it works, but my strong assumption is that internally, it's doing one of the above options here. Anyways, if you know, you know. I do not particularly recommend GAS unless you need it for a bunch of other reasons. It's a very, very complex and over-built system that makes little sense unless you're making an online game where you expect to apply a lot of DOT-type abilities that have complicated overlapping conditions. Still! If that's you, yes, you don't gotta do this, there's a thing in GAS that'll already have you covered.


More Creators