Getting character controller to move at varying input speed

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
Alic
Posts: 39
Joined: Fri Jul 29, 2011 2:25 pm

Getting character controller to move at varying input speed

Post by Alic »

Hey Norbo!

I've been looking around in the Character.HorizontalMotionConstraint class for a while and can't quite wrap my head around everything going on there, so I thought I'd ask this one.

I want analog stick input to control the speed my character moves. So pressing the analog stick 20% of the way to the right will make the character move right at 20% speed after they've fully accelerated from standing still.

I've been doing this by simply setting the Speed property of the constraint every frame based on player input. The problem is that this makes deceleration very unnatural. If you're moving at full speed (analog input 100%) and then the next frame you are only pressing the stick 10% in the same direction, the character's linear velocity is instantaneously set to the new Speed value (which will be 10% of what it was the frame before).

What I'd like to have happen is that the character decelerates, just as if the IsTryingToMove bool is equal to false. (When there is no input, rather than less input, my code doesn't edit Speed, it sets HorizontalMotionConstraint.MovementDirection = new Vector2, and deceleration works perfectly.)

Should I modify the constraint so that if LinearVelocity.Length > maxSpeed, it behaves more like the scenario where MovementDirection = Vector2.Zero? Or should I keep the concept of maxSpeed working the way it does during the HorizontalMotionConstraint's Update method and instead introduce a new concept, something like targetSpeed, which would accelerate the character but not instantly decelerate them, and then only change the target speed each frame based on analog stick input, rather than the maxSpeed?

Or am I approaching this whole thing the wrong way? Is there already a built in way to make the character move at different target speeds based on input, while having deceleration work smoothly/consistently?

Thanks a lot,
Alex
Last edited by Alic on Tue Jan 15, 2013 9:58 pm, edited 1 time in total.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Getting character controller to move at analog stick spe

Post by Norbo »

What I'd like to have happen is that the character decelerates, just as if the IsTryingToMove bool is equal to false.
...
Should I modify the constraint so that if LinearVelocity.Length > maxSpeed, it behaves more like the scenario where MovementDirection = Vector2.Zero?
Deceleration is handled in the same way in either case. There should be no 'instant' deceleration when changing the speed of the character; it should obey the specified maximum force.
Or am I approaching this the wrong way? Is there already a built in way to make the character move at different target speeds based on input, while having deceleration work smoothly/consistently?
Not built in, but adding it is pretty easy. Modifying the character speeds directly is a little inconvenient, but they all boil down to a single targetVelocity each frame. Scaling that single targetVelocity through a property would be pretty convenient. I've added such a property to the development fork to demonstrate.

[Note that this is identical to modifying character speeds directly in terms of end result, it's just easier to use.]
Alic
Posts: 39
Joined: Fri Jul 29, 2011 2:25 pm

Re: Getting character controller to move at varying input sp

Post by Alic »

Cool, checking out the development fork now... seems I was editing my message just as you were typing your reply once again. Sorry about that -- didn't add anything new, was just trying to clarify.
Alic
Posts: 39
Joined: Fri Jul 29, 2011 2:25 pm

Re: Getting character controller to move at varying input sp

Post by Alic »

Hey Norbo, so after some testing, I'm willing to admit I was imagining the instant deceleration on the ground! But the main reason I was imagining it is that something weird does happen while the character is floating. I'm testing this with the SpeedScale property implemented just as you have it in the development fork.

I was wrong about the deceleration being instantaneous -- what's happening is that my character's MaximumAirForce is set very high, so when the maxSpeed gets set lower due to SpeedScale, the force quickly corrects the speed down. However, when the character is floating and MovementDirection == Vector2.Zero, the character's velocity remains constant -- they keep traveling in the same direction. I thought it was slightly decelerating, but I'm pretty sure I'm wrong now.)

So anyway, I was completely wrong about what was happening, but is there any way to make it so a floating character won't decelerate when their maxSpeed is scaled down? Ideally the only time they'd decelerate is when their movementDirection is pushing them in the opposite direction, and otherwise they would maintain their velocity while floating, similar to the current behavior when movementDirection is Vector2.Zero.

Sorry if this is a bit of a jumble, I'll clean it up later tonight. (Heading out for now).

Thank you,

Alex
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Getting character controller to move at varying input sp

Post by Norbo »

is there any way to make it so a floating character won't decelerate when their maxSpeed is scaled down? Ideally the only time they'd decelerate is when their movementDirection is pushing them in the opposite direction, and otherwise they would maintain their velocity while floating
That is roughly how it works now. Floating characters already have a special case which prevents deceleration. They only accelerate in the MovementDirection, up to the MaximumAirSpeed. If it's already beyond the MaximumAirSpeed, it doesn't do anything- no acceleration, no deceleration.
Alic
Posts: 39
Joined: Fri Jul 29, 2011 2:25 pm

Re: Getting character controller to move at varying input sp

Post by Alic »

Aaaand you are absolutely right, sir. I was using an outdated version of the character controller missing that special case. Putting the new one in now... That will teach me to be lazy about updating the character controller when I upgrade to new versions. Sorry to waste your time Norbo, I try to only ask questions as a last resort because you answer so darn many of them!

Thanks a bunch


*edit*
It wasn't even a problem with an outdated version, it was that I had commented out the special case floating behavior, because of other behavior I didn't like, many months ago! Going to try to figure out how to get the floating behavior to not decelerate, which the special case code does fix, while also not allowing the character's current maxSpeed to be violated. (Which is why I had the floating special case commented out; the "Half Life 2 speed run" behavior is really odd looking when you have as much air control as I have in my third person game.)
Alic
Posts: 39
Joined: Fri Jul 29, 2011 2:25 pm

Re: Getting character controller to move at varying input sp

Post by Alic »

Okay, reporting back, I got a pretty good feeling version of what I was looking for. In case anyone else wants to get rid of the Half-Life 2 style jump accelerating (where maxSpeed gets violated if you steer laterally while you're jumping), and they want to do it without breaking the floating behavior the way I did a few months ago, this seems to work:

At line 592 in the latest development version, where it reads

Code: Select all

            if (MovementMode == MovementMode.Floating)
            {
                //If it's floating, clamping rules are different.
                //The constraint is not permitted to slow down the character; only speed it up.
                //This offers a hole for an exploit; by jumping and curving just right,
                //the character can accelerate beyond its maximum speed.  A bit like an HL2 speed run.

                accumulatedImpulse.X = MathHelper.Clamp(accumulatedImpulse.X + lambda.X, 0, maxForce);
                accumulatedImpulse.Y = 0;

            }
Change the if statement to:

Code: Select all

if (MovementMode == MovementMode.Floating && relativeVelocity.X + lambda.X < AirSpeed)
Thanks for all of your responses, Norbo! I really had no idea what was going on when I woke up this morning! :)
Post Reply