Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

WOW/MMO style 3rd person camera.

Discussion in 'Scripting' started by BlankFoxGirl, May 1, 2010.

  1. BlankFoxGirl

    BlankFoxGirl

    Joined:
    Apr 26, 2010
    Posts:
    71
    Ok, so I modified the camera with zoom and collision which I found on the wiki and made a couple of simple edits.

    The results?
    * Camera always follows player at desired distance.
    * Camera movement (For viewing) only happens when you are holding down the right mouse button.
    * Mouse cursor is hidden when holding down and view is activated, otherwise, cursor is shown. Cursor is shown after a release automatically.

    Original Credits go to http://veli.ws/ Veli V.
    Original Code: http://www.unifycommunity.com/wiki/index.php?title=MouseOrbitImproved
    File: MMOStyleCamera.js
    Code (csharp):
    1. var target : Transform;
    2. var distance = 10.0;
    3.  
    4. var xSpeed = 250.0;
    5. var ySpeed = 120.0;
    6.  
    7. var yMinLimit = -20;
    8. var yMaxLimit = 80;
    9.  
    10. var distanceMin = 3;
    11. var distanceMax = 15;
    12.  
    13. private var x = 0.0;
    14. private var y = 0.0;
    15.  
    16.  
    17. @script AddComponentMenu("Camera-Control/Mouse Orbit")
    18.  
    19. function Start () {
    20.     var angles = transform.eulerAngles;
    21.     x = angles.y;
    22.     y = angles.x;
    23.    
    24.     // Make the rigid body not change rotation
    25.     if (rigidbody)
    26.         rigidbody.freezeRotation = false;
    27. }
    28.  
    29. function LateUpdate () {
    30.  
    31.     if (target) {
    32.    
    33.     if(Input.GetKey("mouse 1")){
    34.         Screen.showCursor = false;
    35.         x += Input.GetAxis("Mouse X") * xSpeed * distance* 0.02;
    36.         y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02;
    37.     }else{
    38.     Screen.showCursor = true;
    39.     }
    40.        y = ClampAngle(y, yMinLimit, yMaxLimit);
    41.        
    42.         var rotation = Quaternion.Euler(y, x, 0);
    43.  
    44.         distance = Mathf.Clamp(distance - Input.GetAxis("Mouse ScrollWheel")*5, distanceMin, distanceMax);
    45.        
    46.         var hit : RaycastHit;
    47.         if (Physics.Linecast (target.position, transform.position, hit)) {
    48.                 distance -=  hit.distance;
    49.         }
    50.        
    51.         var position = rotation * Vector3(0.0, 0.0, -distance) + target.position;
    52.  
    53.         transform.rotation = rotation;
    54.         transform.position = position;
    55.    
    56.     }
    57. }
    58.  
    59.  
    60. static function ClampAngle (angle : float, min : float, max : float) {
    61.     if (angle < -360)
    62.         angle += 360;
    63.     if (angle > 360)
    64.         angle -= 360;
    65.     return Mathf.Clamp (angle, min, max);
    66. }
     
    lfvbh likes this.
  2. bluetimeaq

    bluetimeaq

    Joined:
    May 1, 2008
    Posts:
    8
    :D Thanks!!! if the camera has inertia effect it will be better~~
     
  3. BlankFoxGirl

    BlankFoxGirl

    Joined:
    Apr 26, 2010
    Posts:
    71
    Currently right now I am working with modifying the FPSwalk script to include flight by the use of modifying the gravity variable. Wish I knew how to make the character rotate (lol) otherwise I would make them rotate like a bird when they go for a dive or for a swoop.

    If I knew how to get the velocity working, oh boy would I make this look really cool, and I would most certainly be using that couped with gravity.
     
    MusicLover likes this.
  4. SheePwns

    SheePwns

    Joined:
    Mar 17, 2010
    Posts:
    15
    My question is how to get this code work with a xbox360 controller, the right axis. It's the 4th and 5th axis that work, but how can I register this axis as an input without Unity complaining that it doesn't understand this?
     
  5. lfvbh

    lfvbh

    Joined:
    Mar 20, 2015
    Posts:
    1
     
  6. laurikens

    laurikens

    Joined:
    Feb 21, 2014
    Posts:
    2
    You need to go Edit->Project Settings->Input and mess around with whats in there.
    By default Unity isn't going to be listening to most of the controller input, you need to look up some other tutorials about how to see that up correctly.
    Once you have it set up right, you will be calling something like Input.GetAxis("Right Joystick X") and it will return a float between -1.0 and 1.0 which tells you how far the stick is tilted on that axis.
    If the stick is not being touched it will return 0.0, if its all the way to the right, it will return 1.0, half way to the right it will return 0.5 etc.
    You just need to use these numbers in place of Input.GetAxis("Mouse X") to use the joystick in order to control the camera.
     
  7. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,748
    Man, I can't wait until they released the revamped input system that's on the roadmap...
     
  8. Draimond

    Draimond

    Joined:
    Mar 12, 2016
    Posts:
    7
    This isn't the wow style camera until it auto rotates back behind the player after x seconds or is pull (towed) back on move.
    I've been trying to do this for .. going on two weeks now with no luck. using the same base script (camera orbit).
    Thinking about writing this with plain math and ditching bloody quaternions and eulers, so over it... -_-
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class P_CameraOrbit : MonoBehaviour {
    6.  
    7.     public GameObject thisPlayer;
    8.  
    9.     public Transform target;
    10.     public float x = 0.0f;
    11.     public float y = 0.0f;
    12.     public float distance = 5.0f;
    13.     public float xSpeed = 120.0f;
    14.     public float ySpeed = 120.0f;
    15.  
    16.     public float yMinLimit = -20f;
    17.     public float yMaxLimit = 80f;
    18.  
    19.     public float distanceMin = 0.5f;
    20.     public float distanceMax = 15f;
    21.  
    22.     public float camType = 1;
    23.  
    24.     public float cam1x ;
    25.     public float cam1y ;
    26.     Quaternion fromRotation;
    27.     Quaternion toRotation;
    28.  
    29.     // Use this for initialization
    30.     void Awake () {
    31.         camType = 3;
    32.         //transform.rotation = Quaternion.identity;
    33.  
    34.     }
    35.     void Start ()
    36.     {
    37.         Vector3 angles = transform.eulerAngles;
    38.         x = angles.y;
    39.         y = angles.x;
    40.     }
    41.  
    42.     void OnTriggerEnter () {
    43.         //gameObject.GetComponent<SphereCollider> ().enabled = false;
    44.         print ("on collsion: enter camType 1");
    45.         camType = 1;
    46.         transform.localPosition = new Vector3 (cam1x, cam1y, 0f);
    47.         transform.localRotation = Quaternion.Euler (0f, 0f, 0f);
    48.         //transform.localPosition
    49.     }
    50.  
    51.     void Update () {
    52.         if (Input.anyKeyDown) {
    53.             //print (x); WTF R U DOING!?!?
    54.             print (thisPlayer.transform.rotation.eulerAngles.y );
    55.         }
    56.     }
    57.  
    58.     void LateUpdate () {
    59.      
    60.         if (Input.GetAxis("ScrollWheel") != 0) {
    61.         //    print (Input.GetAxis("ScrollWheel"));    // This is here to figure out why the F*** the F***ing camera is F***ed!?
    62.         }
    63.         if (target) {
    64.             if (camType == 1) {
    65.                 if (Input.GetAxis ("ScrollWheel") < 0) {
    66.                     gameObject.GetComponent<SphereCollider> ().enabled = true;
    67.                     print ("This should swap to 3rd person cam");
    68.                     //transform.localPosition = new Vector3 (cam3x, cam3y, cam3z);
    69.                     distance = 2.5f;
    70.                     camType = 3;
    71.                 }
    72.             } else if (camType == 3) {
    73.                 if (Input.GetMouseButton (2)) {
    74.                     x += Input.GetAxis ("Mouse X") * xSpeed * distance * 0.02f;        // <-- put this in public class F***Tard { because it does stuiped S*** }
    75.                     y -= Input.GetAxis ("Mouse Y") * -1 * ySpeed * 0.02f;
    76.                     y = ClampAngle (y, yMinLimit, yMaxLimit);
    77.                 } else {
    78.                     //x = Mathf.Lerp (x, thisPlayer.transform.rotation.eulerAngles.y, Time.deltaTime*10);
    79.                     //y = Mathf.Lerp (y, thisPlayer.transform.rotation.y + 25, Time.deltaTime*10);
    80.                     fromRotation = Quaternion.Euler (y, x, 0);
    81.                     toRotation = Quaternion.Euler (thisPlayer.transform.rotation.y + 25, thisPlayer.transform.rotation.eulerAngles.y, 0);
    82.  
    83.                 }
    84.          
    85.                 Quaternion rotation = Quaternion.Euler (y, x, 0);
    86.                 //Quaternion rotation = Quaternion.? (this.transform.localRotation, toRotation);
    87.                 distance = Mathf.Clamp (distance - Input.GetAxis ("ScrollWheel") * 5, distanceMin, distanceMax);
    88.  
    89.                 //RaycastHit hit;
    90.                 //if (Physics.Linecast (target.position, transform.position, out hit))
    91.                 //{
    92.                 //    distance -=  hit.distance;
    93.                 //}
    94.                 Vector3 negDistance = new Vector3 (0.0f, 0.0f, -distance);
    95.                 //Vector3 position = rotation * negDistance + target.position;
    96.                 Vector3 position = toRotation * negDistance + target.position;
    97.  
    98.                 //fromRotation = this.transform.rotation;
    99.                 //toRotation = Quaternion.Euler (thisPlayer.transform.rotation.y, thisPlayer.transform.rotation.eulerAngles.y, 0f);
    100.                 //Quaternion newRotation = rotation;
    101.                 //transform.rotation = Quaternion.Euler(Quaternion.Angle(this.transform.localRotation, thisPlayer.transform.localRotation), Quaternion.Angle(this.transform.localRotation, thisPlayer.transform.localRotation), 0);
    102.                 //RotateTowards(this.transform.rotation, thisPlayer.transform.rotation, Time.deltaTime*100);
    103.                 transform.localRotation = rotation;
    104.                 transform.position = position;
    105.                 //transform.LookAt (target.transform.position);
    106.  
    107.             }
    108.         } else {
    109.             transform.LookAt (target.transform.position);
    110.         }
    111.     }
    112.  
    113.     public static float ClampAngle(float angle, float min, float max)
    114.     {
    115.         if (angle < -360F)
    116.             angle += 360F;
    117.         if (angle > 360F)
    118.             angle -= 360F;
    119.         return Mathf.Clamp(angle, min, max);
    120.     }
    121. }
    122.  
     
  9. Zaflis

    Zaflis

    Joined:
    May 26, 2014
    Posts:
    438
    2 ways that i'd think of:

    1) If you want camera that is behind the player like a deep nailed stick, set camera as a child-object to player. Move it to position you want in the Scene view and you're good to go. No script required. This is how camera in WoW works.

    2) If you want some delay to the camera so that it smoothly follows the direction, assign Quaternion.Lerp() to transform.rotation.

    Also for some cases SphereCast may be better than RayCast. See if you have a very edged wall behind you, then that ray would pass through to every tiny hole and then make sharp pushes everytime you turn.
     
  10. Collin__Patrick

    Collin__Patrick

    Joined:
    May 20, 2015
    Posts:
    188
    T
    This might be close to what you are looking for but it is in c#.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class CameraController : MonoBehaviour {
    5.  
    6.     public Transform cameraTarget;
    7.     private float x = 0.0f;
    8.     private float y = 0.0f;
    9.  
    10.     private int mouseXSpeedMod = 3;
    11.     private int mouseySpeedMod = 3;
    12.  
    13.     public float maxViewDistance = 25.0f;
    14.     public float minViewDistance = 1.0f;
    15.     public int zoomRate = 30;
    16.     public float lerpRate = 1.0f;
    17.     private float distance = 3.0f;
    18.     private float desiredDistance;
    19.     private float correctedDistance;
    20.     private float currentDistance;
    21.  
    22.     public float cameraTargetHeight = 1.0f;
    23.  
    24.     // Use this for initialization
    25.     void Start () {
    26.         Vector3 angles = transform.eulerAngles;
    27.         x += angles.x;
    28.         y -= angles.y;
    29.  
    30.         currentDistance = distance;
    31.         desiredDistance = distance;
    32.         correctedDistance = distance;
    33.     }
    34.  
    35.     void LateUpdate () {
    36.     if (Input.GetMouseButton (1)) {
    37.             x += Input.GetAxis("Mouse X") * mouseXSpeedMod;
    38.             y -= Input.GetAxis("Mouse Y") * mouseySpeedMod;
    39.         }
    40.  
    41.         else if(Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0){
    42.             float targetRotationAngle = cameraTarget.eulerAngles.y;
    43.             float cameraRotaionAngle = transform.eulerAngles.y;
    44.             x = Mathf.LerpAngle(cameraRotaionAngle, targetRotationAngle, lerpRate * Time.deltaTime);
    45.         }
    46.  
    47.         y = ClampAngle (y, -50, 50);
    48.  
    49.         Quaternion rotation = Quaternion.Euler (y, x, 0);
    50.  
    51.  
    52.         desiredDistance -= Input.GetAxis ("Mouse ScrollWheel") * Time.deltaTime * zoomRate * Mathf.Abs (desiredDistance);
    53.         desiredDistance = Mathf.Clamp (desiredDistance, minViewDistance, maxViewDistance);
    54.         correctedDistance = desiredDistance;
    55.  
    56.         Vector3 position = cameraTarget.position - (rotation * Vector3.forward * desiredDistance);
    57.  
    58.         RaycastHit collisionHit;
    59.         Vector3 cameraTargetPosition = new Vector3 (cameraTarget.position.x, cameraTarget.position.y + cameraTargetHeight, cameraTarget.position.z);
    60.  
    61.         bool isCorrected = false;
    62.         if(Physics.Linecast(cameraTargetPosition, position, out collisionHit)){
    63.             position = collisionHit.point;
    64.             correctedDistance = Vector3.Distance (cameraTargetPosition, position);
    65.             isCorrected = true;
    66.         }
    67.  
    68.         currentDistance = !isCorrected || correctedDistance > currentDistance ? Mathf .Lerp(currentDistance, correctedDistance, Time.deltaTime * zoomRate) : correctedDistance;
    69.  
    70.         position = cameraTarget.position - (rotation * Vector3.forward * currentDistance + new Vector3(0, -cameraTargetHeight, 0));
    71.  
    72.         transform.rotation = rotation;
    73.         transform.position = position;
    74.     }
    75.  
    76.     private static float ClampAngle(float angle, float min, float max){
    77.         if (angle < -360) {
    78.             angle += 360;
    79.         }
    80.         if (angle > 360) {
    81.             angle -= 360;
    82.         }
    83.         return Mathf.Clamp (angle, min, max);
    84.     }
    85. }
     
  11. Draimond

    Draimond

    Joined:
    Mar 12, 2016
    Posts:
    7
    1) this is incorrect because, in wow the camera can be moved and will re-align itself with the player, hence script required. At some point your going to have to tell the camera to return to localposition.y zero as the child of the player.
    2)Quaternion.Lerp is for rotation not position, plus there is no real delay, it moves smoothly but it doesn't pause.
     
  12. Zaflis

    Zaflis

    Joined:
    May 26, 2014
    Posts:
    438
    1) For finer details yeah you need script, but it's still simple to do with this mechanic. Say you put a camera like "on a stick" behind player, you can turn it behind player and see what different angles look like before even hitting Run button just by changing rotations from 1 object. Script only has to change the same angle values (eulerangles). Same way for zoom, just move the camera in Z axis in its localposition, or Y if you want to crouch or something.

    But it's also a matter of preference, when i played WoW i turned the auto-aligning off because to me it's a useless feature. I liked to control the camera myself, allowing things like looking sideways while moving forward, without holding mousebutton down same time.
     
  13. Draimond

    Draimond

    Joined:
    Mar 12, 2016
    Posts:
    7
    Fair enough, if nothing else, this has inspired me to add an option to turn auto center off.
    I really like the ESO setup where they combo fps and mmo styles, which is more what I'm working on.
    I also like the n64 Zelda cam which gives a kinda passive follow on move.
    Ultimately the cam needs to feel intuitive.
     
  14. ruldab111_unity

    ruldab111_unity

    Joined:
    Apr 17, 2018
    Posts:
    6
    НУ вы че блять js не годица лыжи не ходят
     
  15. Dutchmamba

    Dutchmamba

    Joined:
    Jul 3, 2018
    Posts:
    1
    So how can I make

    So how can I make this Camera Controller automatically center player?