Coding Adventure – Golem Player Controller

The Old Method

I want to use Unity’s physics system to move my player, rather than taking in keyboard input and translating the player. Using the rigidbody.addforce() function, you can quickly get realistic movement for an object that can interact with the environment.

My player controller has a fixed camera that sits behind the player like most third person games. To get the camera to follow the player, I could have simply set the player object as the parent and then the camera would inherit the players movements and rotations. But this happens…

First Iteration


To fix this, I took a few steps. The first, I created an empty game object that sat as the root player. I set the player and the camera as a child of the root. Then I needed to figure out a why to get the player to have the same vector forward as the camera.

void FixedUpdate() {
    float moveHorizontal = Input.GetAxis("Horizontal");
    float moveVertical = Input.GetAxis("Vertical");

    Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);

    RB.AddForce(movement * Speed * Time.deltaTime);
  }

In the initial method, in FixedUpdate, a force was added to a Vector3 of the input direction. The problem with this, was that the force was added in world space, so no matter how the player rotated the camera, if they moved forward, they would move forward in world space.

Second Iteration


My second iteration was clunky using GetKeyDown did not provide the movement that I was looking for. My problem was that I was still in the head space of non physics-based translation, taking input from individual keys, when I had most of the solution the first time.

// position
if (Input.GetKeyDown(KeyCode.W)) {
  Movement.z += PlayerSpeed * Time.deltaTime;
  transform.position += transform.TransformDirection(Vector3.forward) * 
                        PlayerSpeed * Time.deltaTime;
  RB.AddForce(Camera.transform.TransformDirection(Vector3.forward) * 
              Speed * Time.deltaTime);
}
if (Input.GetKeyDown(KeyCode.S)) {
  RB.AddForce(Camera.transform.TransformDirection(Vector3.back) * 
              Speed * Time.deltaTime);
}
if (Input.GetKeyDown(KeyCode.A)) {
    RB.AddForce(Camera.transform.TransformDirection(Vector3.left) * 
                Speed * Time.deltaTime);
}
if (Input.GetKeyDown(KeyCode.D)) {
   RB.AddForce(Camera.transform.TransformDirection(Vector3.right) * 
               Speed * Time.deltaTime);
}

It was a lot of code that didn’t work right. I was over thinking and over complicating it.

The Final Product


After doing some reading on Unity’s world space and local space, using the same Vector3 from the begin, I converted that to the local Vector3 of the of the camera controller. Now when the player rotates using Q or E, and then press WASD, the player will move in the local space direction.

 moveHorizontal = Input.GetAxis("Horizontal");
 moveVertical = Input.GetAxis("Vertical");

 Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);

 RB.AddForce(Camera.transform.TransformDirection(movement) * 
             Speed * Time.deltaTime);

In the GIF above, I am moving forward by only holding down W and holding E to turn to the right. The movement is done through the rigidbody.addforce() and is based on the local facing direction of the camera controller. I have achieved my desired effect.

Project Links


You can access the repository of this project here: https://github.com/Scottin3d/GolemPlayground