How to get MouseLook to stay strictly in either X or Y planes

Hi, it’s been a while since I posted here. Can’t figure out how to indicate code or link, so it’s all in the same font. Sorry.

I am trying to modify the MouseLook script to force the mouse motion to stay strictly in the X or Y planes rather than be able to tilt. Here’s my code:

if (Input.GetAxis(“Mouse X”)){
transform.Rotate(0, Input.GetAxis(“Mouse X”) * sensitivityX, 0);
}
if (Input.GetAxis (“Mouse Y”)){
transform.Rotate(-Input.GetAxis(“Mouse Y”) * sensitivityY, 0, 0);
}

Of course this doesn’t work because Input.GetAxis returns a float and I need a boolean value. Is there any way to address Input.GetAxis to find out whether it is using Mouse X or Mouse Y at any given moment. Thanks.

Zaffer

Cross posted this to Unity Answers at http://answers.unity3d.com/questions/769415/how-to-get-mouselook-to-stay-strictly-in-either-x.html – no answer

Setting the Axes property in the inspector to only one axis is not what you want?

Thanks Fraconte,

I’m making a color cube (3D depiction of the RGB color space) that you can go into and move around in like a room. This works well if the MouseLook axis is set to either MouseX or MouseY, but if it is set to MouseXAndY, the view tilts which is not what I want. I’m trying to figure out a way to have the view move strictly as either in MouseX or MouseY but not tilt (see attached image). That’s why I’m trying to figure out how to access Input.GetAxis and have it tell me whether the mouse is moving in X or Y at any given moment so I can constrain the motion to only X or Y axes. If you or anyone has any idea on how to do this, I’d very much appreciate it. Thanks.

EDIT: I totally missed your second post. I see the problem now.

float rotX;
float rotY;

void Update()
{
    rotX += Input.GetAxis("Mouse X");
    rotY = Mathf.Clamp(rotY - Input.GetAxis("Mouse Y"), -85.0f, 85.0f);

    transform.localEulerAngles = new Vector3(rotY, rotX, 0.0f);
}

I didn’t test this, so let me know if it works.

Hi Cranky,
Thanks for your code. Unfortunately, I can’t use “transform.localEulerAngles” because if I do it makes the MouseLook view change in unexpected ways that I don’t want. See this post: character controller rotation won't accept script values - Questions & Answers - Unity Discussions.

So I adapted your approach to using “transform.Rotate” which sort of works. It will keep the mouse traveling in either X or Y direction but it’s still easy to get things tilted because if the mouse is tilted when it starts rotating, of course, it will stay tilted. If only I could make the character controller/camera just stay upright all the time! Here’s my code. Any suggestions will be appreciated.

By the way, how did you get your code into a code box. I can’t find a button for that. Thanks.

if(Input.GetAxis(“Mouse X”) > 0){

rotY = Mathf.Clamp((rotY - Input.GetAxis(“Mouse Y”)), -85.0f, 85.0f);
transform.Rotate(0, Input.GetAxis(“Mouse X”) * sensitivityX, 0);
Debug.Log (“Mouse X”);
}

if(-Input.GetAxis(“Mouse Y”) < 0){

rotX = Mathf.Clamp(-85.0f, (rotX - Input.GetAxis (“Mouse X”)), 85.0f);
transform.Rotate(-Input.GetAxis(“Mouse Y”) * sensitivityY, 0, 0);
Debug.Log (“Mouse Y”);
}

else if(Input.GetAxis (“Mouse X”) == 0 && (-Input.GetAxis (“Mouse Y”) == 0)){
Debug.Log(“no movement”);
}

I tryed a box (of 6 planes) with one camera inside: if i attach the mouselook script to the box i get the tilt you say, but if i attach the script to the camera it works ok.

Are you moving the box? And why not the camera?

Edit: for the code box use the “Insert…” button (near the films icon button)

If your problem with localEulerAngles is the same as the one in the link, simply use my old code and add this:

void Awake()
{
    rotX = transform.localEulerAngles.y;
    rotY = transform.localEulerAngles.x;
}

If this is not the only problem you have with localEulerAngles, what else? Just curious, as I use localEulerAngles for my camera and I’m interested in knowing if there’s any problems with it I’m unaware of.

Moving the box on the mouse X axis (object Y axis) is good because then it sets transform.forward to the box’s forward vector and you can simply multiply transform.forward and transform.right by movement speed to get a movement vector.

In my FPS, I use a weird, hacky solution. I have my camera GameObject as a child of the player GameObject. My MouseLook script adjusts the mouse X (object Y) rotation of the PARENT (which in turn also rotates the camera), while the mouse Y (object X) rotates the camera. This is so my player objects is always upright, but also enables looking up and down.

With “box” I mean the room where the character controller is walking into. The camera setup you are talking about I think is the same of the standard 1st person character controller that works fine too in the room with no “tilting”.
So or Zaffer is moving the room or have a modified setup of the character controller that generates “tilt”.

