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

WOW Camera Movement

Discussion in 'Scripting' started by matrix211v1, Jan 20, 2009.

  1. matrix211v1

    matrix211v1

    Joined:
    Jan 20, 2009
    Posts:
    193
    Hello all!

    I'm new to the Unity and to a Mac but I can script with no problem.

    I am looking for information on how to mimic the camera movement such as in World Of Warcraft. Can someone please either provide me with suggestions OR with links where I can read up about the subject and try and tackle it myself.

    Thanks in advance for your help and support!
     
  2. matrix211v1

    matrix211v1

    Joined:
    Jan 20, 2009
    Posts:
    193
    Ok, I have mimic'd the movements of WOW and I will be posting the scripts shortly. I am in needed of one last detail.

    I need a function to call that will put the camera behind the player in the direction that they are facing at the same distance that the camera is already from. I was looking at using the "RotateAround" function but not sure if this is the best course of action.

    Thanks for any help! Will post current code tonight.

    [edit]

    Here is the code I promised to post.

    This is named "moveCharacter". Add it to your Character
    Code (csharp):
    1. var turnSpeed = 10.0;
    2. var moveSpeed = 10.0;
    3. var mouseTurnMultiplier = 1;
    4.  
    5. private var x : float;
    6. private var z : float;
    7. function Update ()
    8. {
    9.     // x is used for the x axis.  set it to zero so it doesn't automatically rotate
    10.     x = 0;
    11.    
    12.     // check to see if the W or S key is being pressed.  
    13.     z = Input.GetAxis("Vertical") * Time.deltaTime * moveSpeed;
    14.    
    15.     // Move the character forwards or backwards
    16.     transform.Translate(0, 0, z);
    17.            
    18.     // Check to see if the A or S key are being pressed
    19.     if (Input.GetAxis("Horizontal"))
    20.     {
    21.         // Get the A or S key (-1 or 1)
    22.         x = Input.GetAxis("Horizontal");
    23.     }
    24.    
    25.     // Check to see if the right mouse button is pressed
    26.     if (Input.GetMouseButton(1))
    27.     {
    28.         // Get the difference in horizontal mouse movement
    29.         x = Input.GetAxis("Mouse X") * turnSpeed * mouseTurnMultiplier;
    30.     }
    31.  
    32.     // rotate the character based on the x value
    33.     transform.Rotate(0, x, 0);
    34. }
    This is named orbitCharacter. Add it to your camera.
    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 zoomRate = 20;
    11.  
    12. private var x = 0.0;
    13. private var y = 0.0;
    14.  
    15. @script AddComponentMenu("Camera-Control/Mouse Orbit")
    16.  
    17. function Start () {
    18.     var angles = transform.eulerAngles;
    19.     x = angles.y;
    20.     y = angles.x;
    21.  
    22.     // Make the rigid body not change rotation
    23.     if (rigidbody)
    24.         rigidbody.freezeRotation = true;
    25. }
    26.  
    27. function LateUpdate () {
    28.  
    29.     if (target) {
    30.         if (Input.GetMouseButton(0))
    31.         {
    32.         x += Input.GetAxis("Mouse X") * xSpeed * 0.02;
    33.         y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02;
    34.         var test = 0;
    35.         test = y;
    36.         }
    37.         distance += -(Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime) * zoomRate * Mathf.Abs(distance);
    38.         if (distance < 2.5)
    39.         {
    40.             distance = 2.5;
    41.         }
    42.         if (distance > 20)
    43.         {
    44.             distance = 20;
    45.         }
    46.        
    47.        
    48.         y = ClampAngle(y, yMinLimit, yMaxLimit);
    49.                
    50.         //Debug.Log("y: "+y+" test: "+test);
    51.        
    52.         if( y == yMinLimit  test == yMinLimit)
    53.         {
    54.             // This is to allow the camera to slide across the bottom if the player is too low in the y
    55.             distance += -(Input.GetAxis("Mouse Y") * Time.deltaTime) * 10 * Mathf.Abs(distance);
    56.         }
    57.        
    58.         var rotation = Quaternion.Euler(y, x, 0);
    59.         var position = rotation * Vector3(0.0, 2.0, -distance) + target.position;
    60.        
    61.         //Debug.Log("Distance: "+distance);
    62.         transform.rotation = rotation;
    63.         transform.position = position;
    64.     }
    65. }
    66.  
    67. static function ClampAngle (angle : float, min : float, max : float) {
    68.     if (angle < -360)
    69.         angle += 360;
    70.     if (angle > 360)
    71.         angle -= 360;
    72.     return Mathf.Clamp (angle, min, max);
    73. }
     
  3. Quietus2

    Quietus2

    Joined:
    Mar 28, 2008
    Posts:
    2,058
    Parent the camera to the player, move it to your 'default' position and rotation. Store those values upon startup. Then after you're done with your wow style mouselooks or what have you, simply use Lerp to move back to your default settings.
     
    dgwJeff likes this.
  4. matrix211v1

    matrix211v1

    Joined:
    Jan 20, 2009
    Posts:
    193
  5. matrix211v1

    matrix211v1

    Joined:
    Jan 20, 2009
    Posts:
    193
    Any other thoughts?
     
  6. amherst

    amherst

    Joined:
    Dec 9, 2008
    Posts:
    30
    thank you matrix for posting your code! I'd been working on this same issue, building a WoW style controller, but got stuck and put it aside. Now I'm back on the task and am curious if you figured out the camera snapping issue. I'd rewritten some of the code that comes packaged with Unity but yours works much better, except for that same final problem I had, getting the camera to default back to behind the player. Were you able to solve it?
    Thanks!
     
  7. matrix211v1

    matrix211v1

    Joined:
    Jan 20, 2009
    Posts:
    193
    Yes and no. I have it fixed so it does snap behind the player when using the Right Mouse button and when using the left it will Rotate Around the player.

    But I am having issues with the collision detection on the camera. Currently if there is a break in the ray (I shoot the ray FROM the player to the origin) and I try to move the camera to that point. What sometimes happens is that it gets stuck. Trying to find help on that.

    Let me post my code.

    Code (csharp):
    1. // This camera is similar to the one used in Jak  Dexter
    2.  
    3. var target : Transform;
    4. var distance = 4.0;
    5. var height = 1.0;
    6. var smoothLag = 0.2;
    7. var maxSpeed = 10.0;
    8. var snapLag = 0.3;
    9. var clampHeadPositionScreenSpace = 0.75;
    10. var lineOfSightMask : LayerMask = 0;
    11. var zoomSpeed = 50;
    12.  
    13. private var isSnapping = false;
    14. private var headOffset = Vector3.zero;
    15. private var centerOffset = Vector3.zero;
    16. private var controller : ThirdPersonController;
    17. private var velocity = Vector3.zero;
    18. private var targetHeight = 100000.0;
    19. private var theta;
    20. private var theta2;
    21. private var isColliding = false;
    22.  
    23. var targetOffset = Vector3.zero;
    24.  
    25. var closerRadius : float = 0.2;
    26. var closerSnapLag : float = 0.2;
    27.  
    28. var xSpeed = 200.0;
    29. var ySpeed = 80.0;
    30.  
    31. var yMinLimit = -20;
    32. var yMaxLimit = 80;
    33.  
    34. private var currentDistance = 10.0;
    35. private var x = 0.0;
    36. private var y = 0.0;
    37. private var distanceVelocity = 0.0;
    38.  
    39. function Start () {
    40.    var angles = target.transform.eulerAngles;
    41.    x = angles.y;
    42.    y = angles.x;
    43.        currentDistance = distance;
    44.  
    45.        // Make the rigid body not change rotation
    46.        if (rigidbody)
    47.                rigidbody.freezeRotation = true;
    48. }
    49.  
    50. function Awake ()
    51. {
    52.       theta = 0;
    53.       theta2 = 0;
    54.       var characterController : CharacterController = target.collider;
    55.       if (characterController)
    56.       {
    57.               centerOffset = characterController.bounds.center -
    58. target.position;
    59.               headOffset = centerOffset;
    60.               headOffset.y = characterController.bounds.max.y -
    61. target.position.y;
    62.       }
    63.  
    64.       if (target)
    65.       {
    66.               controller = target.GetComponent(ThirdPersonController);
    67.       }
    68.  
    69.       if (!controller)
    70.               Debug.Log("Please assign a target to the camera that has a Third Person Controller script component.");
    71. }
    72.  
    73. function LateUpdate () {
    74.  
    75.       var targetCenter = target.position + centerOffset;
    76.       var targetHead = target.position + headOffset;
    77.  
    78.       // When jumping don't move camera upwards but only down!
    79.       if (controller.IsJumping ())
    80.       {
    81.               // We'd be moving the camera upwards, do that only if it's really high
    82.               var newTargetHeight = targetCenter.y + height;
    83.               if (newTargetHeight < targetHeight || newTargetHeight - targetHeight > 5)
    84.                       targetHeight = targetCenter.y + height;
    85.       }
    86.       // When walking always update the target height
    87.       else
    88.       {
    89.               targetHeight = targetCenter.y + height;
    90.       }
    91.  
    92.       // We start snapping when user pressed Fire2!
    93.       if (Input.GetButton("Fire2")  !isSnapping)
    94.       {
    95.               //velocity = Vector3.zero;
    96.               isSnapping = true;
    97.       }
    98.  
    99.       if (isSnapping)
    100.       {
    101.               //ApplySnapping (targetCenter);
    102.               OrbitPlayerFromBehind (targetCenter);
    103.       }
    104.       else
    105.       {
    106.               //ApplyPositionDamping (Vector3(targetCenter.x, targetHeight, targetCenter.z));
    107.       }
    108.  
    109.       SetUpRotation(targetCenter, targetHead);
    110.  
    111.           if (Input.GetMouseButton(1))
    112.           {
    113.             OrbitPlayerFromBehind (targetCenter);
    114.           }
    115.  
    116.  
    117.       if (Input.GetMouseButton(0))
    118.       {
    119.               OrbitPlayer (targetCenter);
    120.               isSnapping = false;
    121.       }
    122.       else
    123.       {
    124.               //ApplyPositionDamping (Vector3(targetCenter.x, targetHeight, targetCenter.z));
    125.               isSnapping = true;
    126.       }
    127.  
    128.    distance += -(Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime) * zoomSpeed * Mathf.Abs(distance);
    129.        if (distance < 5)
    130.        {
    131.                distance = 5;
    132.        }
    133.        if (distance > 50)
    134.        {
    135.                distance = 50;
    136.        }
    137. }
    138.  
    139. function ApplySnapping (targetCenter : Vector3)
    140. {
    141. }
    142.  
    143. function OrbitPlayer (targetPlayer : Vector3)
    144. {
    145.        y = transform.position.y;
    146.        x += Input.GetAxis("Mouse X") * xSpeed * 0.02;
    147.        y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02;
    148.  
    149.        var rotation = Quaternion.Euler(0, x, 0);
    150.  
    151.        var targetPos = target.position;
    152.        var direction = rotation * -Vector3.forward;
    153.  
    154.        var targetDistance = AdjustLineOfSight(targetPos, direction);
    155.        currentDistance = distance;
    156.        transform.rotation = rotation;
    157.        transform.position = targetPos + direction * currentDistance;
    158.        if (y - target.position.y > 50)
    159.        {
    160.                y = target.position.y + 50;
    161.        }
    162.  
    163.        transform.position.y = y;
    164.        camera.transform.LookAt(targetPlayer);
    165. }
    166.  
    167. function OrbitPlayerFromBehind (targetPlayer : Vector3)
    168. {
    169.       var newPosition = Vector3();
    170.       var fwd = new Vector3();
    171.       var rightVector = new Vector3();
    172.       var upVector = new Vector3();
    173.       var movingVector = new Vector3();
    174.       var collisionVector = new Vector3();
    175.       var zeroVector = new Vector3();
    176.  
    177.       if (Input.GetMouseButton(1))
    178.       {
    179.                var mouseY = Input.GetAxis("Mouse Y");
    180.       }
    181.  
    182.       theta = jangle(transform.position - targetPlayer) * Time.deltaTime;
    183.       theta2 = theta2 + mouseY * Time.deltaTime;
    184.  
    185.       if (1.40 <= theta2)
    186.               theta2 = 1.40;
    187.  
    188.       fwd = target.TransformDirection(Vector3.forward);
    189.       fwd = fwd.normalized;
    190.  
    191.       newPosition = target.position - (distance * fwd);
    192.       newPosition.y = target.position.y + distance * Mathf.Sin(theta2);
    193.  
    194.       y = target.transform.eulerAngles.z;
    195.       x = target.transform.eulerAngles.y;
    196.       rightVector = Vector3(fwd.z, 0, -fwd.x);
    197.       rightVector = rightVector.normalized;
    198.  
    199.       upVector = Vector3.Cross(fwd, rightVector);
    200.       upVector = upVector.normalized;
    201.  
    202.       movingVector = Vector3.Slerp(transform.position, newPosition, Time.deltaTime * 50);
    203.  
    204.       collisionVector = AdjustLineOfSight(transform.position, targetPlayer);
    205.  
    206.        if (collisionVector != Vector3.zero)
    207.        {
    208.                Debug.Log("I am trying to get new position");
    209.                movingVector = collisionVector - (fwd * -1);
    210.                distance = movingVector.z - collisionVector.z;
    211.        }
    212.  
    213.       transform.position = movingVector;
    214.       camera.transform.LookAt(targetPlayer, upVector);
    215.  
    216.  
    217.  
    218. }
    219.  
    220.  
    221. function AdjustLineOfSight (newPosition : Vector3, target : Vector3)
    222. {
    223.       var hit : RaycastHit;
    224.       if (Physics.Linecast (target, newPosition, hit, lineOfSightMask.value))
    225.       {
    226.                   Debug.Log("I hit someting at: "+hit.point);
    227.               velocity = Vector3.zero;
    228.               isColliding = true;
    229.               return hit.point;
    230.       }
    231.       //return newPosition;
    232. }
    233.  
    234.  
    235. function ApplyPositionDamping (targetCenter : Vector3)
    236. {
    237. }
    238.  
    239. function SetUpRotation (centerPos : Vector3, headPos : Vector3)
    240. {
    241. }
    242.  
    243. function AngleDistance (a : float, b : float)
    244. {
    245.       a = Mathf.Repeat(a, 360);
    246.       b = Mathf.Repeat(b, 360);
    247.  
    248.       return Mathf.Abs(b - a);
    249. }
    250.  
    251. function jangle(pTemp : Vector3)
    252. {
    253.       var tTheta:Number;
    254.  
    255.       pTemp.Normalize();
    256.  
    257.       // quadrant I  II
    258.       tTheta = Mathf.Acos(pTemp.x);
    259.  
    260.       // quadtrant III  IV
    261.       if (pTemp.z < 0)
    262.               tTheta = 2*Mathf.PI - tTheta;
    263.  
    264.       return tTheta;
    265. }
    266.  
    267. function bindAngle(tDegrees:Number)
    268. {
    269.       if (tDegrees < 0)
    270.               tDegrees += Mathf.PI*2;
    271.       else if (Mathf.PI*2 <= tDegrees)
    272.               tDegrees += - Mathf.PI*2;
    273.       return tDegrees;
    274. }
    275.  
    276. static function ClampAngle (angle : float, min : float, max : float) {
    277.        if (angle < -360)
    278.                angle += 360;
    279.        if (angle > 360)
    280.                angle -= 360;
    281.        return Mathf.Clamp (angle, min, max);
    282. }
    283.  
    284.  
    285. @script AddComponentMenu ("Third Person Camera/Spring Follow Camera")
    and this:

    Code (csharp):
    1.  
    2. // The speed when walking
    3. var walkSpeed = 3.0;
    4. // after trotAfterSeconds of walking we trot with trotSpeed
    5. var trotSpeed = 4.0;
    6. // when pressing "Fire3" button (cmd) we start running
    7. var runSpeed = 6.0;
    8.  
    9. var inAirControlAcceleration = 3.0;
    10.  
    11. // How high do we jump when pressing jump and letting go immediately
    12. var jumpHeight = 0.5;
    13. // We add extraJumpHeight meters on top when holding the button down longer while jumping
    14. var extraJumpHeight = 2.5;
    15.  
    16. // The gravity for the character
    17. var gravity = 20.0;
    18. // The gravity in controlled descent mode
    19. var controlledDescentGravity = 2.0;
    20. var speedSmoothing = 10.0;
    21. var rotateSpeed = 500.0;
    22. var trotAfterSeconds = 3.0;
    23.  
    24. var canJump = true;
    25. var canControlDescent = true;
    26. var canWallJump = false;
    27.  
    28. private var jumpRepeatTime = 0.05;
    29. private var wallJumpTimeout = 0.15;
    30. private var jumpTimeout = 0.15;
    31. private var groundedTimeout = 0.25;
    32.  
    33. // The camera doesnt start following the target immediately but waits for a split second to avoid too much waving around.
    34. private var lockCameraTimer = 0.0;
    35.  
    36. // The current move direction in x-z
    37. private var moveDirection = Vector3.zero;
    38. // The current vertical speed
    39. private var verticalSpeed = 0.0;
    40. // The current x-z move speed
    41. private var moveSpeed = 0.0;
    42.  
    43. // The last collision flags returned from controller.Move
    44. private var collisionFlags : CollisionFlags;
    45.  
    46. // Are we jumping? (Initiated with jump button and not grounded yet)
    47. private var jumping = false;
    48. private var jumpingReachedApex = false;
    49.  
    50. // Are we moving backwards (This locks the camera to not do a 180 degree spin)
    51. private var movingBack = false;
    52. // Is the user pressing any keys?
    53. private var isMoving = false;
    54. // When did the user start walking (Used for going into trot after a while)
    55. private var walkTimeStart = 0.0;
    56. // Last time the jump button was clicked down
    57. private var lastJumpButtonTime = -10.0;
    58. // Last time we performed a jump
    59. private var lastJumpTime = -1.0;
    60. // Average normal of the last touched geometry
    61. private var wallJumpContactNormal : Vector3;
    62. private var wallJumpContactNormalHeight : float;
    63.  
    64. // the height we jumped from (Used to determine for how long to apply extra jump power after jumping.)
    65. private var lastJumpStartHeight = 0.0;
    66. // When did we touch the wall the first time during this jump (Used for wall jumping)
    67. private var touchWallJumpTime = -1.0;
    68.  
    69. private var inAirVelocity = Vector3.zero;
    70.  
    71. private var lastGroundedTime = 0.0;
    72.  
    73. private var lean = 0.0;
    74. private var slammed = false;
    75.  
    76. private var isControllable = true;
    77.  
    78. private var oldForwardVector : Vector3;
    79.  
    80. private var strafe : float;
    81.  
    82. function Awake ()
    83. {
    84.     moveDirection = transform.TransformDirection(Vector3.forward);
    85. }
    86.  
    87. // This next function responds to the "HidePlayer" message by hiding the player.
    88. // The message is also 'replied to' by identically-named functions in the collision-handling scripts.
    89. // - Used by the LevelStatus script when the level completed animation is triggered.
    90.  
    91. function HidePlayer()
    92. {
    93.     GameObject.Find("rootJoint").GetComponent(SkinnedMeshRenderer).enabled = false; // stop rendering the player.
    94.     isControllable = false; // disable player controls.
    95. }
    96.  
    97. // This is a complementary function to the above. We don't use it in the tutorial, but it's included for
    98. // the sake of completeness. (I like orthogonal APIs; so sue me!)
    99.  
    100. function ShowPlayer()
    101. {
    102.     GameObject.Find("rootJoint").GetComponent(SkinnedMeshRenderer).enabled = true; // start rendering the player again.
    103.     isControllable = true;  // allow player to control the character again.
    104. }
    105.  
    106.  
    107. function UpdateSmoothedMovementDirection ()
    108. {
    109.     strafe = 0;
    110.     var cameraTransform = this.transform;
    111.     var grounded = IsGrounded();
    112.    
    113.     // Forward vector relative to the camera along the x-z plane   
    114.     var forward = cameraTransform.TransformDirection(Vector3.forward);
    115.     forward = forward.normalized;
    116.  
    117.     // Right vector relative to the camera
    118.     // Always orthogonal to the forward vector
    119.     var right = Vector3(forward.z, 0, -forward.x);
    120.         right = right.normalized;  
    121.        
    122.     var v = Input.GetAxisRaw("Vertical");
    123.     var h = Input.GetAxisRaw("Horizontal");
    124.  
    125.     // Are we moving backwards or looking backwards
    126.     if (v < -0.2)
    127.         movingBack = true;
    128.     else
    129.         movingBack = false;
    130.    
    131.     var wasMoving = isMoving;
    132.     isMoving = Mathf.Abs (h) > 0.1 || Mathf.Abs (v) > 0.1;
    133.        
    134.     // Target direction relative to the camera
    135.     var targetDirection = h * right + Mathf.Abs(v) * forward;
    136.    
    137.     // Grounded controls
    138.     if (grounded)
    139.     {
    140.         // Lock camera for short period when transitioning moving  standing still
    141.         //lockCameraTimer += Time.deltaTime;
    142.  
    143.         // We store speed and direction seperately,
    144.         // so that when the character stands still we still have a valid forward direction
    145.         // moveDirection is always normalized, and we only update it if there is user input.
    146.         if (targetDirection != Vector3.zero)
    147.         {
    148.             // If we are really slow, just snap to the target direction
    149.             if (moveSpeed < walkSpeed * 0.9  grounded)
    150.             {
    151.                 moveDirection = moveDirection.normalized;
    152.             }
    153.             // Otherwise smoothly turn towards it
    154.             else
    155.             {
    156.                 moveDirection = moveDirection.normalized;
    157.             }
    158.         }
    159.        
    160.         // Smooth the speed based on the current target direction
    161.         var curSmooth = speedSmoothing * Time.deltaTime;
    162.        
    163.         // Choose target speed
    164.         // We want to support analog input but make sure you cant walk faster diagonally than just forward or sideways
    165.         var targetSpeed = Mathf.Min(targetDirection.magnitude, 1.0);
    166.    
    167.         // Pick speed modifier
    168.         if (Input.GetButton ("Fire3"))
    169.         {
    170.             targetSpeed *= runSpeed;
    171.         }
    172.         else if (Time.time - trotAfterSeconds > walkTimeStart)
    173.         {
    174.             //targetSpeed *= trotSpeed;
    175.         }
    176.         else
    177.         {
    178.             targetSpeed *= walkSpeed;
    179.         }
    180.        
    181.         //Debug.Log("moveSpeed: "+moveSpeed);
    182.        
    183.         if (v == 0  h != 0)
    184.         {
    185.             moveSpeed = .2;
    186.         }
    187.         else
    188.         {
    189.             moveSpeed = Mathf.Lerp(moveSpeed, targetSpeed, curSmooth);
    190.         }
    191.        
    192.         // Reset walk time start when we slow down
    193.         if (moveSpeed < walkSpeed * 0.3)
    194.             walkTimeStart = Time.time;
    195.            
    196.     if (Input.GetAxis("Horizontal") != 0)
    197.     {
    198.         h = Input.GetAxis("Horizontal");
    199.                
    200.         forward = transform.TransformDirection(Vector3.forward);
    201.         forward = forward.normalized;
    202.        
    203.         right = Vector3(forward.z, 0, -forward.x);
    204.         right = right.normalized;          
    205.  
    206.         targetDirection = h * right + 10 * forward;  
    207.          
    208.         moveDirection = targetDirection;
    209.         moveDirection = moveDirection.normalized;
    210.  
    211.     }
    212.  
    213.     if (Input.GetMouseButton(1))
    214.     {
    215.         // Get the difference in horizontal mouse movement
    216.         h = Input.GetAxis("Mouse X");
    217.         if (h > 4)
    218.         {
    219.             h = 4;
    220.         }
    221.         if (h < -4)
    222.         {
    223.             h = -4;
    224.         }
    225.        
    226.        forward = transform.TransformDirection(Vector3.forward);
    227.        forward = forward.normalized;
    228.        
    229.        if (forward != oldForwardVector  v == 0)
    230.        {
    231.             //Debug.Log("1 v: "+moveSpeed);
    232.             moveSpeed = 0.2;
    233.        }
    234.        
    235.        right = Vector3(forward.z, 0, -forward.x);      
    236.  
    237.        targetDirection = h * right + 3 * forward;  
    238.          
    239.        moveDirection = targetDirection;
    240.        moveDirection = moveDirection.normalized;
    241.        
    242.        oldForwardVector = forward;
    243.     }  
    244.  
    245.     // Strafing
    246.     if (Input.GetAxisRaw("Strafe") != 0)
    247.     {
    248.        strafe = Input.GetAxisRaw("Strafe");
    249.        Debug.Log("srafe: "+strafe);
    250.        strafe *= 5;
    251.     }
    252.    
    253.     }
    254.     // In air controls
    255.     else
    256.     {
    257.         // Lock camera while in air
    258.         if (jumping)
    259.             lockCameraTimer = 0.0;
    260.  
    261.         if (isMoving)
    262.             inAirVelocity += targetDirection.normalized * Time.deltaTime * inAirControlAcceleration;
    263.     }
    264.    
    265.  
    266.        
    267. }
    268.  
    269. function ApplyWallJump ()
    270. {
    271.     // We must actually jump against a wall for this to work
    272.     if (!jumping)
    273.         return;
    274.  
    275.     // Store when we first touched a wall during this jump
    276.     if (collisionFlags == CollisionFlags.CollidedSides)
    277.     {
    278.         touchWallJumpTime = Time.time;
    279.     }
    280.  
    281.     // The user can trigger a wall jump by hitting the button shortly before or shortly after hitting the wall the first time.
    282.     var mayJump = lastJumpButtonTime > touchWallJumpTime - wallJumpTimeout  lastJumpButtonTime < touchWallJumpTime + wallJumpTimeout;
    283.     if (!mayJump)
    284.         return;
    285.    
    286.     // Prevent jumping too fast after each other
    287.     if (lastJumpTime + jumpRepeatTime > Time.time)
    288.         return;
    289.    
    290.        
    291.     if (Mathf.Abs(wallJumpContactNormal.y) < 0.2)
    292.     {
    293.         wallJumpContactNormal.y = 0;
    294.         moveDirection = wallJumpContactNormal.normalized;
    295.         // Wall jump gives us at least trotspeed
    296.         moveSpeed = Mathf.Clamp(moveSpeed * 1.5, trotSpeed, runSpeed);
    297.     }
    298.     else
    299.     {
    300.         moveSpeed = 0;
    301.     }
    302.    
    303.     verticalSpeed = CalculateJumpVerticalSpeed (jumpHeight);
    304.     DidJump();
    305.     SendMessage("DidWallJump", null, SendMessageOptions.DontRequireReceiver);
    306. }
    307.  
    308. function ApplyJumping ()
    309. {
    310.     // Prevent jumping too fast after each other
    311.     if (lastJumpTime + jumpRepeatTime > Time.time)
    312.         return;
    313.  
    314.     if (IsGrounded()) {
    315.         // Jump
    316.         // - Only when pressing the button down
    317.         // - With a timeout so you can press the button slightly before landing    
    318.         if (canJump  Time.time < lastJumpButtonTime + jumpTimeout) {
    319.             verticalSpeed = CalculateJumpVerticalSpeed (jumpHeight);
    320.             SendMessage("DidJump", SendMessageOptions.DontRequireReceiver);
    321.         }
    322.     }
    323. }
    324.  
    325.  
    326. function ApplyGravity ()
    327. {
    328.     if (isControllable) // don't move player at all if not controllable.
    329.     {
    330.         // Apply gravity
    331.         var jumpButton = Input.GetButton("Jump");
    332.        
    333.         // * When falling down we use controlledDescentGravity (only when holding down jump)
    334.         var controlledDescent = canControlDescent  verticalSpeed <= 0.0  jumpButton  jumping;
    335.        
    336.         // When we reach the apex of the jump we send out a message
    337.         if (jumping  !jumpingReachedApex  verticalSpeed <= 0.0)
    338.         {
    339.             jumpingReachedApex = true;
    340.             SendMessage("DidJumpReachApex", SendMessageOptions.DontRequireReceiver);
    341.         }
    342.    
    343.         // * When jumping up we don't apply gravity for some time when the user is holding the jump button
    344.         //   This gives more control over jump height by pressing the button longer
    345.         var extraPowerJump =  IsJumping ()  verticalSpeed > 0.0  jumpButton  transform.position.y < lastJumpStartHeight + extraJumpHeight;
    346.        
    347.         if (controlledDescent)         
    348.             verticalSpeed -= controlledDescentGravity * Time.deltaTime;
    349.         else if (extraPowerJump)
    350.             return;
    351.         else if (IsGrounded ())
    352.             verticalSpeed = 0.0;
    353.         else
    354.             verticalSpeed -= gravity * Time.deltaTime;
    355.     }
    356. }
    357.  
    358. function CalculateJumpVerticalSpeed (targetJumpHeight : float)
    359. {
    360.     // From the jump height and gravity we deduce the upwards speed
    361.     // for the character to reach at the apex.
    362.     return Mathf.Sqrt(2 * targetJumpHeight * gravity);
    363. }
    364.  
    365. function DidJump ()
    366. {
    367.     jumping = true;
    368.     jumpingReachedApex = false;
    369.     lastJumpTime = Time.time;
    370.     lastJumpStartHeight = transform.position.y;
    371.     touchWallJumpTime = -1;
    372.     lastJumpButtonTime = -10;
    373. }
    374.  
    375. function Update() {
    376.    
    377.     if (!isControllable)
    378.     {
    379.         // kill all inputs if not controllable.
    380.         Input.ResetInputAxes();
    381.     }
    382.  
    383.     if (Input.GetButtonDown ("Jump"))
    384.     {
    385.         lastJumpButtonTime = Time.time;
    386.     }
    387.  
    388.     UpdateSmoothedMovementDirection();
    389.    
    390.     // Apply gravity
    391.     // - extra power jump modifies gravity
    392.     // - controlledDescent mode modifies gravity
    393.     ApplyGravity ();
    394.  
    395.     // Perform a wall jump logic
    396.     // - Make sure we are jumping against wall etc.
    397.     // - Then apply jump in the right direction)
    398.     if (canWallJump)
    399.         ApplyWallJump();
    400.  
    401.     // Apply jumping logic
    402.     ApplyJumping ();
    403.    
    404.     // Calculate actual motion
    405.     // If moving forwards
    406.    
    407.         forward = transform.TransformDirection(Vector3.forward);
    408.         forward = forward.normalized;
    409.  
    410.         right = Vector3(forward.z, 0, -forward.x);
    411.         right = right.normalized;
    412.    
    413.     if (strafe != 0  moveSpeed == 0)
    414.     {
    415.         moveSpeed = .2;
    416.     }
    417.    
    418.  
    419.     if (movingBack == false)
    420.     {
    421.         var movement = moveDirection * moveSpeed + Vector3 (0, verticalSpeed, strafe) + inAirVelocity;
    422.         movement *= Time.deltaTime;
    423.     }
    424.     else
    425.     {  
    426.         movement = (moveDirection  * -1) * moveSpeed + Vector3 (0, verticalSpeed, strafe) + inAirVelocity;
    427.         movement *= Time.deltaTime;
    428.     }
    429.    
    430.     if (!isMoving)
    431.     {
    432.  
    433.         //Debug.Log("No movement");
    434.         //movement = right * strafe * 5 + Vector3 (0, verticalSpeed, 0) + inAirVelocity;
    435.         //movement *= Time.deltaTime;      
    436.     }
    437.     else
    438.     {
    439.         //Debug.Log("Movement");
    440.     }
    441.         //Debug.Log("movement: "+movement+ " moveSpeed: "+moveSpeed);
    442.     // Move the controller
    443.     var controller : CharacterController = GetComponent(CharacterController);
    444.     wallJumpContactNormal = Vector3.zero;
    445.     collisionFlags = controller.Move(movement);
    446.    
    447.     // Set rotation to the move direction
    448.     if (IsGrounded())
    449.     {
    450.         if(slammed) // we got knocked over by an enemy. We need to reset some stuff
    451.         {
    452.             slammed = false;
    453.             controller.height = 2;
    454.             transform.position.y += 0.75;
    455.         }
    456.        
    457.         transform.rotation = Quaternion.LookRotation(moveDirection);
    458.            
    459.     }  
    460.     else
    461.     {
    462.         if(!slammed)
    463.         {
    464.             var xzMove = movement;
    465.             xzMove.y = 0;
    466.             if (xzMove.sqrMagnitude > 0.001)
    467.             {
    468.                 //transform.rotation = Quaternion.LookRotation(xzMove);
    469.             }
    470.         }
    471.     }  
    472.    
    473.     // We are in jump mode but just became grounded
    474.     if (IsGrounded())
    475.     {
    476.         lastGroundedTime = Time.time;
    477.         inAirVelocity = Vector3.zero;
    478.         if (jumping)
    479.         {
    480.             jumping = false;
    481.             SendMessage("DidLand", SendMessageOptions.DontRequireReceiver);
    482.         }
    483.     }
    484. }
    485.  
    486. function OnControllerColliderHit (hit : ControllerColliderHit )
    487. {
    488.     if (hit.moveDirection.y > 0.01)
    489.         return;
    490.     wallJumpContactNormal = hit.normal;
    491. }
    492.  
    493. function GetSpeed () {
    494.     return moveSpeed;
    495. }
    496.  
    497. function IsJumping () {
    498.     return jumping  !slammed;
    499. }
    500.  
    501. function IsGrounded () {
    502.     return (collisionFlags  CollisionFlags.CollidedBelow) != 0;
    503. }
    504.  
    505. function SuperJump (height : float)
    506. {
    507.     verticalSpeed = CalculateJumpVerticalSpeed (height);
    508.     collisionFlags = CollisionFlags.None;
    509.     SendMessage("DidJump", SendMessageOptions.DontRequireReceiver);
    510. }
    511.  
    512. function SuperJump (height : float, jumpVelocity : Vector3)
    513. {
    514.     verticalSpeed = CalculateJumpVerticalSpeed (height);
    515.     inAirVelocity = jumpVelocity;
    516.    
    517.     collisionFlags = CollisionFlags.None;
    518.     SendMessage("DidJump", SendMessageOptions.DontRequireReceiver);
    519. }
    520.  
    521. function Slam (direction : Vector3)
    522. {
    523.     verticalSpeed = CalculateJumpVerticalSpeed (1);
    524.     inAirVelocity = direction * 6;
    525.     direction.y = 0.6;
    526.     Quaternion.LookRotation(-direction);
    527.     var controller : CharacterController = GetComponent(CharacterController);
    528.     controller.height = 0.5;
    529.     slammed = true;
    530.     collisionFlags = CollisionFlags.None;
    531.     SendMessage("DidJump", SendMessageOptions.DontRequireReceiver);
    532. }
    533.  
    534. function GetDirection () {
    535.     return moveDirection;
    536. }
    537.  
    538. function IsMovingBackwards () {
    539.     return movingBack;
    540. }
    541.  
    542. function GetLockCameraTimer ()
    543. {
    544.     return lockCameraTimer;
    545. }
    546.  
    547. function IsMoving ()  : boolean
    548. {
    549.     return Mathf.Abs(Input.GetAxisRaw("Vertical")) + Mathf.Abs(Input.GetAxisRaw("Horizontal")) > 0.5;
    550. }
    551.  
    552. function HasJumpReachedApex ()
    553. {
    554.     return jumpingReachedApex;
    555. }
    556.  
    557. function IsGroundedWithTimeout ()
    558. {
    559.     return lastGroundedTime + groundedTimeout > Time.time;
    560. }
    561.  
    562. function IsControlledDescent ()
    563. {
    564.     // * When falling down we use controlledDescentGravity (only when holding down jump)
    565.     var jumpButton = Input.GetButton("Jump");
    566.     return canControlDescent  verticalSpeed <= 0.0  jumpButton  jumping;
    567. }
    568.  
    569. function Reset ()
    570. {
    571.     gameObject.tag = "Player";
    572. }
    573. // Require a character controller to be attached to the same game object
    574. @script RequireComponent(CharacterController)
    575. @script AddComponentMenu("Third Person Player/Third Person Controller")
    I need help with the collision for breaking the ray and the strafing.
     
  8. alanis

    alanis

    Joined:
    Mar 4, 2009
    Posts:
    99

    thank you matrix211v1, great script, i tried it and works nicely.

    I was wondering did you ever get the collisions of the camera figured out yet?

    I was playing with it and yes, i noticed the camera going thru inside the objects and even below the ground, it looks funny.

    I also noticed that when to toon is on idle and i try to move it left of right by "a" or "d" on my keyboard it does a violent 360 degree turn, but when running mode use the left or right turn it works accordingly, just setup the rotation speed and it does it correctly, but like stated before, if the toon is on idle and even with the rotation speed of the camera setup low, it does a fast and violent turn, i still cant figure this part yet.

    by the way, I was just testing your spring follow camera script and the default third caracter controller from the demo, because could not use your third caracter controller script, everytime i added to the player and tried to test it, unity editor will close without a reason, like the whole unity game editor shuts down with no error message.

    anyways thanks again for your nice script and let us know if you got the colission part figured out yet.


    regards
     
  9. matrix211v1

    matrix211v1

    Joined:
    Jan 20, 2009
    Posts:
    193
    Once again, yes and no. I tried to use a Character Collider with the move vector but that caused all sorts of problems. I think the best way to solve it is to put a sphere collider on the camera GameObject itself and test that (since I know the position vector that the camera needs to be at because the script is working now!)

    Lately I have been busy building a multiplayer server which I just finished (As the title suggest, I am mimicing WOW) and now trying to get the server to record the player positions in a database (already got most of this working).

    Once I finish that (Sunday), I will get back on the camera collision thing and post what I have for everyone.

    Till later!
     
  10. alanis

    alanis

    Joined:
    Mar 4, 2009
    Posts:
    99
    That is great news matrix211v1,
    cant wait to see your work.

    thank you.

    keep up the good work.

    regards
     
  11. Paintbrush

    Paintbrush

    Joined:
    Apr 1, 2009
    Posts:
    23
    Hey everyone!

    Matrix, thanks for starting this topic! Like many others, I've stumbled on this thread looking for a way to simulate WoW's camera controls, and you've made a good head-start with your first batch of code (I say first batch because the second batch kept crashing Unity for me... I'm not sure why, but I thought it'd be best to start with what you have earlier).

    Hope you don't mind, but I extended on your earlier code to get it close enough to WoW (things like camera rotation on left mouse hold, character rotation on right mouse hold, camera easing behind character when neither mouse buttons are held down while moving, etc.). The only thing I think I haven't implemented it to make it complete is collision detection, which you seem to be working on right now. I kept it as simple as possible so you guys can tear it apart... in fact I would love feedback, because I'm new to 3D math and perhaps there are some things I do in there that could be done with greater efficiency or with built-in functions I do not know of. Anyway, enough stalling, on to the code!

    WowCharacterController.js:
    Code (csharp):
    1.  
    2. private var jumpSpeed:float = 8.0;
    3. private var gravity:float = 20.0;
    4. private var runSpeed:float = 5.0;
    5. private var walkSpeed:float = 1.0;
    6. private var rotateSpeed:float = 150.0;
    7.  
    8. private var grounded:boolean = false;
    9. private var moveDirection:Vector3 = Vector3.zero;
    10. private var isWalking:boolean = false;
    11. private var moveStatus:String = "idle";
    12.  
    13. function Update ()
    14. {
    15.     // Only allow movement and jumps while grounded
    16.     if(grounded) {
    17.         moveDirection = new Vector3((Input.GetMouseButton(1) ? Input.GetAxis("Horizontal") : 0),0,Input.GetAxis("Vertical"));
    18.        
    19.         // if moving forward and to the side at the same time, compensate for distance
    20.         // TODO: may be better way to do this?
    21.         if(Input.GetMouseButton(1)  Input.GetAxis("Horizontal")  Input.GetAxis("Vertical")) {
    22.             moveDirection *= .7;
    23.         }
    24.        
    25.         moveDirection = transform.TransformDirection(moveDirection);
    26.         moveDirection *= isWalking ? walkSpeed : runSpeed;
    27.        
    28.         moveStatus = "idle";
    29.         if(moveDirection != Vector3.zero)
    30.             moveStatus = isWalking ? "walking" : "running";
    31.        
    32.         // Jump!
    33.         if(Input.GetButton("Jump"))
    34.             moveDirection.y = jumpSpeed;
    35.     }
    36.    
    37.     // Allow turning at anytime. Keep the character facing in the same direction as the Camera if the right mouse button is down.
    38.     if(Input.GetMouseButton(1)) {
    39.         transform.rotation = Quaternion.Euler(0,Camera.main.transform.eulerAngles.y,0);
    40.     } else {
    41.         transform.Rotate(0,Input.GetAxis("Horizontal") * rotateSpeed * Time.deltaTime, 0);
    42.     }
    43.    
    44.     if(Input.GetMouseButton(1) || Input.GetMouseButton(0))
    45.         Screen.lockCursor = true;
    46.     else
    47.         Screen.lockCursor = false;
    48.    
    49.     // Toggle walking/running with the T key
    50.     if(Input.GetKeyDown("t"))
    51.         isWalking = !isWalking;
    52.    
    53.     //Apply gravity
    54.     moveDirection.y -= gravity * Time.deltaTime;
    55.    
    56.     //Move controller
    57.     var controller:CharacterController = GetComponent(CharacterController);
    58.     var flags = controller.Move(moveDirection * Time.deltaTime);
    59.     grounded = (flags  CollisionFlags.Below) != 0;
    60. }
    61.  
    62. @script RequireComponent(CharacterController)
    63.  
    WowCamera.js
    Code (csharp):
    1.  
    2. var target : Transform;
    3.  
    4. var targetHeight = 2.0;
    5. var distance = 5.0;
    6.  
    7. var maxDistance = 20;
    8. var minDistance = 2.5;
    9.  
    10. var xSpeed = 250.0;
    11. var ySpeed = 120.0;
    12.  
    13. var yMinLimit = -20;
    14. var yMaxLimit = 80;
    15.  
    16. var zoomRate = 20;
    17.  
    18. var rotationDampening = 3.0;
    19.  
    20. private var x = 0.0;
    21. private var y = 0.0;
    22.  
    23. @script AddComponentMenu("Camera-Control/WoW Camera")
    24.  
    25. function Start () {
    26.     var angles = transform.eulerAngles;
    27.     x = angles.y;
    28.     y = angles.x;
    29.  
    30.    // Make the rigid body not change rotation
    31.       if (rigidbody)
    32.       rigidbody.freezeRotation = true;
    33. }
    34.  
    35. function LateUpdate () {
    36.     if(!target)
    37.         return;
    38.    
    39.     // If either mouse buttons are down, let them govern camera position
    40.    if (Input.GetMouseButton(0) || Input.GetMouseButton(1))
    41.    {
    42.     x += Input.GetAxis("Mouse X") * xSpeed * 0.02;
    43.     y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02;
    44.    
    45.     // otherwise, ease behind the target if any of the directional keys are pressed
    46.    } else if(Input.GetAxis("Vertical") || Input.GetAxis("Horizontal")) {
    47.        var targetRotationAngle = target.eulerAngles.y;
    48.        var currentRotationAngle = transform.eulerAngles.y;
    49.        x = Mathf.LerpAngle(currentRotationAngle, targetRotationAngle, rotationDampening * Time.deltaTime);
    50.    }
    51.    
    52.     distance -= (Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime) * zoomRate * Mathf.Abs(distance);
    53.     distance = Mathf.Clamp(distance, minDistance, maxDistance);
    54.    
    55.    y = ClampAngle(y, yMinLimit, yMaxLimit);
    56.    
    57.     var rotation:Quaternion = Quaternion.Euler(y, x, 0);
    58.     var position = target.position - (rotation * Vector3.forward * distance + Vector3(0,-targetHeight,0));
    59.    
    60.     transform.rotation = rotation;
    61.     transform.position = position;
    62. }
    63.  
    64. static function ClampAngle (angle : float, min : float, max : float) {
    65.    if (angle < -360)
    66.       angle += 360;
    67.    if (angle > 360)
    68.       angle -= 360;
    69.    return Mathf.Clamp (angle, min, max);
    70. }
    71.  
     
  12. matrix211v1

    matrix211v1

    Joined:
    Jan 20, 2009
    Posts:
    193
    Paintbrush:

    Actually yes, I got the camera collision detection working. I will try and clean it up and post this weekend.
     
  13. Paintbrush

    Paintbrush

    Joined:
    Apr 1, 2009
    Posts:
    23
    beautiful :) can't wait to see it then!
     
  14. buandaki

    buandaki

    Joined:
    Mar 10, 2009
    Posts:
    23
    Hi,

    I just wanted to say that in a forum with incredibly helpful people, this set of postings stands out as one of the most useful I've read. I've been struggling to get something like the WoW control system working without luck. The code you've posted here works wonderfully and I can't wait to try out the version with collision detection.

    Thank you!!

    Brian
     
  15. Discord

    Discord

    Joined:
    Mar 19, 2009
    Posts:
    1,008
    Just curious, did you ever clean up the version with collision detection?
     
  16. matrix211v1

    matrix211v1

    Joined:
    Jan 20, 2009
    Posts:
    193
    @Paintbrush:

    Sorry for the delay.

    Ok, here is an almost complete version of Wow with camera collision. There are 2 issues.

    1) When the camera hits something, it "instantly" gets behind the player.
    2) The "AdjustLineOfSight" doesn't seem to fire (so if there is a object between the player and camera, it is not moving closer)

    WowCamera.js
    Code (csharp):
    1.  
    2. var target : Transform;
    3.  
    4. var targetHeight = 12.0;
    5. var distance = 5.0;
    6.  
    7. var maxDistance = 20;
    8. var minDistance = 2.5;
    9.  
    10. var xSpeed = 250.0;
    11. var ySpeed = 120.0;
    12.  
    13. var yMinLimit = -20;
    14. var yMaxLimit = 80;
    15.  
    16. var zoomRate = 20;
    17.  
    18. var rotationDampening = 3.0;
    19.  
    20. var theta2 : float = 0.5;
    21.  
    22. private var x = 0.0;
    23. private var y = 0.0;
    24.  
    25. private var fwd = new Vector3();
    26. private var rightVector = new Vector3();
    27. private var upVector = new Vector3();
    28. private var movingVector = new Vector3();
    29. private var collisionVector = new Vector3();
    30. private var isColliding : boolean = false;
    31.    
    32. private var a1 = new Vector3();
    33. private var b1 = new Vector3();
    34. private var c1 = new Vector3();
    35. private var d1 = new Vector3();
    36. private var e1 = new Vector3();
    37. private var f1 = new Vector3();
    38. private var h1 = new Vector3();
    39. private var i1 = new Vector3();
    40.  
    41. @script AddComponentMenu("Camera-Control/WoW Camera")
    42.  
    43. function Start () {
    44.     var angles = transform.eulerAngles;
    45.     x = angles.y;
    46.     y = angles.x;
    47.  
    48.    // Make the rigid body not change rotation
    49.       if (rigidbody)
    50.       rigidbody.freezeRotation = true;
    51. }
    52.  
    53. function LateUpdate () {
    54.    if(!target)
    55.       return;
    56.    
    57.    // If either mouse buttons are down, let them govern camera position
    58.    if (Input.GetMouseButton(0) || Input.GetMouseButton(1))
    59.    {
    60.    x += Input.GetAxis("Mouse X") * xSpeed * 0.02;
    61.    y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02;
    62.    
    63.    // otherwise, ease behind the target if any of the directional keys are pressed
    64.    } else if(Input.GetAxis("Vertical") || Input.GetAxis("Horizontal")) {
    65.       var targetRotationAngle = target.eulerAngles.y;
    66.       var currentRotationAngle = transform.eulerAngles.y;
    67.       x = Mathf.LerpAngle(currentRotationAngle, targetRotationAngle, rotationDampening * Time.deltaTime);
    68.    }
    69.    
    70.    distance -= (Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime) * zoomRate * Mathf.Abs(distance);
    71.    distance = Mathf.Clamp(distance, minDistance, maxDistance);
    72.    
    73.    y = ClampAngle(y, yMinLimit, yMaxLimit);
    74.    
    75.    var rotation:Quaternion = Quaternion.Euler(y, x, 0);
    76.    var position = target.position - (rotation * Vector3.forward * distance + Vector3(0,-targetHeight,0));
    77.    
    78.     // Check to see if we have a collision
    79.     collisionVector = AdjustLineOfSight(transform.position, position);
    80.    
    81.     // Check Line Of Sight
    82.     if (collisionVector != Vector3.zero)
    83.     {
    84.         Debug.Log("Check Line Of Sight");
    85.         a1 = transform.position;
    86.         b1 = position;
    87.         c1 = AdjustLineOfSight(transform.position, position);
    88.         d1 = c1 - a1;
    89.         e1 = d1.normalized * -1;
    90.         f1 = d1 + e1 * 1;
    91.         g1 = f1 + a1;
    92.         position = g1;
    93.  
    94.         // check distance player to camera
    95.         h1 = position - a1;
    96.         if (h1.magnitude < 10)
    97.         {
    98.             position = a1 - fwd * 4;
    99.             //position.y = targetPlayer.y;
    100.             theta2 = theta2 + .25;
    101.         }
    102.        
    103.         // set new camera distance
    104.         h1 = position - a1;
    105.         distance = h1.magnitude;
    106.     }
    107.  
    108.     // check collision
    109.     if (Physics.CheckSphere (position, .5) )
    110.     {
    111.         a1 = transform.position;
    112.        
    113.         newPosition = a1 - fwd * 4;
    114.         //newPosition.y = targetPlayer.y;
    115.         theta2 = theta2 + .25;
    116.        
    117.         // set new camera distance
    118.         h1 = position - a1;
    119.         distance = h1.magnitude;
    120.     }  
    121.    
    122.     //position = Vector3.Slerp(transform.position, position, Time.deltaTime * 100);
    123.    
    124.    transform.rotation = rotation;
    125.    transform.position = position;
    126. }
    127.  
    128. static function ClampAngle (angle : float, min : float, max : float) {
    129.    if (angle < -360)
    130.       angle += 360;
    131.    if (angle > 360)
    132.       angle -= 360;
    133.    return Mathf.Clamp (angle, min, max);
    134. }
    135.  
    136. function AdjustLineOfSight (vecA: Vector3, vecB: Vector3)
    137. {
    138.       var hit: RaycastHit;
    139.      
    140.       if (Physics.Linecast (vecA, vecB, hit))
    141.       {
    142.             Debug.Log("I hit something");
    143.             return hit.point;
    144.       }
    145.      
    146.       return Vector3.zero;
    147. }
    148.  

    WowCharacterController
    Code (csharp):
    1.  
    2. private var jumpSpeed:float = 8.0;
    3. private var gravity:float = 20.0;
    4. private var runSpeed:float = 50.0;
    5. private var walkSpeed:float = 15.0;
    6. private var rotateSpeed:float = 150.0;
    7.  
    8. private var grounded:boolean = false;
    9. private var moveDirection:Vector3 = Vector3.zero;
    10. private var isWalking:boolean = false;
    11. private var moveStatus:String = "idle";
    12. private var jumping:boolean = false;
    13. private var moveSpeed:float = 0.0;
    14.  
    15. function Update ()
    16. {
    17.    // Only allow movement and jumps while grounded
    18.    if(grounded) {
    19.       moveDirection = new Vector3((Input.GetMouseButton(1) ? Input.GetAxis("Horizontal") : 0),0,Input.GetAxis("Vertical"));
    20.        
    21.       // if moving forward and to the side at the same time, compensate for distance
    22.       // TODO: may be better way to do this?
    23.       if(Input.GetMouseButton(1)  Input.GetAxis("Horizontal")  Input.GetAxis("Vertical")) {
    24.          moveDirection *= .7;
    25.       }
    26.        
    27.       moveDirection = transform.TransformDirection(moveDirection);
    28.       moveDirection *= isWalking ? walkSpeed : runSpeed;
    29.        
    30.       moveStatus = "idle";
    31.       if(moveDirection != Vector3.zero)
    32.          moveStatus = isWalking ? "walking" : "running";
    33.        
    34.       // Jump!
    35.       if(Input.GetButton("Jump"))
    36.          moveDirection.y = jumpSpeed;
    37.    }
    38.    
    39.    // Allow turning at anytime. Keep the character facing in the same direction as the Camera if the right mouse button is down.
    40.    if(Input.GetMouseButton(1)) {
    41.       transform.rotation = Quaternion.Euler(0,Camera.main.transform.eulerAngles.y,0);
    42.    } else {
    43.       transform.Rotate(0,Input.GetAxis("Horizontal") * rotateSpeed * Time.deltaTime, 0);
    44.    }
    45.    
    46.    if(Input.GetMouseButton(1) || Input.GetMouseButton(0))
    47.       Screen.lockCursor = true;
    48.    else
    49.       Screen.lockCursor = false;
    50.    
    51.    // Toggle walking/running with the T key
    52.    if(Input.GetAxis("Run") == 1)
    53.       isWalking = !isWalking;
    54.    
    55.    //Apply gravity
    56.    moveDirection.y -= gravity * Time.deltaTime;
    57.    
    58.    //Move controller
    59.    var controller:CharacterController = GetComponent(CharacterController);
    60.    var flags = controller.Move(moveDirection * Time.deltaTime);
    61.    grounded = (flags  CollisionFlags.Below) != 0;
    62. }
    63.  
    64. function GetSpeed () {
    65.     if (moveStatus == "idle")
    66.         moveSpeed = 0;
    67.     if (moveStatus == "walking")
    68.         moveSpeed = walkSpeed;
    69.     if (moveStatus == "running")
    70.         moveSpeed = runSpeed;
    71.     return moveSpeed;
    72. }
    73.  
    74. function IsJumping () {
    75.     return jumping;
    76. }
    77.  
    78. function GetWalkSpeed () {
    79.     return walkSpeed;
    80. }
    81. @script RequireComponent(CharacterController)
    82.  
     
  17. Paintbrush

    Paintbrush

    Joined:
    Apr 1, 2009
    Posts:
    23
    Thanks for the response matrix :)

    I've never actually used raycasting or linecasting before, so your example got me looking into it.

    I think I nailed the WoW camera behaviour this time with the following script... right down to the way the camera lerps based on collision!

    Since the last time I posted, I've switched to using C# to script for Unity. I tried to add as many comments as I could to explain my thought process. As always, I'm welcome to *any* feedback to improve it, be it in coding style, algorithm, or efficiency:

    WowCamera.cs:
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class WowCamera : MonoBehaviour
    6. {
    7.  
    8.     public Transform target;
    9.    
    10.     public float targetHeight = 1.7f;
    11.     public float distance = 5.0f;
    12.  
    13.     public float maxDistance = 20;
    14.     public float minDistance = .6f;
    15.  
    16.     public float xSpeed = 250.0f;
    17.     public float ySpeed = 120.0f;
    18.  
    19.     public int yMinLimit = -80;
    20.     public int yMaxLimit = 80;
    21.  
    22.     public int zoomRate = 40;
    23.  
    24.     public float rotationDampening = 3.0f;
    25.     public float zoomDampening = 5.0f;
    26.  
    27.     private float x = 0.0f;
    28.     private float y = 0.0f;
    29.     private float currentDistance;
    30.     private float desiredDistance;
    31.     private float correctedDistance;
    32.  
    33.     void Start ()
    34.     {
    35.         Vector3 angles = transform.eulerAngles;
    36.         x = angles.x;
    37.         y = angles.y;
    38.  
    39.         currentDistance = distance;
    40.         desiredDistance = distance;
    41.         correctedDistance = distance;
    42.  
    43.         // Make the rigid body not change rotation
    44.         if (rigidbody)
    45.             rigidbody.freezeRotation = true;
    46.     }
    47.    
    48.     /**
    49.      * Camera logic on LateUpdate to only update after all character movement logic has been handled.
    50.      */
    51.     void LateUpdate ()
    52.     {
    53.         // Don't do anything if target is not defined
    54.         if (!target)
    55.             return;
    56.  
    57.         // If either mouse buttons are down, let the mouse govern camera position
    58.         if (Input.GetMouseButton(0) || Input.GetMouseButton(1))
    59.         {
    60.             x += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
    61.             y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
    62.         }
    63.         // otherwise, ease behind the target if any of the directional keys are pressed
    64.         else if (Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0)
    65.         {
    66.             float targetRotationAngle = target.eulerAngles.y;
    67.             float currentRotationAngle = transform.eulerAngles.y;
    68.             x = Mathf.LerpAngle(currentRotationAngle, targetRotationAngle, rotationDampening * Time.deltaTime);
    69.         }
    70.  
    71.         y = ClampAngle(y, yMinLimit, yMaxLimit);
    72.  
    73.         // set camera rotation
    74.         Quaternion rotation = Quaternion.Euler(y, x, 0);
    75.  
    76.         // calculate the desired distance
    77.         desiredDistance -= Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * zoomRate * Mathf.Abs(desiredDistance);
    78.         desiredDistance = Mathf.Clamp(desiredDistance, minDistance, maxDistance);
    79.         correctedDistance = desiredDistance;
    80.  
    81.         // calculate desired camera position
    82.         Vector3 position = target.position - (rotation * Vector3.forward * desiredDistance + new Vector3(0, -targetHeight, 0));
    83.  
    84.         // check for collision using the true target's desired registration point as set by user using height
    85.         RaycastHit collisionHit;
    86.         Vector3 trueTargetPosition = new Vector3(target.position.x, target.position.y + targetHeight, target.position.z);
    87.  
    88.         // if there was a collision, correct the camera position and calculate the corrected distance
    89.         bool isCorrected = false;
    90.         if (Physics.Linecast(trueTargetPosition, position, out collisionHit))
    91.         {
    92.             position = collisionHit.point;
    93.             correctedDistance = Vector3.Distance(trueTargetPosition, position);
    94.             isCorrected = true;
    95.         }
    96.        
    97.         // For smoothing, lerp distance only if either distance wasn't corrected, or correctedDistance is more than currentDistance
    98.         currentDistance = !isCorrected || correctedDistance > currentDistance ? Mathf.Lerp(currentDistance, correctedDistance, Time.deltaTime * zoomDampening) : correctedDistance;
    99.  
    100.         // recalculate position based on the new currentDistance
    101.         position = target.position - (rotation * Vector3.forward * currentDistance + new Vector3(0, -targetHeight, 0));
    102.  
    103.         transform.rotation = rotation;
    104.         transform.position = position;
    105.     }
    106.  
    107.     private static float ClampAngle(float angle, float min, float max)
    108.     {
    109.         if (angle < -360)
    110.             angle += 360;
    111.         if (angle > 360)
    112.             angle -= 360;
    113.         return Mathf.Clamp(angle, min, max);
    114.     }
    115. }
    116.  
    117.  
     
  18. matrix211v1

    matrix211v1

    Joined:
    Jan 20, 2009
    Posts:
    193
    My only problem with this is that it cuts thru the ground (The camera is at the same Y as the terrain, and therefore you see under the ground)

    Which is why I used a

    Code (csharp):
    1. Physics.CheckSphere (position, .5)
    Which gives it a radius of .5, and therefore should "skoot" along the ground and not clip.

    Otherwise you are doing the "exact point" of the collision, which we do not want because the camera frame is taking half the screen depending on where the character is located.
     
  19. Paintbrush

    Paintbrush

    Joined:
    Apr 1, 2009
    Posts:
    23
    well, you've got a 'correctedDistance' variable, all you'd have to do is reduce it a tad and you have that compensation :)
     
  20. matrix211v1

    matrix211v1

    Joined:
    Jan 20, 2009
    Posts:
    193
    Ok. You got an example? Brain is not firing at the moment (had a Army of Blue Ducks that I had to fix)
     
  21. Paintbrush

    Paintbrush

    Joined:
    Apr 1, 2009
    Posts:
    23
    in my code, I assign values in 2 places to the variable 'correctedDistance', one of them conditional on the correction of the value if the linecast detected a collision. subtract some fixed amount from those values to give yourself that buffer.
     
  22. matrix211v1

    matrix211v1

    Joined:
    Jan 20, 2009
    Posts:
    193
    Maybe I'm just brain dead, but subtracting 100 is still not doing anything.

    P.S.
    I had to convert it to JavaScript, sorry!


    Code (csharp):
    1. public var target : Transform;
    2.  
    3. public var targetHeight : float = 1.7;
    4.  
    5. public var distance : float = 5.0;
    6.  
    7. public var maxDistance : float= 20;
    8. public var minDistance : float = .6;
    9.  
    10. public var xSpeed : float = 250.0;
    11. public var ySpeed : float = 120.0;
    12.  
    13. public var yMinLimit : int = -80;
    14. public var yMaxLimit : int = 80;
    15.  
    16. public var zoomRate : int = 40;
    17.  
    18. public var rotationDampening : float = 3.0;
    19. public var zoomDampening : float = 5.0;
    20.  
    21. private var x : float = 0.0;
    22. private var y : float = 0.0;
    23. private var currentDistance : float;
    24. private var desiredDistance : float;
    25. private var correctedDistance : float;
    26.  
    27. function Start ()
    28. {
    29.     var angles : Vector3 = transform.eulerAngles;
    30.     x = angles.x;
    31.     y = angles.y;
    32.    
    33.     currentDistance = distance;
    34.     desiredDistance = distance;
    35.     correctedDistance = distance;
    36.    
    37.     // Make the rigid body not change rotation
    38.     if (rigidbody)
    39.         rigidbody.freezeRotation = true;
    40. }
    41.  
    42. /**
    43.  * Camera logic on LateUpdate to only update after all character movement logic has been handled.
    44.  */
    45. function LateUpdate ()
    46. {
    47.     // Don't do anything if target is not defined
    48.     if (!target)
    49.         return;
    50.    
    51.     // If either mouse buttons are down, let the mouse govern camera position
    52.     if (Input.GetMouseButton(0) || Input.GetMouseButton(1))
    53.     {
    54.         x += Input.GetAxis("Mouse X") * xSpeed * 0.02;
    55.         y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02;
    56.     }
    57.     // otherwise, ease behind the target if any of the directional keys are pressed
    58.     else if (Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0)
    59.     {
    60.         var targetRotationAngle : float = target.eulerAngles.y;
    61.         var currentRotationAngle : float = transform.eulerAngles.y;
    62.         x = Mathf.LerpAngle(currentRotationAngle, targetRotationAngle, rotationDampening * Time.deltaTime);
    63.     }
    64.    
    65.     y = ClampAngle(y, yMinLimit, yMaxLimit);
    66.    
    67.     // set camera rotation
    68.     var rotation : Quaternion = Quaternion.Euler(y, x, 0);
    69.    
    70.     // calculate the desired distance
    71.     desiredDistance -= Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * zoomRate * Mathf.Abs(desiredDistance);
    72.     desiredDistance = Mathf.Clamp(desiredDistance, minDistance, maxDistance);
    73.     correctedDistance = desiredDistance -100;
    74.    
    75.     // calculate desired camera position
    76.     var position : Vector3 = target.position - (rotation * Vector3.forward * desiredDistance + new Vector3(0, -targetHeight, 0));
    77.    
    78.     // check for collision using the true target's desired registration point as set by user using height
    79.     var collisionHit : RaycastHit;
    80.     var trueTargetPosition : Vector3 = new Vector3(target.position.x, target.position.y + targetHeight, target.position.z);
    81.    
    82.     // if there was a collision, correct the camera position and calculate the corrected distance
    83.     var isCorrected : boolean = false;
    84.     if (Physics.Linecast(trueTargetPosition, position, collisionHit))
    85.     {
    86.         position = collisionHit.point;
    87.         correctedDistance = Vector3.Distance(trueTargetPosition, position);
    88.         correctedDistance -= 100;
    89.         isCorrected = true;
    90.     }
    91.    
    92.     // For smoothing, lerp distance only if either distance wasn't corrected, or correctedDistance is more than currentDistance
    93.     currentDistance = !isCorrected || correctedDistance > currentDistance ? Mathf.Lerp(currentDistance, correctedDistance, Time.deltaTime * zoomDampening) : correctedDistance;
    94.    
    95.     // recalculate position based on the new currentDistance
    96.     position = target.position - (rotation * Vector3.forward * currentDistance + new Vector3(0, -targetHeight, 0));
    97.    
    98.     transform.rotation = rotation;
    99.     transform.position = position;
    100. }
    101.  
    102. private static function ClampAngle(_angle : float, _min : float, _max : float) : float
    103. {
    104.     if (_angle < -360)
    105.         _angle += 360;
    106.     if (_angle > 360)
    107.         _angle -= 360;
    108.     return Mathf.Clamp(_angle, _min, _max);
    109. }
     
  23. penman_f13

    penman_f13

    Joined:
    Sep 20, 2007
    Posts:
    5
    Hey all - just a quick thanks for posting these scripts. Very helpful for a project I'm working on. The camera.cs script is super useful!

    Thanks!
     
  24. sandolkakos

    sandolkakos

    Joined:
    Jun 3, 2009
    Posts:
    282
    Hello, everyone, thank you for being sharing their work.

    Someone to solve the problem with the camera in the C# script or in Javascript?
     
  25. zigs

    zigs

    Joined:
    May 27, 2009
    Posts:
    145
    Yes, but you should make a new topic, instead of posting in an old one.
     
  26. markfrancombe

    markfrancombe

    Joined:
    May 26, 2009
    Posts:
    155
    NO NO NO... Pleas continue to write in THIS thread... I know the scripts at the beginning dont completely work, but if you subscribe to a lot of threads to watch the development and learn you NEED some kind of consistancy in how the information that this forum throws up.

    PLEASE remeber, this is NOT chat... its a resource you are building, for those that follow in your footsteps...

    OH.. AND ONE MORE THING:
    Could you clever coders please add the NAME to the script (camera.cs) as a comment actually IN the code at the top, plus author, plus email, plus date??? Just usual programming practice...

    Cheers

    Mark
    Extreme Newbie
     
  27. matrix211v1

    matrix211v1

    Joined:
    Jan 20, 2009
    Posts:
    193
    Actually, these last 2 scripts have turned out quite wonderful! They are used for the MMO I just finished at http://www.bobbersworld.com (it took 4 months of development time with 1 programmer, 1 modeler and 1 texture artist)
     
  28. zigs

    zigs

    Joined:
    May 27, 2009
    Posts:
    145
    broken link my friend :)
     
  29. Tempest

    Tempest

    Joined:
    Dec 10, 2008
    Posts:
    1,286
  30. sandolkakos

    sandolkakos

    Joined:
    Jun 3, 2009
    Posts:
    282
    yes, i too think this.
    --
    about the problem that i am geting in Camera Scripts is:

    WowCamera.js
    Posted for matrix211v1: Fri May 15, 2009 9:17 pm




    Code (csharp):
    1. //WowCamera.js
    2.  
    3. //with test of Collision Correction
    4.  
    5. //Credits to this script: "matrix211v1"
    6.  
    7.  
    8. public var target : Transform;
    9.  
    10. public var targetHeight : float = 1.7;
    11.  
    12. public var distance : float = 5.0;
    13.  
    14. public var maxDistance : float= 20;
    15. public var minDistance : float = .6;
    16.  
    17. public var xSpeed : float = 250.0;
    18. public var ySpeed : float = 120.0;
    19.  
    20. public var yMinLimit : int = -80;
    21. public var yMaxLimit : int = 80;
    22.  
    23. public var zoomRate : int = 40;
    24.  
    25. public var rotationDampening : float = 3.0;
    26. public var zoomDampening : float = 5.0;
    27.  
    28. private var x : float = 0.0;
    29. private var y : float = 0.0;
    30. private var currentDistance : float;
    31. private var desiredDistance : float;
    32. private var correctedDistance : float;
    33.  
    34. function Start ()
    35. {
    36.    var angles : Vector3 = transform.eulerAngles;
    37.    x = angles.x;
    38.    y = angles.y;
    39.    
    40.    currentDistance = distance;
    41.    desiredDistance = distance;
    42.    correctedDistance = distance;
    43.    
    44.    // Make the rigid body not change rotation
    45.    if (rigidbody)
    46.       rigidbody.freezeRotation = true;
    47. }
    48.  
    49. /**
    50.  * Camera logic on LateUpdate to only update after all character movement logic has been handled.
    51.  */
    52. function LateUpdate ()
    53. {
    54.    // Don't do anything if target is not defined
    55.    if (!target)
    56.       return;
    57.    
    58.    // If either mouse buttons are down, let the mouse govern camera position
    59.    if (Input.GetMouseButton(0) || Input.GetMouseButton(1))
    60.    {
    61.       x += Input.GetAxis("Mouse X") * xSpeed * 0.02;
    62.       y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02;
    63.    }
    64.    // otherwise, ease behind the target if any of the directional keys are pressed
    65.    else if (Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0)
    66.    {
    67.       var targetRotationAngle : float = target.eulerAngles.y;
    68.       var currentRotationAngle : float = transform.eulerAngles.y;
    69.       x = Mathf.LerpAngle(currentRotationAngle, targetRotationAngle, rotationDampening * Time.deltaTime);
    70.    }
    71.    
    72.    y = ClampAngle(y, yMinLimit, yMaxLimit);
    73.    
    74.    // set camera rotation
    75.    var rotation : Quaternion = Quaternion.Euler(y, x, 0);
    76.    
    77.    // calculate the desired distance
    78.    desiredDistance -= Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * zoomRate * Mathf.Abs(desiredDistance);
    79.    desiredDistance = Mathf.Clamp(desiredDistance, minDistance, maxDistance);
    80.    correctedDistance = desiredDistance -100;
    81.    
    82.    // calculate desired camera position
    83.    var position : Vector3 = target.position - (rotation * Vector3.forward * desiredDistance + new Vector3(0, -targetHeight, 0));
    84.    
    85.    // check for collision using the true target's desired registration point as set by user using height
    86.    var collisionHit : RaycastHit;
    87.    var trueTargetPosition : Vector3 = new Vector3(target.position.x, target.position.y + targetHeight, target.position.z);
    88.    
    89.    // if there was a collision, correct the camera position and calculate the corrected distance
    90.    var isCorrected : boolean = false;
    91.    if (Physics.Linecast(trueTargetPosition, position, collisionHit))
    92.    {
    93.       position = collisionHit.point;
    94.       correctedDistance = Vector3.Distance(trueTargetPosition, position);
    95.       correctedDistance -= 100;
    96.       isCorrected = true;
    97.    }
    98.    
    99.    // For smoothing, lerp distance only if either distance wasn't corrected, or correctedDistance is more than currentDistance
    100.    currentDistance = !isCorrected || correctedDistance > currentDistance ? Mathf.Lerp(currentDistance, correctedDistance, Time.deltaTime * zoomDampening) : correctedDistance;
    101.    
    102.    // recalculate position based on the new currentDistance
    103.    position = target.position - (rotation * Vector3.forward * currentDistance + new Vector3(0, -targetHeight, 0));
    104.    
    105.    transform.rotation = rotation;
    106.    transform.position = position;
    107. }
    108.  
    109. private static function ClampAngle(_angle : float, _min : float, _max : float) : float
    110. {
    111.    if (_angle < -360)
    112.       _angle += 360;
    113.    if (_angle > 360)
    114.       _angle -= 360;
    115.    return Mathf.Clamp(_angle, _min, _max);
    116. }
    *************
    *************
    *************
    *************
    WowCamera.cs
    Posted for Paintbrush: Thu May 07, 2009 10:05 am


    Please enter in link to see my result of this script.
    http://www.universalgamesonline.com.br/unity3d/studies/wowcamera.cs.html

    Code (csharp):
    1.  
    2. //WowCamera.cs
    3.  
    4. //Credits to this script: "Paintbrush"
    5.  
    6.  
    7. using UnityEngine;
    8. using System.Collections;
    9.  
    10. public class WowCamera : MonoBehaviour
    11. {
    12.  
    13.     public Transform target;
    14.    
    15.     public float targetHeight = 1.7f;
    16.     public float distance = 5.0f;
    17.  
    18.     public float maxDistance = 20;
    19.     public float minDistance = .6f;
    20.  
    21.     public float xSpeed = 250.0f;
    22.     public float ySpeed = 120.0f;
    23.  
    24.     public int yMinLimit = -80;
    25.     public int yMaxLimit = 80;
    26.  
    27.     public int zoomRate = 40;
    28.  
    29.     public float rotationDampening = 3.0f;
    30.     public float zoomDampening = 5.0f;
    31.  
    32.     private float x = 0.0f;
    33.     private float y = 0.0f;
    34.     private float currentDistance;
    35.     private float desiredDistance;
    36.     private float correctedDistance;
    37.  
    38.    void Start ()
    39.     {
    40.         Vector3 angles = transform.eulerAngles;
    41.         x = angles.x;
    42.         y = angles.y;
    43.  
    44.         currentDistance = distance;
    45.         desiredDistance = distance;
    46.         correctedDistance = distance;
    47.  
    48.         // Make the rigid body not change rotation
    49.         if (rigidbody)
    50.             rigidbody.freezeRotation = true;
    51.    }
    52.    
    53.     /**
    54.      * Camera logic on LateUpdate to only update after all character movement logic has been handled.
    55.      */
    56.    void LateUpdate ()
    57.     {
    58.        // Don't do anything if target is not defined
    59.         if (!target)
    60.             return;
    61.  
    62.         // If either mouse buttons are down, let the mouse govern camera position
    63.         if (Input.GetMouseButton(0) || Input.GetMouseButton(1))
    64.         {
    65.             x += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
    66.             y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
    67.         }
    68.         // otherwise, ease behind the target if any of the directional keys are pressed
    69.         else if (Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0)
    70.         {
    71.             float targetRotationAngle = target.eulerAngles.y;
    72.             float currentRotationAngle = transform.eulerAngles.y;
    73.             x = Mathf.LerpAngle(currentRotationAngle, targetRotationAngle, rotationDampening * Time.deltaTime);
    74.         }
    75.  
    76.         y = ClampAngle(y, yMinLimit, yMaxLimit);
    77.  
    78.         // set camera rotation
    79.         Quaternion rotation = Quaternion.Euler(y, x, 0);
    80.  
    81.         // calculate the desired distance
    82.         desiredDistance -= Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * zoomRate * Mathf.Abs(desiredDistance);
    83.         desiredDistance = Mathf.Clamp(desiredDistance, minDistance, maxDistance);
    84.         correctedDistance = desiredDistance;
    85.  
    86.         // calculate desired camera position
    87.         Vector3 position = target.position - (rotation * Vector3.forward * desiredDistance + new Vector3(0, -targetHeight, 0));
    88.  
    89.         // check for collision using the true target's desired registration point as set by user using height
    90.         RaycastHit collisionHit;
    91.         Vector3 trueTargetPosition = new Vector3(target.position.x, target.position.y + targetHeight, target.position.z);
    92.  
    93.         // if there was a collision, correct the camera position and calculate the corrected distance
    94.         bool isCorrected = false;
    95.         if (Physics.Linecast(trueTargetPosition, position, out collisionHit))
    96.         {
    97.             position = collisionHit.point;
    98.             correctedDistance = Vector3.Distance(trueTargetPosition, position);
    99.             isCorrected = true;
    100.         }
    101.        
    102.         // For smoothing, lerp distance only if either distance wasn't corrected, or correctedDistance is more than currentDistance
    103.         currentDistance = !isCorrected || correctedDistance > currentDistance ? Mathf.Lerp(currentDistance, correctedDistance, Time.deltaTime * zoomDampening) : correctedDistance;
    104.  
    105.         // recalculate position based on the new currentDistance
    106.         position = target.position - (rotation * Vector3.forward * currentDistance + new Vector3(0, -targetHeight, 0));
    107.  
    108.         transform.rotation = rotation;
    109.         transform.position = position;
    110.    }
    111.  
    112.     private static float ClampAngle(float angle, float min, float max)
    113.     {
    114.         if (angle < -360)
    115.             angle += 360;
    116.         if (angle > 360)
    117.             angle -= 360;
    118.         return Mathf.Clamp(angle, min, max);
    119.     }
    120. }
    121.  
    122.  
    *************
    *************
    *************
    *************
    WowCamera.js
    Posted for matrix211v1: Sun May 03, 2009 2:48 am


    http://www.universalgamesonline.com.br/unity3d/studies/wowcamera.js.html

    Code (csharp):
    1. //WowCamera.js
    2.  
    3. //When the camera hits something, it "instantly" gets behind the player.
    4.  
    5. //Credits to this script: "matrix211v1"
    6.  
    7. var target : Transform;
    8.  
    9. var targetHeight = 12.0;
    10. var distance = 5.0;
    11.  
    12. var maxDistance = 20;
    13. var minDistance = 2.5;
    14.  
    15. var xSpeed = 250.0;
    16. var ySpeed = 120.0;
    17.  
    18. var yMinLimit = -20;
    19. var yMaxLimit = 80;
    20.  
    21. var zoomRate = 20;
    22.  
    23. var rotationDampening = 3.0;
    24.  
    25. var theta2 : float = 0.5;
    26.  
    27. private var x = 0.0;
    28. private var y = 0.0;
    29.  
    30. private var fwd = new Vector3();
    31. private var rightVector = new Vector3();
    32. private var upVector = new Vector3();
    33. private var movingVector = new Vector3();
    34. private var collisionVector = new Vector3();
    35. private var isColliding : boolean = false;
    36.    
    37. private var a1 = new Vector3();
    38. private var b1 = new Vector3();
    39. private var c1 = new Vector3();
    40. private var d1 = new Vector3();
    41. private var e1 = new Vector3();
    42. private var f1 = new Vector3();
    43. private var h1 = new Vector3();
    44. private var i1 = new Vector3();
    45.  
    46. @script AddComponentMenu("Camera-Control/WoW Camera")
    47.  
    48. function Start () {
    49.     var angles = transform.eulerAngles;
    50.     x = angles.y;
    51.     y = angles.x;
    52.  
    53.    // Make the rigid body not change rotation
    54.       if (rigidbody)
    55.       rigidbody.freezeRotation = true;
    56. }
    57.  
    58. function LateUpdate () {
    59.    if(!target)
    60.       return;
    61.    
    62.    // If either mouse buttons are down, let them govern camera position
    63.    if (Input.GetMouseButton(0) || Input.GetMouseButton(1))
    64.    {
    65.    x += Input.GetAxis("Mouse X") * xSpeed * 0.02;
    66.    y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02;
    67.    
    68.    // otherwise, ease behind the target if any of the directional keys are pressed
    69.    } else if(Input.GetAxis("Vertical") || Input.GetAxis("Horizontal")) {
    70.       var targetRotationAngle = target.eulerAngles.y;
    71.       var currentRotationAngle = transform.eulerAngles.y;
    72.       x = Mathf.LerpAngle(currentRotationAngle, targetRotationAngle, rotationDampening * Time.deltaTime);
    73.    }
    74.    
    75.    distance -= (Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime) * zoomRate * Mathf.Abs(distance);
    76.    distance = Mathf.Clamp(distance, minDistance, maxDistance);
    77.    
    78.    y = ClampAngle(y, yMinLimit, yMaxLimit);
    79.    
    80.    var rotation:Quaternion = Quaternion.Euler(y, x, 0);
    81.    var position = target.position - (rotation * Vector3.forward * distance + Vector3(0,-targetHeight,0));
    82.    
    83.    // Check to see if we have a collision
    84.    collisionVector = AdjustLineOfSight(transform.position, position);
    85.    
    86.    // Check Line Of Sight
    87.    if (collisionVector != Vector3.zero)
    88.    {
    89.       Debug.Log("Check Line Of Sight");
    90.        a1 = transform.position;
    91.       b1 = position;
    92.       c1 = AdjustLineOfSight(transform.position, position);
    93.       d1 = c1 - a1;
    94.       e1 = d1.normalized * -1;
    95.       f1 = d1 + e1 * 1;
    96.       g1 = f1 + a1;
    97.       position = g1;
    98.  
    99.       // check distance player to camera
    100.       h1 = position - a1;
    101.       if (h1.magnitude < 10)
    102.       {
    103.          position = a1 - fwd * 4;
    104.          //position.y = targetPlayer.y;
    105.          theta2 = theta2 + .25;
    106.       }
    107.      
    108.       // set new camera distance
    109.       h1 = position - a1;
    110.       distance = h1.magnitude;
    111.    }
    112.  
    113.    // check collision
    114.    if (Physics.CheckSphere (position, .5) )
    115.    {
    116.        a1 = transform.position;
    117.      
    118.       newPosition = a1 - fwd * 4;
    119.       //newPosition.y = targetPlayer.y;
    120.       theta2 = theta2 + .25;
    121.      
    122.       // set new camera distance
    123.       h1 = position - a1;
    124.       distance = h1.magnitude;
    125.    }  
    126.    
    127.    //position = Vector3.Slerp(transform.position, position, Time.deltaTime * 100);  
    128.    
    129.    transform.rotation = rotation;
    130.    transform.position = position;
    131. }
    132.  
    133. static function ClampAngle (angle : float, min : float, max : float) {
    134.    if (angle < -360)
    135.       angle += 360;
    136.    if (angle > 360)
    137.       angle -= 360;
    138.    return Mathf.Clamp (angle, min, max);
    139. }
    140.  
    141. function AdjustLineOfSight (vecA: Vector3, vecB: Vector3)
    142. {
    143.       var hit: RaycastHit;
    144.    
    145.       if (Physics.Linecast (vecA, vecB, hit))
    146.       {
    147.          Debug.Log("I hit something");
    148.          return hit.point;
    149.       }
    150.      
    151.      return Vector3.zero;
    152. }
    153.  
    154.  
    155.  

    *************
    *************
    *************
    *************
    I thanks all for helps and shares!!!
    And sorry for this BIG Post.


    *************
     
  31. matrix211v1

    matrix211v1

    Joined:
    Jan 20, 2009
    Posts:
    193
    Not sure what the issue is by looking at the screen shot BUT make sure you have your player as your Target in the component editor.
     
  32. sandolkakos

    sandolkakos

    Joined:
    Jun 3, 2009
    Posts:
    282
    yes, my player is in Target of Componet WowCamera Script in my Main Camera.

    thanks for helping.

    i am making images of my errors, of your others Script posted in Sun May 03, 2009 2:48 am
     
  33. markfrancombe

    markfrancombe

    Joined:
    May 26, 2009
    Posts:
    155
    >I think that you are simply not setting up the variables exposed on the WoWCamera component. that I guess you have added to your Camera.

    just adjusting your cameras start position relative to the parented character isnt enough, click your camera, and make the adjustments on the WoWCamera component.

    ALSO:
    Earlier message complained of whacky jumping in the idle state.. I too get this.. I am however NO CODER.. just a dirty mean code stealer.. Was this fixed? Matrix?? Please, Pretty please?

    Also Im getting an error Axis Run not set up. This is because you have a reference to using the T key (line 51) for run. I dont have this setup.. had a look but cant figure it out... I added Run, but then... settings... Hjelp!

    What else? Oh.. just to say that I was V impressed that the mouse wheel affects the distance to character.. nice, genuine touch.

    One thing, to be picky.. Both Left and right mouse buttons do the same. In WoW however Rt mouse steers (same as you have done) but left mouse rotates camera around the character (tis the only way you can see your own face) I think this might auto correct after a while. So left click is more like a camera positioning tool.
     
  34. sandolkakos

    sandolkakos

    Joined:
    Jun 3, 2009
    Posts:
    282
    yes, i have adjusted values of camera, and too have tested modify anythings in scripts, but without sucess.
    ----

    I have posted my error in Page 2, please, if somebody have patience, look my building Web Player that i have posted the Links, in page 2 with the 3 differents scripts used.
     
  35. Michael-Ryan

    Michael-Ryan

    Joined:
    Apr 10, 2009
    Posts:
    184
    The scripts have been pretty helpful in getting a camera setup. I have based by implementation on Paintbrush's C# code, although I'm running into the issue that matrix211v1 reported, and which Paintbrush seemed to have a solution to.

    The camera position is aligned with the surface, so the camera is clipping through. I'd like to have some padding around the camera (0.25) that keeps it away from the geometry it would otherwise clip into.

    I've tried using the CheckSphere(), and while it does detect that it's clipping into geometry, there seems to be no way of determining what it's colliding with, and therefore no easy way of determining the objects direction.

    Should I be adding a Sphere collider on the camera? Or make it a RigidBody so the OnCollisionEnter/OnCollisionStay function? The Linecast has the RaycastHit variable which provides info on the object it collided with, including the surface normal. Is there anyway to get that information without using Raycasts? Or is there some combination of Raycasts and CheckSphere calls that will generate the results I'm looking for?

    I've attached an image for what I'm trying to accomplish (A) versus what I'm currently experiencing (B).
     

    Attached Files:

  36. Mani

    Mani

    Joined:
    Jan 12, 2009
    Posts:
    117
    Thanks for posting this about implementing the camera positions. It's helpful because I'm trying to get to know some more about camera positioning and the details as you walked/thought through it are helpful when I get stuck.
     
  37. MrHyde

    MrHyde

    Joined:
    Mar 23, 2009
    Posts:
    30
    Thanks so much for all of this. It's been a valuable learning experience.

    I've been trying to make it so that when you push down both mouse buttons at the same time, you move forward in the direction that the character is facing. I did manage to get some movement out of it, but it wasn't oriented correctly as the player turned. Does anyone know how this would be accomplished?

    Here's what I've been working with:

    Code (csharp):
    1.       if(Input.GetMouseButton(1)  Input.GetMouseButton(0))
    2.    {     
    3.     forward = transform.TransformDirection(Vector3.forward);
    4.     forward = forward.normalized;
    5.     moveDirection = forward;
    6.     moveDirection = moveDirection.normalized;
    7.    }
    It moves, just not always the direction that the player is facing. :(
     
  38. km

    km

    Joined:
    Mar 20, 2009
    Posts:
    16
    :D
    favorite~
     
  39. Rakdos

    Rakdos

    Joined:
    Jun 4, 2009
    Posts:
    34
    all these scripts are really interresting, i want to make a Real wow camera too but too hard for the poor developper i am :( so if you've any script of that, tell us !!! :D
     
  40. Vimalakirti

    Vimalakirti

    Joined:
    Oct 12, 2009
    Posts:
    755
    Thank you all for this wonderful script. I'm an artist, not a programmer, and this frees me up to do the work that I want to do. Part of that work requires having a free mouse for the player to interact with the environment by clicking on objects, and now I can concentrate on that.

    I am so happy to be part of such a wonderful community of kind, giving people here with Unity. You are all Rock Stars!
     
  41. omoymenya

    omoymenya

    Joined:
    Aug 5, 2009
    Posts:
    18
    I made some changes to the script to fix two problems:

    1. The collision ray was able to hit the character itself, causing the camera to jump wildly if your orbit point was inside the character somewhere.

    2. I was seeing the same problem mryan reported. When your line of sight penetrated a wall, your camera ended up on the wall surface itself. This sometimes caused clipping problems (i.e. if you got close enough to a wall and were looking along it, the camera's near clipping plane would clip the wall, allowing you to see inside it and sometimes completely through to the other side).

    To fix problem 1, I added a collision layer mask. This allows you to avoid hitting yourself by putting your player on its own layer, and then setting the mask to hit everything else BUT the layer you are on.

    As a partial solution to problem 2, I added a small minimum offset distance for the camera from the wall. This solves the problem in most cases. It still fails, however, when your character is really close to the wall. In that case, even with the minimum offset distance, your camera to character ray will be almost parallel to the surface of the wall, and the offset probably won't be enough to prevent clipping.

    The real solution would be, as mryan suggested, to use something like Physics.CheckCapsule. The capsule would be defined with one end at the player, one end at the wall intercept point, and the radius being our minimum wall offset distance. If only CheckCapsule returned a collision list, we could then look through the list, find the closest collision point in the capsule, and move our camera sphere forward so it is just in front of that location. Unfortunately, CheckCapsule only returns a yes or no for collisions. [Could UT add this? Will have to post something on the feature request list.]

    A second way would be to use the surface normal of the wall plus the min offset distance to calculate a camera position just above the wall surface. I tried this, and it doesn't always work. In some cases the new offset position is itself invalid, putting your camera inside a different wall or object. We would have to check the new position to make sure it is valid, and then repeat ad infintum (which obviously we can't afford to do).

    A third way would be to cast let's say four rays spread around the surface of the capsule. We could then use whichever one is closest, and offset the camera a given distance from the closest surface. The downside is this quadruples the number of ray casts and still won't correctly handle all situations.

    Anyway, attached below is my modified version of the C# script:
     

    Attached Files:

  42. Dirck

    Dirck

    Joined:
    Nov 13, 2009
    Posts:
    1
    Works perfectly! Thanks!
     
  43. Standridge

    Standridge

    Joined:
    Nov 14, 2009
    Posts:
    3
    Hi! This script sounds awsome! but when I try to place it on my camera, Unity tells me that I have to fix all the compiling errors before I can use it... Is this a "version" problem? I'm useing Unity 2.5. Thanks!
     
  44. primoadamg

    primoadamg

    Joined:
    Aug 17, 2009
    Posts:
    98
    Thanks a lot for the scripts helped a ton.
     
  45. jojomondag

    jojomondag

    Joined:
    Jan 7, 2010
    Posts:
    1
    Can one get instructions on how to get it to work?

    Im very new to unity but ive been doing 3d for som years and i wanna use this too observe a character ive done. But i dont really know how too attach the script too the camera the right way.

    Greets/jojo
     
  46. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Attaching a script to an object is simply a matter of selecting the object in the editor and then dragging the script onto the inspector panel.
     
  47. omoymenya

    omoymenya

    Joined:
    Aug 5, 2009
    Posts:
    18
    Standridge, it may be a version issue. I am running the latest Unity, v2.6.1. There have been some API changes between the two versions, so, you might want to download 2.6.1 and try it there.
     
  48. Broken-Toy

    Broken-Toy

    Joined:
    Jan 16, 2010
    Posts:
    455
    @omoymenya
    Solid piece of scripting you got there! Is there a way to have it use the target's local axis instead of the world's (so the camera looks ok when the character is, for example, standing upside down on a spherical world)?
     
  49. GrimWare

    GrimWare

    Joined:
    Jul 23, 2009
    Posts:
    211
    Whenever I run the scripts, I'm having problems with the WowCharacterController.js

    Code (csharp):
    1.    // Allow turning at anytime. Keep the character facing in the same direction as the Camera if the right mouse button is down.
    2.    if(Input.GetMouseButton(1)) {
    3.       transform.rotation = Quaternion.Euler(0,Camera.main.transform.eulerAngles.y,0);
    4.    } else {
    5.       transform.Rotate(0,Input.GetAxis("Horizontal") * rotateSpeed * Time.deltaTime, 0);
    6.    }
    7.    
    Holding down the right mouse button does not turn the entity, rather the camera like the left mouse button. This has been mentioned before but no fix that I have seen..

    Any ideas?
     
  50. ksncho

    ksncho

    Joined:
    Jan 19, 2010
    Posts:
    1
    to GrimWare

    I think you should give "MAINCAMERA" tag to your main camera.