Rotating Game Object's Y axis relevant to Input.Acceleration.X

Hi, in my game when the user tilts their phone screen left or right I would like the game object to rotate its y axis left or right depending on the acceleration. The game object is constantly moving forward so to turn I will just make it that the player tilts to rotate the object and it should hopefully turn it since it is always moving forwards. Preferably in C# if possible! Thanks :slight_smile:

Bump?

Check out the example code of using acceleration input;

Apply the input values from the orientation you’re interested in to the rotation of the target game object. You might need to smooth the input over a few frames, reorient the input to match your device/game/camera/object rotation, and/or apply multipliers to output the range or sensitivity you want.

You will probably need to be familiar with Vectors and maybe some Quaternions to get things working nicely. There are also good overviews in Apple’s iOS documentation and plenty of search results for obtaining and smoothing/low-pass filtering accelerometer data.

http://docs.unity3d.com/Manual/UnderstandingVectorArithmetic.html

If this sounds too tricky then you might want to work through learning a few more fundamentals about Unity (and general maths) from some tutorials, sites, or books. Otherwise, maybe take a look at non-code solutions like PlayMaker.

Uhh thanks I’m so confused so I’ll definitely need to look into that…

So I’ve fixed it, the object rotates relevant to the input on the acceleration.x but for some reason it also rotates randomly on the y and z acceleration. Why is this and how can I fix it? This is my current code -

public Quaternion target;
    public float yRotation;

    void Update () {

        if(Input.acceleration.x > 0.1f){
            yRotation = 90;
            target = Quaternion.Euler(0, yRotation, 0);
            transform.rotation = Quaternion.Slerp(transform.rotation, target, Time.deltaTime);
        }

        if(Input.acceleration.x > -0.1f){
            yRotation = -90;
            target = Quaternion.Euler(0, yRotation, 0);
            transform.rotation = Quaternion.Slerp(transform.rotation, target, Time.deltaTime);
        }

        transform.up = -(Input.acceleration.normalized);


        player.transform.Translate(Vector3.forward * Time.deltaTime * speed);

}

*EDIT
What I mean is when I hold the phone flat in my palm so the screen is facing up I have to tilt the z axis to rotate what should be the x axis - I have to bring the left side of the screen up and push down the right side is what I mean or vice versa. Otherwise if I hold the phone upright then the rotation is so messed up you can’t even see anything properly. It seems to me like the game is also picking up the y and z rotations too and I don’t know how to fix it?

You might want to check a few things;
The comparison for negative acceleration.x probably needs to be “Input.acceleration.x < -0.1f”.
What happens if Input.acceleration is very close to 0,0,0?

You could look at Unity - Scripting API: Quaternion.SetLookRotation to combine your rotation with the up hint/direction, depending on your intentions. Your initial post only suggested that you wanted to rotate the object around the Y axis (ie. moving on a ground plane turning left/right).

All I want it to do is you can see that the player moves forward on their own, when the screen is tilted left I want the player to rotate however much the screen is tilted and opposite for right which I assume will make the player continue to move in the rotated direction since it is always moving forward? But I honestly don’t understand what I’m doing here.

If the code is yours then you’re well on your way to getting something going. If it’s copy-paste then you need to learn what’s going on and fix/change it to suit your needs.

To answer one question, your object is rotating freely because of this line;

transform.up = -(Input.acceleration.normalized);

You’re rotating your object so that its upwards direction is pointing in the negative accelerometer direction, which is going to be some arbitrary rotation based on your device orientation and movement that you’re using directly without clamping or filtering. Try commenting out that line and seeing how your object reacts.

It’s not copy paste, I wrote it but over several hours and with great difficulty!

Great :slight_smile: Comment out that line and you should see the rotation behaviour change a lot. Also, I recommend the use of Debug.DrawRay and Debug.DrawLine to help with debugging your thinking.

Thanks! I’ve just commented out that line and I’m testing it now. It now just rotates around sideways instead of vertically…