HI Fraconte,

I am using my own scripts for Character Controller and MouseLook, but I tried the default ones and got the same result, lots of tilting. I don’t know how you got your results of no tilting.

I posted a build of my cube at http://www.bitsong.com/forPosting/Unity/Color%20Cube_Build.html/Color%20Cube_Build.html
For this build I used my original code with the tilt problem – a very stripped down version of the MouseLook script:

using UnityEngine;
using System.Collections;

[AddComponentMenu("Camera-Control/Mouse Look")]
public class MouseLook_bp1 : MonoBehaviour {

    public enum RotationAxes { MouseXAndY = 0, MouseX = 1, MouseY = 2 }
    public RotationAxes axes = RotationAxes.MouseXAndY;
    public float sensitivityX = 10F;
    public float sensitivityY = 10F;

       
    void Update ()
    {

        if (axes == RotationAxes.MouseXAndY)
        {
   
            transform.Rotate(-Input.GetAxis("Mouse Y") * sensitivityY, Input.GetAxis("Mouse X") * sensitivityX, 0);
        }

        else if (axes == RotationAxes.MouseX)
        {
            transform.Rotate(0, Input.GetAxis("Mouse X") * sensitivityX, 0);

        }
        else
        {
            transform.Rotate(-Input.GetAxis("Mouse Y") * sensitivityY, 0, 0);

        }
    }

}

Hi Cranky,

Thanks Cranky, I will try this and let you know if it works – sound like it might.

My other problem with localEulerAngles is that I am also planning to have a feature where the user can input two colors, like 204 153 153 and 0 0 0 by clicking on a palette of the 216 “Web Safe” colors which are the spheres in my model. The controller/camera will then snap to line up those two colors so the user can “surf” from one color to the other. You can see how this works by typing the “t” key in my running build at http://www.bitsong.com/forPosting/Unity/Color%20Cube_Build.html/Color%20Cube_Build.html

Here is the code for my FPSWalker script with the snapping code included at the bottom. It’s a very simplified controller script.

#pragma strict

var speed = 8.0;
private var moveDirection = Vector3.zero;

function FixedUpdate () {
        moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
        moveDirection = transform.TransformDirection(moveDirection);
        moveDirection *= speed;
                   
        if(Input.GetButton("Test")){
            PlaceFPC();
        }
       
    var controller : CharacterController = GetComponent(CharacterController);
    var flags = controller.Move(moveDirection * Time.deltaTime);
}

function PlaceFPC (){
    var obj2 = GameObject.Find ("204 153 153");
    var obj1 = GameObject.Find ("0 0 0");
   
    var dir : Vector3 = obj1.transform.position - obj2.transform.position;
    Debug.Log ("dir: " + dir);
   
    var midPoint : Vector3 = obj2.transform.position + dir / 2.0;
    var endPoint : Vector3 = obj2.transform.position;
    this.transform.position = endPoint;
   
    var rot : Quaternion = Quaternion.LookRotation(dir);
    this.transform.rotation = rot;
    Debug.Log ("rot: " + rot); 

}
@script RequireComponent(CharacterController)

This feature doesn’t work at all if I use the localEulerAngles code. Only works with the transform.Rotate code. I’m sorry, I’m not much of a coder and I haven’t stopped to figure out why this should be so, just went with what worked.

As for moving the box or cube, I also will have a feature that will rotate the box in three directions – haven’t decided whether to use buttons or keys yet. I want to have a lot of different kinds of user input, but don’t want it to be too complicated. That’s why I’m trying to get the mouse to do what I want, so I don’t have to add a keystroke to make the mouse move in either X or Y, though maybe I will have to do that.

Thanks for all you help and suggestions. If you have any more after trying out my actual color cube, please let know.

In the previous code examples I gave you, replace localEulerAngles with eulerAngles. Does that solve the issue?

Hi Cranky,

The eulerAngles did remove the problem of my “snapping” script not working. Thanks! But unfortunately, it works like the example I tried above, of using Mathf.clamp with transform.Rotate. It will keep the mouse traveling in either X or Y direction but it’s still easy to get things tilted because if the mouse is tilted when it starts rotating it will stay tilted.

Isn’t the camera object normally a child of the controller object?

How did you do this? Did you attach a MouseLook script to both the controller and the camera with one set to X Axis and one set to Y axis? That didn’t work for me. Thanks.

Odd, I’m not having the tilting problem. I created a brand new project and used this code:

using UnityEngine;

public class MouseLookTest : MonoBehaviour
{
    public float Sensitivity = 2.0f;
    public float MoveSpeed = 0.2f;

    private float rotX;
    private float rotY;

    private new Transform transform;

    void Awake()
    {
        transform = base.transform;

        rotX = transform.eulerAngles.y;
        rotY = transform.eulerAngles.z;
    }

