I am trying to implement a 3D, Third person character movement using a Rigidbody and Cinemachine. The character should be able to walk on the ground and ceiling, as well as on the walls (only left and right wall, when facing the positive X-Axis).
I achieved that by adding/changing a constant force to the Rigidbody, to change the gravity direction and rotating the character on x for up and down and z for right and left.
The CinemachineBrain has a World Up Override set to the Characters transform and the CinemchineFreeLook Binding Mode is set to "Simple Follow with World Up". This lets the camera/cinemachine orbits rotate relative to the Characters rotation.
For now I have implemented 4 methods in my PlayerMovement Script, one for each gravity direction (up, down, left, right) each of them doing basically the same just with the changed rotation and gravity.
The MoveUp() and MoveDown() methods work as expected.
But I can't get the MoveLeft() and MoveRight() methods to work.
The Problem is that the Character can't make a 360 degree rotation (here on the x axis) when adding the cameras angle but just a 180 degree rotation while facing positive or negative x (it feels like there is an invisible wall on the y axis.
I somehow expect Cinemachine / the + Camera.main.transform.eulerAngles.x;
to be the problem here, but I can't figure out what it is exactly.
This is my first Project in Unity / Game development in general - so i hope i gave all necessary information.
Thanks for answers.
And here is my Script:
( I followed this tutorial to implement the basic movement and changed it to work with a Rigidbody : https://youtu.be/4HpC--2iowE )
public class PlayerMovement : MonoBehaviour
{
public float walkSpeed = 5f;
public float runSpeed = 15f;
public float idleSpeed = 0f;
public string gravityDiretion = "down";
public ConstantForce gravity = new ConstantForce();
private float actualSpeed;
public float turnSmoothing = 0.1f;
float turnSmoothVelocity;
private Rigidbody character;
private void Start()
{
character = GetComponent<Rigidbody>();
gravity = gameObject.AddComponent<ConstantForce>();
}
private void FixedUpdate()
{
Move();
}
private void Move()
{
if (gravityDiretion.Equals("up"))
{
MoveUp();
}
else if (gravityDiretion.Equals("down"))
{
MoveDown();
}
else if (gravityDiretion.Equals("right"))
{
MoveRight();
}
else if (gravityDiretion.Equals("left"))
{
MoveLeft();
}
}
private void MoveUp()
{
gravity.force = new Vector3(0.0f, 9.81f, 0.0f);
if (Input.GetKey(KeyCode.LeftShift))
{
actualSpeed = runSpeed;
}
else
{
actualSpeed = walkSpeed;
}
float horizonal = Input.GetAxisRaw("Horizontal"); // 1 = left -1 righ
float vertical = Input.GetAxisRaw("Vertical"); // 1 = forward -1 bakwadrd
Debug.Log("Axis Vertical = " + vertical);
Debug.Log("Axis Horizontal = " + horizonal);
Vector3 direction = new Vector3(horizonal, 0f, -vertical).normalized; //normalize to not moving faster when pressing two keys to walk diagonal
if (direction.magnitude >= 0.1f) // If lenght of the vecctor is > 0
{
//Character Rotation
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + Camera.main.transform.eulerAngles.y; // The angle the character should turn to face forward
Debug.Log("targetAngle = " + targetAngle);
float smoothedAngle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, - turnSmoothing);
Debug.Log("smoothedAngle = " + smoothedAngle);
character.MoveRotation(Quaternion.Euler(180f, smoothedAngle, 0f));
//Character Movement
Vector3 moveDir = Quaternion.Euler(180f, targetAngle, 0f) * Vector3.forward;
Debug.Log("Movedir = " + moveDir.ToString());
character.MovePosition(transform.position + moveDir.normalized * actualSpeed * Time.fixedDeltaTime);
}
else
{
actualSpeed = 0f;
}
}
private void MoveDown()
{
//Gravity
gravity.force = new Vector3(0.0f, -9.81f, 0.0f);
if (Input.GetKey(KeyCode.LeftShift))
{
actualSpeed = runSpeed;
}
else
{
actualSpeed = walkSpeed;
}
float horizonal = Input.GetAxisRaw("Horizontal"); // 1 = left -1 righ
float vertical = Input.GetAxisRaw("Vertical"); // 1 = forward -1 bakward
Debug.Log("Axis Vertical = " + vertical);
Debug.Log("Axis Horizontal = " + horizonal);
Vector3 direction = new Vector3(horizonal, 0f, vertical).normalized;
if (direction.magnitude >= 0.1f)
{
//Character Rotation
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + Camera.main.transform.eulerAngles.y;
float smoothedAngle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothing);
character.MoveRotation(Quaternion.Euler(0f, smoothedAngle, 0f));
//Character Movement
Vector3 moveDir = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
Debug.Log("Movedir = " + moveDir.ToString());
character.MovePosition(transform.position + moveDir.normalized * actualSpeed * Time.fixedDeltaTime);
}
else
{
actualSpeed = 0f;
}
}
private void MoveRight()
{
//Gravity
gravity.force = new Vector3(9.81f, 0.0f, 0.0f);
if (Input.GetKey(KeyCode.LeftShift))
{
actualSpeed = runSpeed;
}
else
{
actualSpeed = walkSpeed;
}
float horizonal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
Debug.Log("Axis Vertical = " + vertical);
Debug.Log("Axis Horizontal = " + horizonal);
Vector3 direction = new Vector3( 0f, horizonal, vertical).normalized;
if (direction.magnitude >= 0.1f)
{
float targetAngle = Mathf.Atan2(direction.y, direction.z) * Mathf.Rad2Deg + Camera.main.transform.eulerAngles.x;
Debug.Log("targetAngle = " + targetAngle);
float smoothedAngle = Mathf.SmoothDampAngle(transform.eulerAngles.x, targetAngle, ref turnSmoothVelocity, turnSmoothing);
Debug.Log("smoothedAngle = " + smoothedAngle);
character.MoveRotation( Quaternion.Euler(targetAngle, 0f , 90f));
//Character Movement
Vector3 moveDir = Quaternion.Euler(targetAngle, 0.0f, 90f) * Vector3.forward;
Debug.Log("Movedir = " + moveDir.ToString());
character.MovePosition(transform.position + moveDir.normalized * actualSpeed * Time.fixedDeltaTime);
}
else
{
actualSpeed = 0f;
}
}
private void MoveLeft()
{
//Gravity
gravity.force = new Vector3(-9.81f, 0.0f, 0.0f);
if (Input.GetKey(KeyCode.LeftShift))
{
actualSpeed = runSpeed;
}
else
{
actualSpeed = walkSpeed;
}
float horizonal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
Debug.Log("Axis Vertical = " + vertical);
Debug.Log("Axis Horizontal = " + horizonal);
Vector3 direction = new Vector3(0f, horizonal, vertical).normalized;
if (direction.magnitude >= 0.1f)
{
//Character Rotation
float targetAngle = Mathf.Atan2(direction.z, direction.y) * Mathf.Rad2Deg + Camera.main.transform.eulerAngles.x;
float smoothedAngle = Mathf.SmoothDampAngle(transform.eulerAngles.x, targetAngle, ref turnSmoothVelocity, turnSmoothing);
character.MoveRotation(Quaternion.Euler(smoothedAngle, 0f, -90f));
//Character Movement
Vector3 moveDir = Quaternion.Euler(targetAngle, 0.0f, -90f) * Vector3.right;
Debug.Log("Movedir = " + moveDir.ToString());
character.MovePosition(transform.position + moveDir.normalized * actualSpeed * Time.fixedDeltaTime);
}
else
{
actualSpeed = 0f;
}
}
public void ChangeDravityDirection(string newGravityDirection)
{
gravityDiretion = newGravityDirection;
}