Search Unity

Camera Mouse Orbit + Collision Detection

Discussion in 'Scripting' started by Eziekieal, Jul 7, 2015.

  1. Eziekieal

    Eziekieal

    Joined:
    Mar 12, 2015
    Posts:
    28
    Hey guys.

    So right now I have two separate scripts that work just fine alone. But I'm having an issue combining them.

    First one is:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class CameraMouseOrbit : MonoBehaviour
    5. {
    6.  
    7.     public Transform Target;
    8.     public float Distance = 5.0f;
    9.     public float xSpeed = 250.0f;
    10.     public float ySpeed = 120.0f;
    11.     public float yMinLimit = -20.0f;
    12.     public float yMaxLimit = 80.0f;
    13.      
    14.     public float x;
    15.     public float y;
    16.      
    17.     void Awake()
    18.     {
    19.         Vector3 angles = transform.eulerAngles;
    20.         x = angles.x;
    21.         y = angles.y;
    22.  
    23.         if(GetComponent<Rigidbody>() != null)
    24.         {
    25.             GetComponent<Rigidbody>().freezeRotation = true;
    26.         }
    27.     }
    28.      
    29.     void LateUpdate()
    30.     {
    31.  
    32.         if(Target != null)
    33.         {
    34.             x += (float)(Input.GetAxis("Mouse X") * xSpeed * 0.02f);
    35.             y -= (float)(Input.GetAxis("Mouse Y") * ySpeed * 0.02f);
    36.  
    37.             y = ClampAngle(y, yMinLimit, yMaxLimit);
    38.  
    39.             Quaternion rotation = Quaternion.Euler(y, x, 0);
    40.             Vector3 position = rotation * (new Vector3(0.0f, 0.0f, -Distance)) + Target.position;
    41.  
    42.             transform.rotation = rotation;
    43.             transform.position = position;
    44.         }
    45.  
    46.     }
    47.      
    48.     private float ClampAngle(float angle, float min, float max)
    49.     {
    50.         if(angle < -360)
    51.         {
    52.             angle += 360;
    53.         }
    54.         if(angle > 360)
    55.         {
    56.             angle -= 360;
    57.         }
    58.         return Mathf.Clamp (angle, min, max);
    59.     }
    60. }
    And the second one is:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class CameraCollision : MonoBehaviour
    5. {
    6.     Transform playerTransform;
    7.     Quaternion targetLook;
    8.     Vector3 targetMove;
    9.     public float rayHitMoveInFront = 0.1f;
    10.     Vector3 targetMoveUse;
    11.     public float smoothLook = 0.5f;
    12.     public float smoothMove = 0.5f;
    13.     Vector3 smoothMoveV;
    14.     public float distFromPlayer = 5.0f;
    15.     public float heightFromPlayer = 2.0f;
    16.  
    17.     // Use this for initialization
    18.     void Start ()
    19.     {
    20.         playerTransform = GameObject.FindWithTag("Player").transform;
    21.  
    22.  
    23.     }
    24.  
    25.     // Update is called once per frame
    26.     void Update ()
    27.     {
    28.         targetMove = playerTransform.position + (playerTransform.rotation * new Vector3(0, heightFromPlayer, -distFromPlayer));
    29.      
    30.         RaycastHit hit;
    31.         if (Physics.Raycast(playerTransform.position, targetMove - playerTransform.position, out hit, Vector3.Distance(playerTransform.position, targetMove)))
    32.         {
    33.             targetMoveUse = Vector3.Lerp (hit.point, playerTransform.position, rayHitMoveInFront);
    34.         }
    35.         else
    36.         {
    37.             targetMoveUse = targetMove;
    38.         }
    39.  
    40.         transform.position = Vector3.SmoothDamp(transform.position, targetMoveUse, ref smoothMoveV, smoothMove);
    41.  
    42.     }
    43. }
    The first one is the basic mouse orbit script. The second one zooms the camera in if it collides with an object. I know the problem is just because the mouse orbit is constantly moving the camera position so the collision detection doesn't have time to adjust the camera...

    It might just be due to lack of sleep but I can't figure out how to work around this...

    Any help would be appreciated.

    Thanks.
     
  2. Pirs01

    Pirs01

    Joined:
    Sep 30, 2012
    Posts:
    389
    After just a really quick look at the scripts my guess is your problem is due to using Lerp and SmoothDamp. You adjust your camera position in each Update and that's good (somewhat - more later) - it will be synchronized with user input. You react to user input on time but then you delay the camera adjustment by using Lerp and SmoothDamp. Drop them and go all the way to new position of camera in the same Update call where you discover need for that new position and calculate it.

    Another thing is - this is probably not the issue here but still: you should only have logic for user input in Update but then any adjustments to camera you do based on that input should be done in FixedUpdate. Update is synchronized with user input but FixedUpdate is synchronised with physics engine. Doing your calculations based on transforms (that may be related to Rigidbodies and thus physics simulation) will ensure that you always adjust your camera based on current - up to date state of the scene. Also it will make your camera react to environment regardless of machine / game performance at the moment - FixedUpdate is guaranteed to be called every so often.

    EDIT: Now that I think about it the second part is probably wrong - it's probably fine to adjust the camera position in Update in that adjusting camera more often then it renders (more often then Update is called) wouldn't give any visible effect anyway I guess.

    EDIT: So after a look at documentation the best event to move your camera is LateUpdate. By the time it's called all transforms has already been moved around the scene based onphysics or not. That brings me to another problem with the scripts I see now and will explain in next post in case you missed the late edits.
     
    Last edited: Jul 7, 2015
  3. Pirs01

    Pirs01

    Joined:
    Sep 30, 2012
    Posts:
    389
    You have one script that does camera orbiting and another that does camera "zoom" based on collision. A problem is that you do zooming in Update before you do orbiting in LateUpdate (check the doc for event call order). So the collision checking and zooming is based on out-dated camera position. You should do all your camera adjustments in LateUpdate and you should do zooming only after you rotated it around character (causing change in position). To ensure correct sequence move logic for both orbiting and zooming into single script and deal with both problems in single LateUpdate call in desired sequence.
     
    Last edited: Jul 7, 2015