I have a player where you move with WASD. Currently, moving forwards and backwards has the same speed, but walking backwards and sideways should be slower.
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x transform.forward * z;
if (move.magnitude > 1)
move /= move.magnitude;
controller.Move(move * speed * Time.deltaTime);
if (Input.GetKey(KeyCode.LeftShift))
{
speed = sprintSpeed;
}
else
{
speed = walkSpeed;
}
The only solution I have would be to add if statements for W, A, S and D keys and reduce their speeds individually based on the users key input, but I'm not sure if that's a bad way to implement it.
CodePudding user response:
One way is to check if the pressed key is W and then set the speed with more magnitude.
float wSpeed = 10f;
float sdfSpeed = 7f;
float currentSpeed;
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 move = transform.right * x transform.forward * z;
// Check if W is pressed
if(move.x == 0 && move.z > 0) {
currentSpeed = wSpeed;
} else {
currentSpeed = sdfSpeed;
}
controller.Move(move * currentSpeed * Time.deltaTime);
CodePudding user response:
You could use Vector3.Dot
to check how much the input vector aligns with your forward vector
var dot = Vector3.Dot(move.normalized, transform.forward);
=> which would tell you
1
=>move
fully aligns withtransform.forward
0
=> 90° totransform.forward
=> purely sideward-1
exactly opposite direction totransform.forward
=> fully backwards
Then you could define your different speed modifiers and blend them together accordingly like e.g.
// With these example values
// - Moves forwards with full speed
public float ForwardSpeed = 1f;
// - Moves sidewards with 70% of full speed
public float SidewardSpeed = 0.7f;
// - Moves backwards with 50% of full speed
public float BackwardSpeed = 0.5f;
...
var x = Input.GetAxis("Horizontal");
var z = Input.GetAxis("Vertical");
var move = Vector3.ClampMagnitude(transform.right * x transform.forward * z, 1f);
if (Input.GetKey(KeyCode.LeftShift))
{
speed = sprintSpeed;
}
else
{
speed = walkSpeed;
}
var dot = Vector3.Dot(move.normalized, transform.forward);
// since the factor of Lerp is clamped between "0" and "1" this will effectively only interpolate
// between "dot = 1" (fully forwards) to "dot = 0" (fully sideward)
// and just stay 0 for "dot < 0" (sideward-backward)
var forwardModifier = Mathf.Lerp(0f, ForwardSpeed, dot);
// This will treat forward and backward the same and just interpolate between "dot = 0" (fully forwards)
// and "Abs(dot) > 1" (not sidewards)
var sidewardModifier = Mathf.Lerp(SidewardSpeed, 0f, Mathf.Abs(dot));
// This basically works exactly inverted as the "forwardsModifier"
// and interpolates between "dot = -1" (fully backwards) to "dot = 0" (fully sidewards)
// an just stays "0" for "dot > 0"
var backwardModifier = Mathf.Lerp(0f, BackwardSpeed, -dot);
speed *= (forwardModifier sidewardModifier backwardModifier);
controller.Move(move * speed * Time.deltaTime);
See also Mathf.Lerp
.
This basically blends the three possible modifiers together such that mapped to the dot
you could basically also read it as
dot = 1
=>forwardModifier
0 -> 1
=> interpolatesidewardSpeed -> forwardModifier
dot = 0
=>sidewardModifier
-1 -> 0
=> interpolatebackwardSpeed -> sidewardSpeed
dot = -1
=>backwardModifer