Search Unity

Rotating camera around an object by touch while limiting X axis

Discussion in 'Scripting' started by Zythus, Jun 25, 2017.

  1. Zythus

    Zythus

    Joined:
    Jun 28, 2014
    Posts:
    30
    Hello ladies and gentlemen, I would like to ask you a huge favor.
    I tried to get rotating camera around an object by using touch, and I managed to get it to work with rotating around Y axis (horizontally). All fair and square, but when trying to meddle with rotating around X axis and limiting it, everything seems to say ,,good luck with that mate" as camera starts doing some crazy spins. I went through many threads on unity forums, and can't seem to find an answer. Maybe somebody came across that problem and could help me?
    I simply want the camera to rotate freely around Y axis, while limiting rotation around X axis to around 40 degrees up, and to almost floor down.

    Here is what I've got so far. Not a lot, and I guess not a lot more is needed to fix it.
    By the way I'm using that assignment in Start() since I read in one thread that it reduces processing power usage

    Code (CSharp):
    1.  
    2. void Start() {
    3.         cameraTransform = Camera.main.transform;
    4. }
    5.  
    6. void Update() {
    7.  
    8. if (Input.GetTouch(0).phase == TouchPhase.Moved)
    9. {
    10.  Vector2 TouchDirection = Input.GetTouch(0).deltaPosition;
    11.  Vector3 worldVector = Camera.main.ScreenToWorldPoint(new Vector3(0, TouchDirection.y, 0));
    12.  transform.RotateAround(player.transform.position, (new Vector3(0.0f, worldVector.y, 0.0f)), TouchDirection.x * 0.37f);
    13.  
    14. cameraTransform.LookAt(transform.position + transform.forward * 10f);
    15. }
    16.  
     
  2. BTCallahan

    BTCallahan

    Joined:
    Jun 6, 2015
    Posts:
    71
    I had the same problem, so I ended up using a bit of roundabout solution. I used a hierarchy of gameObjects with the player object as the base, with a child empty named Y_Yaw than handles rotation on the Y axis, and a child of Y_Yaw named X_Pich that handles rotation on the X axis. The camera is parented to X_Pitch. for limiting rotation, I used Mathf.Clamp to make sure it stays within the desired parameters.
     
    Zythus likes this.
  3. methos5k

    methos5k

    Joined:
    Aug 3, 2015
    Posts:
    8,712
    I also found it very useful to have the camera setup (I think the same as @BTCallahan said). It's much better :)
     
    Zythus likes this.
  4. Zythus

    Zythus

    Joined:
    Jun 28, 2014
    Posts:
    30
    So the hierarchy should look like:
    Player
    Y_Yaw (handling Y axis)
    X_Pitch (handlix X axis)
    And both of these children have their separate scripts? Could you share some of that code with me, maybe give a clue how it would look like? It's probably not too difficult, but I always have hard time wrapping my head around this stuff.

    Thanks
     
    Last edited: Jun 26, 2017
  5. BTCallahan

    BTCallahan

    Joined:
    Jun 6, 2015
    Posts:
    71
    You would be able to control them using a single script, like so:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class CameraController : MonoBehaviour {
    5.  
    6.     public float MaxPitch=25f, MinPitch=-25f;
    7.  
    8.     public GameObject Player, Y_Yaw, X_Pitch;
    9.  
    10.     void Update(){
    11.  
    12.         if (Input.GetTouch(0).phase == TouchPhase.Moved){
    13.            
    14.             Vector2 TouchDirection = Input.GetTouch(0).deltaPosition;
    15.  
    16.             Y_Yaw.transform.eulerAngles = new Vector3 (0f, TouchDirection.x * 360f, 0f);
    17.             X_Pitch.transform.eulerAngles = new Vector3 (Mathf.Clamp (TouchDirection.y * 360f, MinPitch, MaxPitch));
    18.         }
    19.     }
    20. }
    If multiplying the x and y value of touch direction by 360 gives unwanted result then another number would work better. I'm not familiar on what values TouchDirection normally returns.
     
    Zythus likes this.
  6. Zythus

    Zythus

    Joined:
    Jun 28, 2014
    Posts:
    30
    Thanks for the tips, I did as you said - created Player, made a child called Y_Yaw, and as for X_Pitch I associated Main Camera with it in inspector, tinkled a bit with the code, and I do have vertical and horizontal movement, but I cannot seem to restrict it. I put a Clamp like in your example, but in a couple of places, and in noone of these places it seems to work.
    Here's the code that I have:
    Code (CSharp):
    1.  if (Input.GetTouch(0).phase == TouchPhase.Moved)
    2.               {
    3.               Vector2 TouchDirection = Input.GetTouch(0).deltaPosition;
    4.  
    5.               Vector3 worldVector = Camera.main.ScreenToWorldPoint(new Vector3(TouchDirection.x, TouchDirection.y, 0));
    6.  
    7.               transform.RotateAround(player.transform.position, (new Vector3(0.0f, worldVector.y, 0.0f)), TouchDirection.x * 0.37f);
    8.               transform.RotateAround(player.transform.position, (new Vector3(worldVector.x, 0f, 0.0f)), TouchDirection.y * 0.2f);
    9.  
    10.                 Y_Yaw.transform.eulerAngles = new Vector3(TouchDirection.y * 0.3f, 0f, 0f);
    11.  
    12.                 cameraTransform.LookAt(player.transform.position);
    13.  
    14.                 }
     
  7. BTCallahan

    BTCallahan

    Joined:
    Jun 6, 2015
    Posts:
    71
    Sorry for the delay. It might be because of the way Input.GetTouch(0).deltaPosition works. If, say, a player's finger touches the right hand edge of the screen, and the screen is 800 pixels wide, will Input.GetTouch(0).deltaPosition.x return a value of 1 or 800? If it's the later, then you might need to adjust the values before plugging them into the RotateAround method.

    Code (CSharp):
    1.  
    2. Vector2 TouchDirection = Input.GetTouch(0).deltaPosition;
    3.  
    4. Vector3 worldVector = Camera.main.ScreenToWorldPoint(new Vector3(TouchDirection.x, TouchDirection.y, 0));
    5.  
    6. Vector2 SpinDirection = new Vector2 (TouchDirection.x - (Camera.main.pixelWidth * 0.5f), TouchDirection.y - (Camera.main.pixelHeight * 0.5f)) * 2f;//this means that SpinDirection.x will be somewhere between negative Camera.main.pixelWidth and positive Camera.main.pixelWidth, and SpinDirection.y will between negative Camera.main.pixelHeight and positive Camera.main.pixelHeight.
    7.  
    8. //Alternatively if you want to SpinDirection.x and y be clamped between -1 and 1, this bit of code would probably work better:
    9. SpinDirection = new Vector2 ((TouchDirection.x / Camera.main.pixelWidth -  0.5f) * 2f), (TouchDirection.y / Camera.main.pixelHeight -  0.5f) * 2f);
    10.  
    Also in the transform.RotateAround method, you probably don't need to declare a new Vector3 with a worldVector.y or x as an argument. Instead you could just use Vector3.up and Vector3.right respectively.

    Is the script attached to the camera, or another object?
     
    Zythus likes this.
  8. Zythus

    Zythus

    Joined:
    Jun 28, 2014
    Posts:
    30

    Script is attached to camera. Now I've got 2 versions. Either I have both RotateArounds working, and vertical rotation is smooth, and the camera moves in a circle-ish way on that X axis, but it goes below the ground, or I have the 2nd RotateAround commented out, which makes vertical rotation really choppy and responding in a weird way, while it looks like it's glued to one spot, and doesn't really wanna leave this spot. By the way I don't know if I got that SpinDirection thing right, but if I put SpinDirection.y in place of TouchDirection.y in the 2nd RotateAround I get crazy spins.

    I was also thinking about maybe changing player's X axis if moving camera on Y axis(horizontally), because if camera is placed on a proper spot on Y axis, it can rotate vertically 360 degrees around the plane. But If I move camera horizontally to different spot, it doesn't go around the top of the player, but rather does a smaller 360 by the spot it was placed. I guess that is how LookAt works here.
    Thanks for all the help BTCallahan!

    Code (CSharp):
    1. Vector2 TouchDirection = Input.GetTouch(0).deltaPosition;
    2. Vector3 worldVector = Camera.main.ScreenToWorldPoint(new Vector3(TouchDirection.x, TouchDirection.y, 0));  
    3.  
    4. Vector2 SpinDirection = new Vector2(TouchDirection.x - (Camera.main.pixelWidth * 0.5f), TouchDirection.y - (Camera.main.pixelHeight * 0.5f)) * 2f;
    5.  
    6. transform.RotateAround(player.transform.position, Vector3.up, TouchDirection.x * 0.37f);
    7. //transform.RotateAround(player.transform.position, Vector3.right, TouchDirection.y * 0.2f);
    8.  
    9. Y_Yaw.transform.eulerAngles = new Vector3(SpinDirection.y * 0.1f, 0f, 0f);
    10.  
    11.  cameraTransform.LookAt(player.transform.position);
     
  9. BTCallahan

    BTCallahan

    Joined:
    Jun 6, 2015
    Posts:
    71
    To prevent the camera from dipping below the ground, I recumbent using a clamp function:
    Code (CSharp):
    1.  
    2. float maxSpin = 45f;
    3. Y_Yaw.transform.eulerAngles = new Vector3.(Mathf.Clamp(SpinDirection.y * 0.1f, maxSpin, 0f), 0f, 0f);
    Another thing, in the code you have, what happens if you use X_Pitch instead Y_Yaw on line 9?
     
    Zythus likes this.
  10. Zythus

    Zythus

    Joined:
    Jun 28, 2014
    Posts:
    30
    Actually nothing changes if I use X_Pitch instead of Y_Yaw, and that code with Clamp doesn't do anything too ;/.
     
  11. Zythus

    Zythus

    Joined:
    Jun 28, 2014
    Posts:
    30
    I believe my thinking was flawed in this instance. I was thinking about limiting the rotation of Camera, but what I should do is limit its position in world space, so it would never go below a point on X axis. So I guess its not really that much about rotation (since LookAt takes care of this) but more about position of the gameObject in world.

    And thus I achieved this thing where camera doesn't go under the ground, but it still goes above the plane, and behaves in a weird way if I try to limit it (if I keep swiping down, into the ground, it slowly moves away from the player, or swiping up, and it slowly comes closer to the player and accordingly it can go completely out of the building or come too close, will try to fix this later)

    All I'm using is Vector2 TouchDirection, Vector3 worldVector, both RotateArounds and just after them I added these 2 lines of code:

    Code (CSharp):
    1. Vector3 p = cameraTransform.position;
    2. cameraTransform.position = new Vector3(p.x, Mathf.Clamp(p.y, 1f, 10f), p.z); ;
    Thanks for the help guys
     
    Last edited: Jul 5, 2017