If that’s what you intend it to do, then great. If not, then double-check what coordinate system Unity uses (left-handed, Y is up) and then determine what axis you want to apply your acceleration input to. Looking down an axis towards its origin, positive rotations are clockwise.

Is there not a way where you can just lock the y and z rotations of the player?

Sure, don’t apply rotations around those axes or clamp them when they might happen. Without a screenshot explaining your intentions, you might be confusing the axes.

Try changing the rotations;

target = Quaternion.Euler(0f, 0f, yourRotationAngle); // rotate around z axis (ie. 'roll' around the axis looking into screen)

Ok this is basically what I want to happen in my game:

The player is a ball right, when the phone is held in any position in the players hands and they tilt the side of their screen left or right like a racing game would or something; the ball will rotate left or right depending on how much the screen is tilted and in which direction. Since the ball is always moving forward and the user cannot control this, I assume that when the ball is rotated right it will start moving right because that will now be forwards to it.

Check our private thread about coordinate systems. You’ll need to be mindful of how you’re applying your movement and rotations.

You could do it all with a single, top-level transform, or you might want to approach your problem using nested gameobjects and separate some of your translation and rotation logic, ie. a parent moves around on the ground plane but only rotates around its Y and always moves in its forward direction, and a nested object rotates a ball mesh around its X axis to simulate moving forward.

How could I do it all with a single, top-level transform??? That sounds like the better option for my game.

Try breaking down your problem by nesting your gameobjects. Make the top level one only rotate around the Y axis depending on the acceleration input, similar to how you’re rotating it now. Then, translate it in its forward direction by your speed * deltatime. The ball won’t roll around yet, just spin.

When that works how you want, then add a script to your nested game object (one with a ball mesh). In an update method, apply a rotation around the local x axis to roll the ball forward/back in its local space (not in world space, the parent is taking care of that). Combined, these should work to create a rolling ball effect.

After you can see how the input is working to control basic movement and rotation, you can try making a single-transform rig with some different translation and rotation code. Check the Transform commands for the relativeTo Space which will help apply them correctly, or supply an axis in the Transform.RotateAround command.

Hey just letting everyone know that I’ve fixed it, here’s the full code!

using UnityEngine;
using System.Collections;

public class Ball_Rolling : MonoBehaviour {

    public float speed = 2.0F;
    public float rotSpeed = 20F;
    public GameObject player;
    public GameObject camera;

    public Quaternion target;
    public float yRotation;

    void Update () {

        Vector3 dir = Vector3.zero;

        dir.y = Input.acceleration.x;
       
        if (dir.sqrMagnitude > 1)
            dir.Normalize();
       
        dir *= Time.deltaTime;
        transform.Rotate(dir * rotSpeed);

        player.transform.Translate(Vector3.forward * Time.deltaTime * speed);

        speed += 0.0001F;


}

}
2 Likes

No worries. It’s great that it’s all working for you :slight_smile:

Here’s a few things you might want to consider for next time…

This might not be doing what you expect all the time. You’re getting a normalised direction using the input only if the sqrMagnitude is greater than one. You could do some calculations based just on Input.acceleration.x or adjust the comparison to normalise if its length is non-zero.

// might not do what you expect
if (dir.sqrMagnitude > 1)
     dir.Normalize();

// perhaps normalise the direction if it's non-zero (you could test using the sqrMagnitude here too)
if (!Mathf.Approximately(dir.magnitude, 0f))
     dir.Normalize();

// or just use the Input.acceleration.x value to set up the direction vector, then no normalisation is required
if (Input.acceleration.x > 0f)
     dir.y = 1f;
else if (Input.acceleration.x < 0f)
     dir.y = -1f;

Also, your speed will increase forever - no limits. If this is what you want then great. Also, note that you’re increasing it a fixed amount per frame rather than by some acceleration based on deltaTime.

// speed up a bit based on deltaTime (still not based in real physics, though)
speed += accelerationPerSecond * Time.deltaTime;