Home > OS >  Reducing player speed when walking backwards, left and right?
Reducing player speed when walking backwards, left and right?

Time:11-22

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 with transform.forward
  • 0 => 90° to transform.forward => purely sideward
  • -1 exactly opposite direction to transform.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 => interpolate sidewardSpeed -> forwardModifier
  • dot = 0 => sidewardModifier
  • -1 -> 0 => interpolate backwardSpeed -> sidewardSpeed
  • dot = -1 => backwardModifer
  • Related