CharacterMovementComponent changes in beta 6?

I’m confused about some of the changes to CharacterMovementComponent and how I’m supposed to use it now?

It used to be that you could pass in a velocity (that inherently had a direction because of the argument being a vector) using one of two functions and the character would move in that direction as expected. For example it used to be possible to do something like this:

	FVector delta_pos(0.f, -(MovementSpeed * DeltaSeconds), 0.f);
	CharacterMovement->MoveSmooth(delta_pos);

Or this:

	FVector direction = delta_pos.SafeNormal();
	CharacterMovement->CalcVelocity(MovementSpeed, direction, DeltaSeconds, 0.f, true, 10.f);

Now the arguments have changed so that the same code would look like:

	FVector delta_pos(0.f, -(MovementSpeed * DeltaSeconds), 0.f);
	CharacterMovement->MoveSmooth(delta_pos, DeltaSeconds);

	FVector direction = delta_pos.SafeNormal();
	CharacterMovement->CalcVelocity(DeltaSeconds, 0.f, true, 10.f);

And the character still moves - but ignores the direction. Now velocity truly is a velocity - but how do I make it move in a given direction?

I’m still looking into it and I’m hoping that when the Release Notes are available that it’ll be documented - but it’s worth asking in case somebody has already hit (and solved) this problem already!

Now the arguments have changed so that
the same code would look like:

FVector delta_pos(0.f, -(MovementSpeed * DeltaSeconds), 0.f);
CharacterMovement->MoveSmooth(delta_pos, DeltaSeconds);

This isn’t correct, you are applying DeltaSeconds twice. The function now takes a Velocity and DeltaTime, whereas previously it only took a movement delta, which was Velocity * DeltaTime.

Nothing about the internal treatment of the velocity with respect to direction has changed.

By the way, MoveSmooth() is generally intended as a less-complete version of movement, usually used by simulated proxies on the network. While your use of it might not be strictly incorrect, it is usually better in general to accumulate changes to the InputVector to apply acceleration, or directly affect Velocity, and then let the tick logic for specific movement modes take care of it. However it is reasonable to use it in cases where you need to apply a force and immediately have movement applied, which may be the case for you.

As for CalcVelocity():

We removed AccelDir because we never had a case where it was different than current Acceleration, and the out param was always the same as Acceleration.SafeNormal() as well. CalcVelocity() operates based on current Velocity and Acceleration, applying the effects of friction and braking as well.

The only difference in the result now compared to before is when Acceleration is non-zero and AccelDir was not equal to Acceleration, and the difference was minor at that. That was a bizarre edge case we decided to remove for simplicity.

Good spot! I saw earlier that I was doing that twice now.

That said, it does appear as though something changed with regards to the internal treatment of velocity. This same code (albeit with more arguments!) with beta 5 had the character moving along the Y axis but now it only moves in the positive direction along the X axis. It looks like it’s just getting the vector length and using that as the velocity whereas before it was also using it for the direction too.

With beta 5 I could pretty much used either MoveSmooth or CalcVelocity (if I didn’t care about animation) and that would move the character at the given speed along with the given direction. Now it just moves the character at a given speed in a direction I can’t appear specify…

For example:

FVector delta_pos(0.f, -(MovementSpeed), 0.f);
CharacterMovement->MoveSmooth(delta_pos, DeltaSeconds);

FVector delta_pos(0.f, MovementSpeed, 0.f);
CharacterMovement->MoveSmooth(delta_pos, DeltaSeconds);

FVector delta_pos(-(MovementSpeed), 0.f, 0.f);
CharacterMovement->MoveSmooth(delta_pos, DeltaSeconds);

FVector delta_pos(MovementSpeed, 0.f, 0.f);
CharacterMovement->MoveSmooth(delta_pos, DeltaSeconds);

…all move the character in exactly the same direction.

Is CharacterMovementComponent.CurrentFloor valid at the time you are using this function? Try a displayall CharacterMovementComponent.CurrentFloor and see if the normals look reasonable.

I tried putting this at the end of CharacterMovementComponent::TickComponent:

const float MovementSpeed = 100.f;
FVector delta_pos;

delta_pos.Set(0.f, MovementSpeed, 0.f);
MoveSmooth(delta_pos, DeltaTime);

delta_pos.Set(MovementSpeed, 0.f, 0.f);
MoveSmooth(delta_pos, DeltaTime);

And it moves in +x and +y as expected, no matter the orientation of the character, and layered on top of any input velocity I apply.

Do you possibly have other code or settings that could conflict? Plane constraint, overridden functions, BP scripts…

I don’t think so. I’ll have to do some more investigation then I guess - but I’m calling those functions from my actor’s tick function. I didn’t override anything in the component itself so I’m somewhat at a loss…

Hi Neil, did you figure out what the issue was?

Yes… and no. It was related to me forcing max acceleration but some other bug is causing them to move in the direction that they spawned and completely ignore the velocity I was passing in.

I’ve “solved” the issue for now - but I’m clearly doing something wrong (or at least not in the way that Epic imagined the CharacterMovement component to work!). I’m going to open a new question about that now rather than confuse this one. :slight_smile:

Dear Neil,

You want direction relative to the facing of the Character?

#My Direction From Velocity + Actor Rotation Code
You can use code similar to this if you like

I use this in my custom animinstance class

This code gives you a float value of direction in range of -180 to 180 based on the velocity of the Character as well as the Character’s Actor Rotation

.h

float Direction;

.cpp

//~~~ Direction ~~~
	//Normalized Diff between velocity dir and character rotation
	RV_Rot = VictoryCharacter->GetVelocity().Rotation() - VictoryCharacter->GetActorRotation();
	RV_Rot.Normalize();
		
	//if direction > 180 subtract 360
	if (RV_Rot.Yaw <= 180) Direction = RV_Rot.Yaw;
	else Direction = RV_Rot.Yaw - 360;



	//Strafing?
	if(FMath::Abs(Direction) > 85 && FMath::Abs(Direction) < 110  ) IsStrafing = true;
	else IsStrafing = false;

	//switch Direction for Backing up with A or D
	if(FMath::Abs(Direction) > 120) UseBackwardsBlendSpace = true;
	else UseBackwardsBlendSpace = false;
		
	//~~~ END OF DIRECTION ~~~

The Key Part For You

the key part for your own use is here, I re-wrote a bit more clearly

//Normalized Diff between velocity dir and character rotation
FRotator TheRot = VictoryCharacter->GetVelocity().Rotation() - VictoryCharacter->GetActorRotation();
TheRot.Normalize();
		
//if direction > 180 subtract 360
if (TheRot.Yaw <= 180) Direction = TheRot.Yaw;
else Direction = TheRot.Yaw - 360;

this code yields a range from -180 to 180, where 90 is right, -90 is left, -180 and 180 are straight behind, 0 is forward

:slight_smile:

:heart:

Rama

I don’t think that’s what he was asking …

No, I don’t mean that. That’s easy. I appreciate you trying to help though! :slight_smile:

The function prototypes for MoveSmooth and CalcVelocity have changed inside of the CharacterMovementComponent and they now ignore the direction of the vector being passed in - instead using only the length (speed - or velocity in this case) of the vector… It’s important to know how these work if you want to move characters around when they’re not being driven by a PlayerController or by the Navigation System.