    void Update()
    {
        rotX += Input.GetAxis("Mouse X") * Sensitivity;
        rotY -= Input.GetAxis("Mouse Y") * Sensitivity;

        transform.eulerAngles = new Vector3(rotY, rotX, 0.0f);

        transform.Translate((Input.GetAxis("Horizontal") * MoveSpeed) * Vector3.right + (Input.GetAxis("Vertical") * MoveSpeed) * Vector3.forward);
    }
}

Do you intend to implement Player collision? Because if not, a Character Controller like that isn’t necessary. The code like I wrote above could easily cover movement. But if you intend to add collision, then perhaps a Character Controller is in your best interest.

Please note that you should disable your Character Controller component while testing this script, since it takes care of movement for you. You only need a single object with a camera attached for this script.

Sorry if this is confusing :S

Nope, I used one component and attached it to the camera and made the camera a child of the player GameObject. Here is what I did:

float dx = Input.GetAxis("Mouse X");
float dy = Input.GetAxis("Mouse Y");

Vector3 rotation = parent.localEulerAngles;
rotation.y += dx;
parent.localEulerAngles = rotation;

rotationY = Mathf.Clamp(rotationY + dy, MinY, MaxY);

rotation = transform.localEulerAngles;
rotation.x = rotationY;
transform.localEulerAngles = rotation;
1 Like

Hi Cranky, You’re a genius! Your MouseLookTest script works. There is still some tilting, but it’s controllable. I can use the mouse to straighten the image and get back to level. Whereas before, the scene would just spin out of control. I think my problem was that I didn’t realize you didn’t really need a controller script, that the MouseLook script alone would let you use the arrow keys to move. I had no idea. No, I don’t need any type of collision, the only thing I will need to do is get my “snapping” code working with this new setup – shouldn’t be too difficult. Thanks so much!

Zaffer

Hi Franconte,

I think my problem was that I didn’t realize that I didn’t really need a character controller script at all – that the MouseLook script alone would move the object. Apparently the controller script was causing the tilt problem. With a modified MouseLook script using Mathf.clamp per Cranky’s code, I can get things working well. Sorry I didn’t realize your suggestion was a good one. Thanks.

Take a look at this too (if you want some smoothing): http://forum.unity3d.com/threads/smooth-mouse-look-modified-for-the-wiki.262068/

Thanks Franconte, I’ll give it a try sometime and let you know how it goes.

1 Like

Hi Cranky,

Famous last words… I added my code for “snapping” – positioning the camera along a line determined by two of the color spheres it only “sort of” works. When I play the scene and press the “t” key (input for this), the camera goes to the correct position and rotation, but when I release the “t” key, the camera stays in its new position but returns to its last rotation before the “t” key was pressed – either the starting rotation or the last rotation determined by the user rotating the mouse (see attached). If you or anybody has a suggestion on how to fix this, I would greatly appreciate it. Thanks.

void Update()
    {       
        rotX += Input.GetAxis("Mouse X") * Sensitivity;
        rotY -= Input.GetAxis("Mouse Y") * Sensitivity;

        transform.eulerAngles = new Vector3(rotY, rotX, 0.0f);

        transform.Translate((Input.GetAxis("Horizontal") * MoveSpeed) * Vector3.right + (Input.GetAxis("Vertical") * MoveSpeed) * Vector3.forward);

        if(Input.GetButton("Test")){
            PlaceCamera();
        }
    }

    void PlaceCamera()
    {
        obj1 = GameObject.Find ("255 255 255"); //first color sphere
        obj2 = GameObject.Find ("0 0 0");        //second color sphere

        Vector3 startPoint = new Vector3(0, 0, 0);
        startPoint = obj1.transform.position;
        this.transform.position = startPoint;

        Vector3 direction = new Vector3(0, 0, 0);
        direction = obj2.transform.position - obj1.transform.position;                           
        Quaternion rot = Quaternion.LookRotation(direction);
        this.transform.rotation = rot;
    }

I lost my mind trying to understand why transform.eulerAngles reset the rotation. I also tryed to save and restoring old euler… I don’t know why but it doesn’t works.
The good news is I have an easy fix for this:

        //rotX = Input.GetAxis("Mouse X") * Sensitivity;
        //rotY = -Input.GetAxis("Mouse Y") * Sensitivity;

        //transform.eulerAngles = new Vector3(rotY, rotX, 0.0f);

Now for the rotation just add another script: the standard MouseLook.cs or the SmoothMouseLook.cs I told you above (or any other MouseLook you want…). :slight_smile:

This is because the MouseLook script is setting the transform’s rotation to its own internal rotation value internally. The good news is this can be remedied pretty easily :).

Add this to the end of your PlaceCamera() method:

rotX = transform.eulerAngles.y;
rotY = transform.eulerAngles.x

Let me know how it goes!

1 Like