Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

(Solved) What's Wrong With My Camera Rotation? (RTS-Style Camera)

Discussion in 'Scripting' started by EternalAmbiguity, Aug 23, 2017.

  1. EternalAmbiguity

    EternalAmbiguity

    Joined:
    Dec 27, 2014
    Posts:
    3,144
    I'm trying to make a simple camera in the same format as the editor camera - where you right-click to rotate, and move freely (relative to your facing direction) with WASD. I haven't been able to find this in the standard assets at all.

    The camera and movement are working. However the movement is very jerky. Now, I can attempt to fix this with a Lerp. But for some reason this causes the camera to spin around rapidly. I can set the Lerp parameter t lower, but it still does the spinning and is too slow.

    See attached script. You can create a new project, create an empty GameObject, set the main Camera as its child (zero the transforms and rotations), and then attach the script. Should work and show the problem. Create a Terrain or something to have something to see it by.

    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityStandardAssets.CrossPlatformInput;
    5. using UnityStandardAssets.Utility;
    6. public class CameraControl : MonoBehaviour
    7. {
    8.     public float XSensitivity = 10f;
    9.     public float YSensitivity = 10f;
    10.     public float movementSpeed = 1f;
    11.     public float MinimumX = -90F;
    12.     public float MaximumX = 90F;
    13.     public bool smooth;
    14.     public float smoothTime = 5f;
    15.     private Camera camera;
    16.     private Quaternion cameraRot;
    17.     private Vector3 euler;
    18.     GameObject parent;
    19.     // Use this for initialization
    20.     void Start () {
    21.         parent = this.transform.parent.gameObject;
    22.         camera = Camera.main;
    23.         Init();
    24.     }
    25.  
    26.  // Update is called once per frame
    27.  void Update () {
    28.  
    29.     }
    30.     public void Init()
    31.     {
    32.         cameraRot = camera.transform.localRotation;
    33.     }
    34.     private void FixedUpdate()
    35.     {
    36.         if (Input.GetKey(KeyCode.W))
    37.         {
    38.            
    39.             parent.transform.position = new Vector3(parent.transform.position.x + (parent.transform.forward.x * movementSpeed), parent.transform.position.y + (parent.transform.forward.y * movementSpeed), parent.transform.position.z + (parent.transform.forward.z * movementSpeed));
    40.         }
    41.         if (Input.GetKey(KeyCode.S))
    42.         {
    43.             parent.transform.position = new Vector3(parent.transform.position.x - (parent.transform.forward.x * movementSpeed), parent.transform.position.y - (parent.transform.forward.y * movementSpeed), parent.transform.position.z - (parent.transform.forward.z * movementSpeed));
    44.         }
    45.         if (Input.GetKey(KeyCode.A))
    46.         {
    47.             parent.transform.position = new Vector3(parent.transform.position.x - (parent.transform.right.x * movementSpeed), parent.transform.position.y - (parent.transform.right.y * movementSpeed), parent.transform.position.z - (parent.transform.right.z * movementSpeed));
    48.         }
    49.         if (Input.GetKey(KeyCode.D))
    50.         {
    51.             parent.transform.position = new Vector3(parent.transform.position.x + (parent.transform.right.x * movementSpeed), parent.transform.position.y + (parent.transform.right.y * movementSpeed), parent.transform.position.z + (parent.transform.right.z * movementSpeed));
    52.         }
    53.         if(Input.GetMouseButton(1))
    54.         {
    55.             RotateView();
    56.         }
    57.     }
    58.     private void RotateView()
    59.     {
    60.         float yRot = CrossPlatformInputManager.GetAxis("Mouse X") * XSensitivity;
    61.         float xRot = CrossPlatformInputManager.GetAxis("Mouse Y") * YSensitivity;
    62.         euler.y += yRot;
    63.         cameraRot *= Quaternion.Euler(-xRot, 0, 0);
    64.         if (smooth == true)
    65.         {
    66.             parent.transform.eulerAngles = Vector3.Lerp(parent.transform.eulerAngles, euler, 0.03f);
    67.             camera.transform.localRotation = Quaternion.Lerp(camera.transform.localRotation, cameraRot, 0.03f);
    68.         }
    69.         else
    70.         {
    71.             parent.transform.eulerAngles = euler;
    72.             camera.transform.localRotation = cameraRot;
    73.         }
    74.     }
    75. }
    Any tips?
     
    Last edited: Aug 23, 2017
  2. chelnok

    chelnok

    Joined:
    Jul 2, 2012
    Posts:
    680
    I believe camera movement should be in LateUpdate()

    Couldn't you just add if(Input.GetMouseButton(1)) to mouseLook script (or similar, haven't used standard assets for a while)
     
  3. jexmatex

    jexmatex

    Joined:
    Jun 23, 2016
    Posts:
    47
    try this

    void Update()
    {
    if (Input.GetMouseButton(1))
    {
    rotationX += Input.GetAxis("Mouse X") * Time.deltaTime;
    rotationY += Input.GetAxis("Mouse Y") * Time.deltaTime;
    // rotationY = Mathf.Clamp(rotationY, -90, 90);

    transform.localRotation = Quaternion.AngleAxis(rotationX, Vector3.up);
    transform.localRotation *= Quaternion.AngleAxis(rotationY, Vector3.left);
    // transform.localRotation *= Quaternion.AngleAxis(rotationZ, Vector3.back);
    }
    }
     
  4. jexmatex

    jexmatex

    Joined:
    Jun 23, 2016
    Posts:
    47
    Try this in void Update

    Code (csharp):
    1.  
    2.  
    3. if (Input.GetMouseButton(1))
    4.         {
    5.             rotationX += Input.GetAxis("Mouse X")  * Time.deltaTime;
    6.             rotationY += Input.GetAxis("Mouse Y") * Time.deltaTime;
    7.             // rotationY = Mathf.Clamp(rotationY, -90, 90);
    8.  
    9.             transform.localRotation = Quaternion.AngleAxis(rotationX, Vector3.up);
    10.             transform.localRotation *= Quaternion.AngleAxis(rotationY, Vector3.left);
    11.             //     transform.localRotation *= Quaternion.AngleAxis(rotationZ, Vector3.back);
    12.         }
    13. else
    14.         {
    15.             transform.position += transform.forward * Input.GetAxis("Vertical") * Time.deltaTime;
    16.             transform.position += transform.right * Input.GetAxis("Horizontal") * Time.deltaTime;
    17.         }
    18.    
    19.  
    20.  
     
  5. chelnok

    chelnok

    Joined:
    Jul 2, 2012
    Posts:
    680
    @jexmatex until your code, i didn't even notice OP wasn't using deltatime. Perhaps thats why he's using FixedUpdate(), but even that your code use deltatime, shouldn't this (camera movement) be handled in LateUpdate()?
     
  6. EternalAmbiguity

    EternalAmbiguity

    Joined:
    Dec 27, 2014
    Posts:
    3,144
    Thanks for the tips, I will try them and post if they work or not.
     
  7. EternalAmbiguity

    EternalAmbiguity

    Joined:
    Dec 27, 2014
    Posts:
    3,144
    I tried this. Commented out all of FixedUpdate. It works, but unfortunately when one moves the camera with WASD it changes the height, which did not happen in my previous script.

    I switched to my movement part in FixedUpdate, commenting out the else statement above, and then changed it to transform the camera instead of the parent. It does the same thing as with the else statement (changing height). But if I change it back to transform the parent, and then change the X rotation in the above, it kind of works, but unfortunately moving at all in the Y direction causes the camera to start moving, so if you release the button then press it again, it maintains the motion.

    I'm going to try removing all this and adding MouseLook.
     
  8. EternalAmbiguity

    EternalAmbiguity

    Joined:
    Dec 27, 2014
    Posts:
    3,144
    So I probably could have gotten it working with the previous suggestion, but it was just too much fiddly stuff I don't have a whole bunch of experience with. I've added a SimpleMouseRotator to the Camera and gotten rid of the cube completely. I put a modified version of my WASD movement in. It doesn't have zooming (based on mouse wheel scroll) yet, I plan to add that, but here it is if anyone's interested.

    Code (csharp):
    1. using System;
    2. using UnityEngine;
    3. using UnityStandardAssets.CrossPlatformInput;
    4. namespace UnityStandardAssets.Utility
    5. {
    6.     public class SimpleMouseRotator : MonoBehaviour
    7.     {
    8.         // A mouselook behaviour with constraints which operate relative to
    9.         // this gameobject's initial rotation.
    10.         // Only rotates around local X and Y.
    11.         // Works in local coordinates, so if this object is parented
    12.         // to another moving gameobject, its local constraints will
    13.         // operate correctly
    14.         // (Think: looking out the side window of a car, or a gun turret
    15.         // on a moving spaceship with a limited angular range)
    16.         // to have no constraints on an axis, set the rotationRange to 360 or greater.
    17.         public Vector2 rotationRange = new Vector3(90, 361);
    18.         public float rotationSpeed = 10;
    19.         public float dampingTime = 0.2f;
    20.         public bool autoZeroVerticalOnMobile = true;
    21.         public bool autoZeroHorizontalOnMobile = false;
    22.         public bool relative = true;
    23.        
    24.        
    25.         private Vector3 m_TargetAngles;
    26.         private Vector3 m_FollowAngles;
    27.         private Vector3 m_FollowVelocity;
    28.         private Quaternion m_OriginalRotation;
    29.         public float movementSpeed = 30f;
    30.         private void Start()
    31.         {
    32.             m_OriginalRotation = transform.localRotation;
    33.         }
    34.  
    35.         private void Update()
    36.         {
    37.             if (Input.GetMouseButton(1))
    38.             {
    39.                 Cursor.lockState = CursorLockMode.Locked;
    40.                 Cursor.visible = false;
    41.                 // we make initial calculations from the original local rotation
    42.                 transform.localRotation = m_OriginalRotation;
    43.                 // read input from mouse or mobile controls
    44.                 float inputH;
    45.                 float inputV;
    46.                 if (relative)
    47.                 {
    48.                     inputH = CrossPlatformInputManager.GetAxis("Mouse X");
    49.                     inputV = CrossPlatformInputManager.GetAxis("Mouse Y");
    50.                     // wrap values to avoid springing quickly the wrong way from positive to negative
    51.                     if (m_TargetAngles.y > 180)
    52.                     {
    53.                         m_TargetAngles.y -= 360;
    54.                         m_FollowAngles.y -= 360;
    55.                     }
    56.                     if (m_TargetAngles.x > 180)
    57.                     {
    58.                         m_TargetAngles.x -= 360;
    59.                         m_FollowAngles.x -= 360;
    60.                     }
    61.                     if (m_TargetAngles.y < -180)
    62.                     {
    63.                         m_TargetAngles.y += 360;
    64.                         m_FollowAngles.y += 360;
    65.                     }
    66.                     if (m_TargetAngles.x < -180)
    67.                     {
    68.                         m_TargetAngles.x += 360;
    69.                         m_FollowAngles.x += 360;
    70.                     }
    71. #if MOBILE_INPUT
    72.             // on mobile, sometimes we want input mapped directly to tilt value,
    73.             // so it springs back automatically when the look input is released.
    74.    if (autoZeroHorizontalOnMobile) {
    75.     m_TargetAngles.y = Mathf.Lerp (-rotationRange.y * 0.5f, rotationRange.y * 0.5f, inputH * .5f + .5f);
    76.    } else {
    77.     m_TargetAngles.y += inputH * rotationSpeed;
    78.    }
    79.    if (autoZeroVerticalOnMobile) {
    80.     m_TargetAngles.x = Mathf.Lerp (-rotationRange.x * 0.5f, rotationRange.x * 0.5f, inputV * .5f + .5f);
    81.    } else {
    82.     m_TargetAngles.x += inputV * rotationSpeed;
    83.    }
    84. #else
    85.                     // with mouse input, we have direct control with no springback required.
    86.                     m_TargetAngles.y += inputH * rotationSpeed;
    87.                     m_TargetAngles.x += inputV * rotationSpeed;
    88. #endif
    89.                     // clamp values to allowed range
    90.                     m_TargetAngles.y = Mathf.Clamp(m_TargetAngles.y, -rotationRange.y * 0.5f, rotationRange.y * 0.5f);
    91.                     //Consider changing negative to greater ratio and positive to lower ratio. Why should players look into the sky?
    92.                     m_TargetAngles.x = Mathf.Clamp(m_TargetAngles.x, -rotationRange.x * 0.5f, rotationRange.x * 0.5f);
    93.                 }
    94.                 else
    95.                 {
    96.                     inputH = Input.mousePosition.x;
    97.                     inputV = Input.mousePosition.y;
    98.                     // set values to allowed range
    99.                     m_TargetAngles.y = Mathf.Lerp(-rotationRange.y * 0.5f, rotationRange.y * 0.5f, inputH / Screen.width);
    100.                     m_TargetAngles.x = Mathf.Lerp(-rotationRange.x * 0.5f, rotationRange.x * 0.5f, inputV / Screen.height);
    101.                 }
    102.                 // smoothly interpolate current values to target angles
    103.                 m_FollowAngles = Vector3.SmoothDamp(m_FollowAngles, m_TargetAngles, ref m_FollowVelocity, dampingTime);
    104.                 // update the actual gameobject's rotation
    105.                 transform.localRotation = m_OriginalRotation * Quaternion.Euler(-m_FollowAngles.x, m_FollowAngles.y, 0);
    106.             }
    107.             else
    108.             {
    109.                 Cursor.lockState = CursorLockMode.None;
    110.                 Cursor.visible = true;
    111.             }
    112.             if (Input.GetKey(KeyCode.W))
    113.             {
    114.                 this.transform.position = new Vector3(this.transform.position.x + (this.transform.forward.x * movementSpeed * Time.deltaTime), this.transform.position.y, this.transform.position.z + (this.transform.forward.z * movementSpeed * Time.deltaTime));
    115.             }
    116.             if (Input.GetKey(KeyCode.S))
    117.             {
    118.                 this.transform.position = new Vector3(this.transform.position.x - (this.transform.forward.x * movementSpeed * Time.deltaTime), this.transform.position.y, this.transform.position.z - (this.transform.forward.z * movementSpeed * Time.deltaTime));
    119.             }
    120.             if (Input.GetKey(KeyCode.A))
    121.             {
    122.                 this.transform.position = new Vector3(this.transform.position.x - (this.transform.right.x * movementSpeed * Time.deltaTime), this.transform.position.y, this.transform.position.z - (this.transform.right.z * movementSpeed * Time.deltaTime));
    123.             }
    124.             if (Input.GetKey(KeyCode.D))
    125.             {
    126.                 this.transform.position = new Vector3(this.transform.position.x + (this.transform.right.x * movementSpeed * Time.deltaTime), this.transform.position.y, this.transform.position.z + (this.transform.right.z * movementSpeed * Time.deltaTime));
    127.             }
    128.         }
    129.     }
    130. }
    Thanks for all of the help, I appreciate it.