- Home /
Movement Relative to both Camera and XZ Plane
I have simple movement set up with a sphere object using a Mouse Orbit style camera and Rigidbody.AddForce(). The main issue is that I want it to move in the direction the camera is facing but only receiving input force along the XZ plane, but when I add force when the camera is facing up or down, I fly up into the air. I understand what is causing this, but I am wondering if there is a way to calculate its XZ rotation in relation to the world space that doesn't involve what I used as a workaround: I attached an empty gameobject as a child to the main camera that the camera movement script doesn't send it the Y rotation.
This is my code prior to me implementing my workaround fix:
function FixedUpdate()
{
var cameraRight : Vector3 = Camera.main.transform.TransformDirection(Vector3.right);
var cameraFront : Vector3 = Camera.main.transform.TransformDirection(Vector3.forward);
cameraRight.Normalize();
cameraFront.Normalize();
if(Input.GetAxis("Horizontal") > 0)
{
Debug.Log("Right");
GetComponent(Rigidbody).AddForce(cameraRight * moveSpeed * Time.deltaTime);
}
if(Input.GetAxis("Horizontal") < 0)
{
Debug.Log("Left");
GetComponent(Rigidbody).AddForce(-cameraRight * moveSpeed * Time.deltaTime);
}
if(Input.GetAxis("Vertical") > 0)
{
Debug.Log("Forward");
GetComponent(Rigidbody).AddForce(cameraFront * moveSpeed * Time.deltaTime);
}
if(Input.GetAxis("Vertical") < 0)
{
Debug.Log("Back");
GetComponent(Rigidbody).AddForce(-cameraFront * moveSpeed * Time.deltaTime);
}
}
I clearly understand why this doesn't work, but I am at a loss as to how to calculate a way to get 100% of the force to be applied forward and backward along the XZ plane whenever the camera's Y rotation isn't perfectly zero.
Any help is much appreciated. Thanks!
Answer by rutter · Jul 14, 2014 at 08:43 PM
Probably the simplest thing is to zero out the y-axis on your reference vectors:
var cameraRight : Vector3 = Camera.main.transform.TransformDirection(Vector3.right);
var cameraFront : Vector3 = Camera.main.transform.TransformDirection(Vector3.forward);
cameraRight.Normalize();
cameraFront.Normalize();
Change to:
var cameraRight : Vector3 = Camera.main.transform.TransformDirection(Vector3.right);
var cameraFront : Vector3 = Camera.main.transform.TransformDirection(Vector3.forward);
cameraRight.y = 0;
cameraFront.y = 0;
cameraRight.Normalize();
cameraFront.Normalize();
There is probably a general solution involving cross products, but that's a lot more work. ;)
I tried this a few times sticking it right after the normalize statements. I don't know what I was thinking by doing that. Thanks for the help!
Answer by Sospitas · Jul 14, 2014 at 08:42 PM
Your cameraFront and cameraRight variables are both of type Vector3. This means that they have values for all 3 axes. If you do not want to take in the Y-value for applying force, before you get to your if-statements, zero out the Y-value of both cameraFront and cameraRight e.g.
cameraFront.y = 0;
cameraRight.y = 0;
That might not work fully, I'm not too versed in Javascript; I am more used to C#, but it should enable you to work out the Javascript equivalent if it does not work :)
Answer by TheGameLearner · Sep 10, 2018 at 05:41 AM
Based on above suggestions, I have made a script for adding force based on another body's transform values. just sharing it here with comments and extra codes for some future souls help. using System.Collections; using System.Collections.Generic; using UnityEngine;
public class PlayerMovements : MonoBehaviour
{
//each step force
public float step=80;
//axis to move with
private float _horizAxes, _vertAxis;
//rigidbody of player to apply force
private Rigidbody _rb;
//direction transform for referral
public Transform dirTrans;
//to divide directional force across XZ plane
private Vector3 forwardDir, rightDir;
private void Start()
{
_rb = GetComponent<Rigidbody>();
}
private void Update()
{
//get axis horizontally and vertically
_horizAxes = Input.GetAxis("Horizontal");
_vertAxis = Input.GetAxis("Vertical");
//Add Force only when Axes are not zero, as Zero means player is stationary
if (!(_horizAxes == 0 && _vertAxis == 0))
{
/*
* Tried this way, but when camera looks with down angle, the player starts to fly for reverse
* planning to add new Vector3 references and force only across XZ plane
if(_horizAxes > 0 ){
_rb.AddForce(step * dirTrans.right * Time.deltaTime);
}
else if(_horizAxes < 0){
_rb.AddForce(step * -dirTrans.right * Time.deltaTime);
}
if (_vertAxis > 0){
_rb.AddForce(step * dirTrans.forward * Time.deltaTime);
}
else if (_vertAxis < 0){
_rb.AddForce(step * -dirTrans.forward * Time.deltaTime);
}
*/
forwardDir = dirTrans.forward;
forwardDir.y = 0;
rightDir = dirTrans.right;
rightDir.y = 0;
if (_horizAxes > 0)
{
_rb.AddForce(step * rightDir * Time.deltaTime);
}
else if (_horizAxes < 0)
{
_rb.AddForce(step * -rightDir * Time.deltaTime);
}
if (_vertAxis > 0)
{
_rb.AddForce(step * forwardDir * Time.deltaTime);
}
else if (_vertAxis < 0)
{
_rb.AddForce(step * -forwardDir * Time.deltaTime);
}
}
}
}