Tuesday, June 20, 2017

unity - Camera relative movement is pushing into/off the ground instead of parallel


I'm building upon roll a ball tutorial in unity, and I have managed to rotate the camera around the ball just fine with the code below. But there's one problem.


In this code, when I add force to the ball, with W for example, the force will be added in the exact direction the camera is looking at the ball, meaning pushing the ball onto the ground, increasing friction and lowering speed. And if I press S the force will push the ball to the air, lowering friction and making the ball move fast.


So my question is, how can I achieve rotation without this issue?


Code for Camera (CameraController):


public GameObject Player;
private Vector3 offset;

public float cameraSpeed;
private Vector3 point;
static public Vector3 finalMovement;


void Start () {
offset = transform.position - Player.transform.position;

point = Player.transform.position;
transform.LookAt(point);

}

void LateUpdate()
{
point = Player.transform.position;

offset = Quaternion.AngleAxis(Input.GetAxis("Mouse X") * cameraSpeed, Vector3.up) * offset;
transform.position = point + offset;
transform.LookAt(point);
}


Vector3 movement;
void FixedUpdate()
{
movement = new Vector3();
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
movement = new Vector3(moveHorizontal, 0f, moveVertical);

finalMovement = GetComponent().transform.TransformDirection(movement);

}

Code for ball:


public float speed;
void FixedUpdate()
{
rb.AddForce((CameraController.finalMovement) * speed);
}

Answer



I often like to give myself a little convenience method:



Vector3 CameraRelativeFlatten(Vector3 input, Vector3 localUp)
{
// If this script is on your camera object, you can use this.transform instead.
Transform cam = Camera.main.transform;

// The first part creates a rotation looking into the ground, with
// "up" matching the camera's look direction as closely as it can.
// The second part rotates this 90 degrees, so "forward" input matches
// the camera's look direction as closely as it can in the horizontal plane.
Quaternion flatten = Quaternion.LookRotation(

-localUp,
cam.forward
)
* Quaternion.Euler(Vector3.right * -90f);

// Now we rotate our input vector into this frame of reference
return flatten * input;
}

When I have an input in controller space, I can use this convert it to a direction in the world horizontal plane, relative to the camera:



Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));

Vector3 worldSpaceInput = CameraRelativeFlatten(input, Vector3.up);

If we wanted, we could also use a local surface normal instead of Vector3.up to get our input parallel to an arbitrary tilted surface, instead of always in the XZ plane.


Since we're rotating the input vector, the length is preserved, so we won't just chop off the portion of a vector that was digging into the surface, slowing our forward-back movement relative to left-right.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...