0
\$\begingroup\$

I have a Unity project in which I want to control a player in a similar way to Source games, and so far I am clipping each input to the speed in the player's coordinates, by using

transform.InverseTransformDirection( GetComponent<Rigidbody>().velocity )

after which I pass each of the player's input vector direction through this function:

private float FLSMF ( float aInputVelocity, float aMaximumVelocityOnAxis, float aSpeedOnAxis ) {
    if ( Mod( aSpeedOnAxis ) >= aMaximumVelocityOnAxis ) {
        if( Sign( aSpeedOnAxis ) != Sign ( aInputVelocity ) ) {
            if ( Mod( aSpeedOnAxis + aInputVelocity ) > aMaximumVelocityOnAxis ) {
                return Sign ( aInputVelocity ) * ( aMaximumVelocityOnAxis + Mod( aSpeedOnAxis ) );
            }
            return aInputVelocity;
        }
        return 0;
    }
    if( Mod( aSpeedOnAxis + aInputVelocity ) > aMaximumVelocityOnAxis ) {
        return Sign( aInputVelocity ) * ( aMaximumVelocityOnAxis - Mod( aSpeedOnAxis ) );
    }
    return aInputVelocity;
}

There is only one problem: whenever I turn and strafe and walk forwards or backwards, the speed increases dramatically. I tried solving it by comparing each processed velocity axis to the velocity rotated by the difference in the rotations between the last 2 FixedUpdate's. So far nothing worked, aside from driving the drag factor through the roof.

My best guess is that when turning, the unclipped X axis of the vector bleeds into the Z axis when turning, which can't add anything, but cant stop the X axis from interfering because the forward key is pressed.

There is no issue when only one of the input axis are used, the speed remaining consistent when turning.

I tried to implement this function especially so I don't have to use any drag, to allow the player to be flung by other things, like grapples and explosions (this issue is present irrespective of said external factors).

If you want to, I will share the entire code, but it's messy and I don't think it would help.

Any ideas how to solve it?

Edit: yes, I have normalized the input vector. The speed increases to more than triple of the maximum, in as few as 2 turns.

\$\endgroup\$
0
\$\begingroup\$

The usual pattern I use for this is something like...

void FixedUpdate()
{
    var movementInput = new Vector2(
                                 Input.GetAxis("Horizontal"), 
                                 Input.GetAxis("Vertical")
                            );

    // Ensure our movement input never exceeds a radius of 1.
    var movementInput = Vector2.ClampMagnitude(movementInput, 1f);

    var movementFrame = Quaternion.LookRotation(-groundNormal, camera.forward);

    // Accelerate up to, but not past, our max speed.
    var desiredVelocity = movementFrame * (Vector3)(movementInput * maxSpeed);        
    AccelerateTo(desiredVelocity);
}

void AccelerateTo(Vector3 desiredVelocity) {
    // Compute the desired change in velocity.
    var deltaV = desiredVelocity - body.velocity;        

    // Enforce our maximum acceleration limits when speeding up or slowing down.
    float limit = maxAcceleration;
    if (Vector3.Dot(body.velocity, desiredVelocity) <= 0f) 
        limit = maxDeceleration;

    deltaV = Vector2.ClampMagnitude(deltaV, limit * Time.deltaTime);

    body.AddForce(deltaV, ForceMode.VelocityChange);
}

This ensures the player can never push themselves to go faster than maxSpeed in any direction, and propels themselves with only a finite acceleration or deceleration.

I usually keep the maxAcceleration quite high for tight controls, and the maxDeceleration even higher so you stop quickly when you let go. But you can vary these two variables depending on the game state - dropping them when the player is on slippery terrain or in a knockback state where you want them to keep moving inertially.

\$\endgroup\$
2
  • \$\begingroup\$ I didnt see your comment in time, sorry. Aside from that, this script is basically a Rigidbody MovePosition one. I am more intrested in the underlying reason for the speed increase when turning. I am controlling the drag by a combination of parenting and physics material manipulation, and i am also increasing or decreasing the input force efficiency based on said material, so the player can skid on ice. I will create a minimum provable project and send it over as an example. \$\endgroup\$ – UndeF NuLL Dec 19 '20 at 22:50
  • \$\begingroup\$ I will not open a stranger's project file, so do not send it to me. You're welcome to edit your question to include the steps to build a minimal complete verifiable example though. \$\endgroup\$ – DMGregory Dec 19 '20 at 22:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.