x


Camera rotation around a single axis - following a rolling ball

I'm sure this is very simple, there's just one line I can't quite work out! I have an empty object at the centre of a controllable ball. The camera is a child of this empty object. This object needs to stay with the ball, and only rotate around the y axis, so that the camera swings round when you turn the ball. So far I have only managed to get as far as having the camera follow the ball with no inherited rotation whatsoever. I just can't find a way to split the ball's rotational Quaternion into a Vector3 and then carry that Vector3's y value to a new Vector3 to be converted back into a Quaternion for the camera's parent.

Here's what I've got so far - this script is attached to the empty gameobject at the centre of the ball:

using UnityEngine;
using System.Collections;

public class CameraScript : MonoBehaviour 
{
    public Transform ballObject;

    void Update() 
    {
        transform.position = ballObject.transform.position;
        transform.rotation = Quaternion.Euler(0, ballObject.transform.rotation.y, 0);
    }
}

There are no compiler errors, yet it just doesn't do anything! I'm currently getting used to C# after using JS for all my previous Unity projects, so I'm assuming there's just something I've missed!

more ▼

asked Jul 09 '11 at 10:55 AM

Rob 6 gravatar image

Rob 6
83 6 6 11

(comments are locked)
10|3000 characters needed characters left

3 answers: sort voted first

I've created a slightly more workable solution, merging the movement and camera scripts together. Now, the "ball centre" object that the camera is attached to controls turning, while forward and backwards controls apply a force on the ball in the direction that the camera is facing.

using UnityEngine;
using System.Collections;

public class CameraScript : MonoBehaviour 
{
    public Transform ballObject, ballCamera;
    public float speed, turnSpeed;
    Vector3 forceDirection;

    void FixedUpdate() 
    {
        transform.position = ballObject.position;
        if(Input.GetAxis("Vertical") != 0)
        {
            RollBall();
        }
        //calculate ball turning
        transform.Rotate((Vector3.up * Input.GetAxis("Horizontal") * turnSpeed), Space.World);
    }

    void RollBall()
    {
        //set force down camera's look direction
        forceDirection = ballCamera.transform.forward;

        //remove y force direction for angled camera
        forceDirection = new Vector3(forceDirection.x, 0, forceDirection.z);

        //add force to ball
        ballObject.rigidbody.AddForce(forceDirection.normalized * speed * (Input.GetAxis("Vertical")));
    }
}

The result is that the movement can be considered in a way that is independent of the rotation of the ball - so it's more of a work-around than a solution, but there didn't seem to be a graceful way to clone a rotation value across via a Vector3.

more ▼

answered Jul 10 '11 at 02:33 PM

Rob 6 gravatar image

Rob 6
83 6 6 11

(comments are locked)
10|3000 characters needed characters left

If what you want is just to keep the camera facing always the direction of movement, you must calculate its direction based on the last position. To avoid inaccuracies produced by very small displacements, you can set a minimum distance to refresh the view direction (adjust the distance variable in the Inspector if needed):

using UnityEngine;
using System.Collections;

public class CameraScript : MonoBehaviour 
{
    public Transform ballObject;    
    public float distance = 0.1f; // min distance to refresh view direction

    Vector3 lastPos;
    Vector3 viewDir;

    void Start(){
        // ensure forward direction at start
       lastPos = ballObject.transform.position - transform.forward * distance; 
    }   

    void Update() 
    {
       Vector3 ballPos = ballObject.transform.position;
       Vector3 newDir = ballPos - lastPos;  // direction from last position
       newDir.y = 0; // keep the camera on horizontal plane
       if (newDir.magnitude>distance){  // only recalculate after min distance
         viewDir = newDir;
         lastPos = ballPos;
       }
        transform.position = ballPos;
       transform.forward = Vector3.Slerp(transform.forward, viewDir.normalized, Time.deltaTime);
    }
}
more ▼

answered Jul 10 '11 at 02:13 PM

aldonaletto gravatar image

aldonaletto
41.4k 16 42 197

(comments are locked)
10|3000 characters needed characters left

Try this:

using UnityEngine; using System.Collections;

public class CameraScript : MonoBehaviour { public Transform ballObject;

void Update() 
{
    transform.position = ballObject.position;
    transform.rotation.eulerAngles = new Vector3(0, ballObject.transform.rotation.y, 0);
}

}

You don't need to add the .transform after ballObject because it is a transform.

more ▼

answered Jul 09 '11 at 11:17 AM

Ludiares gravatar image

Ludiares
210 2 3

Thanks, but that line causes it to throw an error:

"error CS1612: Cannot modify a value type return value of `UnityEngine.Transform.rotation'. Consider storing the value in a temporary variable"

Jul 10 '11 at 09:51 AM Rob 6

What exactly are you trying to do? Make the camera face always the direction of movement?

Jul 10 '11 at 01:42 PM aldonaletto
(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x2996
x2163
x322
x33

asked: Jul 09 '11 at 10:55 AM

Seen: 1682 times

Last Updated: Jul 10 '11 at 02:33 PM