1: using UnityEngine;
2: using System.Collections;
3: public class ThirdPersonCamera : MonoBehaviour {
4: Transform cameraTransform;
5: private Transform _target;
6: // The distance in the x-z plane to the target
7: public float distance = 7.0f;
8: // the height we want the camera to be above the target
9: public float height = 3.0f;
10: public float angularSmoothLag = 0.3f;
11: public float angularMaxSpeed = 15.0f;
12: public float heightSmoothLag = 0.3f;
13: public float snapSmoothLag = 0.2f;
14: public float snapMaxSpeed = 720.0f;
15: public float clampHeadPositionScreenSpace = 0.75f;
16: public float lockCameraTimeout = 0.2f;
17: private Vector3 headOffset = Vector3.zero;
18: private Vector3 centerOffset = Vector3.zero;
19: private float heightVelocity = 0.0f;
20: private float angleVelocity = 0.0f;
21: private bool snap = false;
22: private ThirdPersonController controller;
23: private float targetHeight = 100000.0f;
24: void Awake ()
25: {
26: if(!cameraTransform && Camera.main)
27: cameraTransform = Camera.main.transform;
28: if(!cameraTransform) {
29: Debug.Log("Please assign a camera to the ThirdPersonCamera script.");
30: enabled = false;
31: }
32: _target = transform;
33: if (_target)
34: {
35: controller = _target.GetComponent <ThirdPersonController> ();
36: }
37: if (controller)
38: {
39: Collider characterController = _target.GetComponent <Collider> ();
40: centerOffset = characterController.bounds.center - _target.position;
41: headOffset = centerOffset;
42: headOffset.y = characterController.bounds.max.y - _target.position.y;
43: }
44: else
45: Debug.Log("Please assign a target to the camera that has a ThirdPersonController script attached.");
46: Cut(_target, centerOffset);
47: }
48: float AngleDistance (float a, float b)
49: {
50: a = Mathf.Repeat(a, 360);
51: b = Mathf.Repeat(b, 360);
52: return Mathf.Abs(b - a);
53: }
54: void DebugDrawStuff ()
55: {
56: Debug.DrawLine(_target.position, _target.position + headOffset);
57: }
58: void Apply (Transform dummyTarget , Vector3 dummyCenter)
59: {
60: // Early out if we don't have a target
61: if (!controller)
62: return;
63: Vector3 targetCenter = _target.position + centerOffset;
64: Vector3 targetHead = _target.position + headOffset;
65: // DebugDrawStuff();
66: // Calculate the current & target rotation angles
67: float originalTargetAngle = _target.eulerAngles.y;
68: float currentAngle = cameraTransform.eulerAngles.y;
69: // Adjust real target angle when camera is locked
70: float targetAngle = originalTargetAngle;
71: // When pressing Fire2 (alt) the camera will snap to the target direction real quick.
72: // It will stop snapping when it reaches the target
73: if (Input.GetButton("Fire2"))
74: snap = true;
75: if (snap)
76: {
77: // We are close to the target, so we can stop snapping now!
78: if (AngleDistance (currentAngle, originalTargetAngle) < 3.0)
79: snap = false;
80: currentAngle = Mathf.SmoothDampAngle(currentAngle, targetAngle, ref angleVelocity, snapSmoothLag, snapMaxSpeed);
81: }
82: // Normal camera motion
83: else
84: {
85: if (controller.GetLockCameraTimer () < lockCameraTimeout)
86: {
87: targetAngle = currentAngle;
88: }
89: // Lock the camera when moving backwards!
90: // * It is really confusing to do 180 degree spins when turning around.
91: if (AngleDistance (currentAngle, targetAngle) > 160 && controller.IsMovingBackwards ())
92: targetAngle += 180;
93: currentAngle = Mathf.SmoothDampAngle(currentAngle, targetAngle, ref angleVelocity, angularSmoothLag, angularMaxSpeed);
94: }
95: // When jumping don't move camera upwards but only down!
96: if (controller.IsJumping ())
97: {
98: // We'd be moving the camera upwards, do that only if it's really high
99: float newTargetHeight = targetCenter.y + height;
100: if (newTargetHeight < targetHeight || newTargetHeight - targetHeight > 5)
101: targetHeight = targetCenter.y + height;
102: }
103: // When walking always update the target height
104: else
105: {
106: targetHeight = targetCenter.y + height;
107: }
108: // Damp the height
109: float currentHeight = cameraTransform.position.y;
110: currentHeight = Mathf.SmoothDamp (currentHeight, targetHeight, ref heightVelocity, heightSmoothLag);
111: // Convert the angle into a rotation, by which we then reposition the camera
112: Quaternion currentRotation = Quaternion.Euler (0, currentAngle, 0);
113: // Set the position of the camera on the x-z plane to:
114: // distance meters behind the target
115: cameraTransform.position = targetCenter;
116: cameraTransform.position += currentRotation * Vector3.back * distance;
117: // Set the height of the camera
118: cameraTransform.position = new Vector3 (cameraTransform.position.x,currentHeight,cameraTransform.position.z);
119: // Always look at the target
120: SetUpRotation(targetCenter, targetHead);
121: }
122: void Cut (Transform dummyTarget, Vector3 dummyCenter)
123: {
124: float oldHeightSmooth = heightSmoothLag;
125: float oldSnapMaxSpeed = snapMaxSpeed;
126: float oldSnapSmooth = snapSmoothLag;
127: snapMaxSpeed = 10000;
128: snapSmoothLag = 0.001f;
129: heightSmoothLag = 0.001f;
130: snap = true;
131: Apply (transform, Vector3.zero);
132: heightSmoothLag = oldHeightSmooth;
133: snapMaxSpeed = oldSnapMaxSpeed;
134: snapSmoothLag = oldSnapSmooth;
135: }
136: void SetUpRotation (Vector3 centerPos, Vector3 headPos)
137: {
138: // Now it's getting hairy. The devil is in the details here, the big issue is jumping of course.
139: // * When jumping up and down we don't want to center the guy in screen space.
140: // This is important to give a feel for how high you jump and avoiding large camera movements.
141: //
142: // * At the same time we dont want him to ever go out of screen and we want all rotations to be totally smooth.
143: //
144: // So here is what we will do:
145: //
146: // 1. We first find the rotation around the y axis. Thus he is always centered on the y-axis
147: // 2. When grounded we make him be centered
148: // 3. When jumping we keep the camera rotation but rotate the camera to get him back into view if his head is above some threshold
149: // 4. When landing we smoothly interpolate towards centering him on screen
150: Vector3 cameraPos = cameraTransform.position;
151: Vector3 offsetToCenter = centerPos - cameraPos;
152: // Generate base rotation only around y-axis
153: Quaternion yRotation = Quaternion.LookRotation(new Vector3(offsetToCenter.x, 0, offsetToCenter.z));
154: Vector3 relativeOffset = Vector3.forward * distance + Vector3.down * height;
155: cameraTransform.rotation = yRotation * Quaternion.LookRotation(relativeOffset);
156: // Calculate the projected center position and top position in world space
157: Ray centerRay = cameraTransform.GetComponent <Camera>().ViewportPointToRay(new Vector3(0.5f, 0.5f, 1));
158: Ray topRay = cameraTransform.GetComponent <Camera>().ViewportPointToRay(new Vector3(0.5f, clampHeadPositionScreenSpace, 1));
159: Vector3 centerRayPos = centerRay.GetPoint(distance);
160: Vector3 topRayPos = topRay.GetPoint(distance);
161: float centerToTopAngle = Vector3.Angle(centerRay.direction, topRay.direction);
162: float heightToAngle = centerToTopAngle / (centerRayPos.y - topRayPos.y);
163: float extraLookAngle = heightToAngle * (centerRayPos.y - centerPos.y);
164: if (extraLookAngle < centerToTopAngle)
165: {
166: extraLookAngle = 0;
167: }
168: else
169: {
170: extraLookAngle = extraLookAngle - centerToTopAngle;
171: cameraTransform.rotation *= Quaternion.Euler(-extraLookAngle, 0, 0);
172: }
173: }
174: Vector3 GetCenterOffset ()
175: {
176: return centerOffset;
177: }
178: // Use this for initialization
179: void Start () {
180: }
181: // Update is called once per frame
182: void Update () {
183: }
184: void LateUpdate () {
185: Apply (transform, Vector3.zero);
186: }
187: }
mercredi 23 septembre 2015
Unity ThirdPersonCamera.js to ThirdPersonCamera.cs
S'abonner à :
Publier des commentaires (Atom)
Aucun commentaire:
Publier un commentaire