- Home /
How to transform velocity to world space before calling controller.move?
In my game I am trying to make it so that the player's velocity increases based on the direction the camera is facing. This is simple enough to do, by calling controller.move(transform.TransformDirection(velocity)), but there is the issue that if the player then rotates the camera, the velocity will again be converted, causing the player to swerve. I'm trying to make it so that, for example, when the player presses "W," they will increase speed in the direction that the camera is facing, at the exact instance the key is pressed.
This is what I presently have; as you can see whenever the player presses a movement key, their velocity increases by the respective amount, but that value is transformed the instant that the key is pressed instead of waiting for the .move(velocity) to be called. I did this in hopes that the player would continue travelling in the same direction that the velocity would be regardless of the gameobject's rotation. This works as intended when the player has a rotation of 0,0,0, but I get some extraneous results when changing rotation. How can I improve my movement script?
private void movePlayer()
{
if (playerController.isGrounded)
{
if (Input.GetKey(KeyCode.Space))
{
velocity.y = 10f;
}
if (Input.GetKey(KeyCode.W))
{
if (velocity.z < maxSpeed)
{
velocity += player.transform.TransformDirection(0, 0, (accelerationSpeed * Time.deltaTime));
if(velocity.z > maxSpeed) { velocity.z = maxSpeed; }
}
}
if (Input.GetKey(KeyCode.S))
{
if(velocity.z > -maxSpeed)
{
velocity -= player.transform.TransformDirection(0, 0, (accelerationSpeed * Time.deltaTime));
if (velocity.z < -maxSpeed) { velocity.z = -maxSpeed; }
}
}
if (Input.GetKey(KeyCode.A))
{
if(velocity.x > -maxSpeed)
{
velocity -= player.transform.TransformDirection((accelerationSpeed * Time.deltaTime), 0, 0);
if (velocity.x < -maxSpeed) { velocity.x = -maxSpeed; }
}
}
if (Input.GetKey(KeyCode.D))
{
if(velocity.x < maxSpeed)
{
velocity += player.transform.TransformDirection((accelerationSpeed * Time.deltaTime), 0, 0);
if (velocity.x > maxSpeed) { velocity.x = maxSpeed; }
}
}
applyFriction();
}
if (!playerController.isGrounded)
{
velocity.y -= 25f * Time.deltaTime;
}
playerController.Move(velocity * Time.deltaTime);
Answer by Ermiq · Nov 25, 2019 at 09:52 AM
So, you want to simulate inertia, right? Maybe something like this?
Update: previous version was all wrong actually.
Vector3 desiredDirection;
Vector3 velocity;
float inputX;
float inputY;
void Update() {
inputX = Input.GetAxis("Horizontal"); // A D input
inputY = Input.GetAxis("Vertical"); // W S input
// get desired move direction relative to camera or transform direction and WASD inputs
desiredDirection = (transform.right * inputX + transform.forward * inputY).normalized;
// calculate the velocity the controller will get to check the resulting speed
velocity = controller.velocity + desiredDirection * accelerationSpeed * Time.deltaTime;
// if the speed gonna be more than maxSpeed, than just set velocity to maxSpeed at the desired direction
if (velocity.magnitude > maxSpeed)
velocity = desiredDirection * maxSpeed;
controller.Move(velocity * Time.deltaTime);
}
With this setup the controller should slow down when you rotate briefly and get speed on again in new direction, I guess.
But it won't stop if you just release all WASD keys. The only way to stop is to hold down S key while looking in the move direction. Or W while looking opposite.
To make the controller stop when there's no input, need to make it something like this:
Vector3 desiredDirection;
Vector3 velocity;
float inputX;
float inputY;
void Update() {
inputX = Input.GetAxis("Horizontal"); // A D input
inputY = Input.GetAxis("Vertical"); // W S input
// get desired move direction relative to camera or transform direction and WASD inputs
desiredDirection = (transform.right * inputX + transform.forward * inputY).normalized;
if ((inputX = 0 && inputY = 0) //released WASD
{
velocity = Vector3.zero;
}
else // if at least one of WASD keys is down
{
// calculate the velocity the controller will get to check the resulting speed
velocity = controller.velocity + desiredDirection * accelerationSpeed * Time.deltaTime;
// if the speed gonna be more than maxSpeed, than just set velocity to maxSpeed at the desired direction
if (velocity.magnitude > maxSpeed)
velocity = desiredDirection * maxSpeed;
}
controller.Move(velocity * Time.deltaTime);
}
I ended up asking some of my friends and we talked through the process and figured it out, but this is roughly the same conclusion we got to. Thanks.