I'm making a character move right with addforce and in order to keep the player from infinitely going up to mach 10, I clamp the velocity. Which works fine HOWEVER if I clamp the velocity it also clamps the y velocity which prevents me from jumping.
if (moveDir.magnitude >= 0.1f)
{
controller.AddForce(moveDir * moveSpeed, ForceMode.Impulse);
//Needs a fix because it also clamps the Y velocity which is needed so it doesn't fall slowly
controller.velocity = Vector3.ClampMagnitude(controller.velocity, moveSpeed);
//Animation Call
animationCaller.Animation_Move(animator);
}
else
{
//Needs a fix because it also clamps the Y velocity which is needed so it doesn't fall slowly
controller.velocity = Vector3.ClampMagnitude(controller.velocity, 0f);
controller.angularVelocity = Vector3.ClampMagnitude(controller.angularVelocity, 0f);
//Animation Call
animationCaller.Animation_Idle(animator);
}
Tried seperating them all into their own vector 3 and then re adding back the y velocity after it calmps it but that causes an issue where the velocity never goes back down.
controller.AddForce(moveDir * moveSpeed, ForceMode.Impulse);
/*
Vector3 clampVelocity;
clampVelocity.x = 0;
clampVelocity.y = controller.velocity.y;
clampVelocity.z = 0;
*/
controller.velocity = Vector3.ClampMagnitude(controller.velocity, moveSpeed); // clampVelocity;
CodePudding user response:
When you clamp the magnitude of a Vector, you limit its scalar size. That means, irrespective of direction it can't exceed a given size.
If you want to impose a limit to the non-vertical components, you can project the Z and X components onto a 2D vector, and clamp that, then, set the X and Z components on the original Vector3 accordingly.
To make this behavior well integrated, it would be wise to add assignment logic to a property for the velocity vector. However, this may require you to extend the physics object class you're using. Since you call the velocity member of the GameObject itself (which is just a redirect to the velocity of the first physics component it finds) you can either change the type of the physics controller you're assigning, or hide the inherited velocity properly of your gameObject.
CodePudding user response:
I think your were close but you want to first clamp only XZ and then keep the current Y velocity like e.g.
controller.AddForce(moveDir * moveSpeed, ForceMode.Impulse);
// get velocity
var currentVelocity = controller.velocity;
// store Y axis
var currentY = currentVelocity.y;
// reset Y axis - so it doesn't influence the clamp
currentVelocity.y = 0;
// clamp magnitude of XZ
currentVelocity = Vector3.ClampMagnitude(currentVelocity, moveSpeed);
// re-apply Y axis
currentVelocity.y = controller.velocity.y;
controller.velocity = currentVelocity;
Though my question would be why even use AddForce
at all?
You could probably as well just compose the velocity directly like
// already clamp on the input
var velocity = Vector3.ClampMagnitude(moveDir * moveSpeed);
// also take over current Y axis
velocity.y = controller.velocity.y;
controller.velocity = velocity;
Then what exactly is
controller.velocity = Vector3.ClampMagnitude(controller.velocity, 0f);
supposed to do? If you clamp the magnitude to 0
you can as well just right Vector3.zero
. If you only want to reset two components XZ you could simply do
var velocity = controller.velocity;
velocity.x = 0;
velocity.z = 0;
controller.velocity = velocity;