Unity3D - Third person
- Get link
- X
- Other Apps
Demonstration of a Camera, Controller and Character for a third person gameplay in a few days.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | using UnityEngine; using System.Collections; public class ControllerTPS : MonoBehaviour { #region Membres // Character private CharacterTPS m_Character = null; #endregion #region MonoBehaviour // Use this for initialization void Start() { // Get character m_Character = gameObject.GetComponent<CharacterTPS>(); } // Update is called once per frame void Update() { // Move character Move(); // Jumping Jump(); } #endregion #region Controller Manipulators /// <summary> /// Move character controller /// </summary> void Move() { Vector3 movement = Vector3.zero; bool sprint = false; // Move forward if (Input.GetKey(KeyCode.Z) || Input.GetKey(KeyCode.UpArrow)) { movement.z++; } // Move backward if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) { movement.z--; } // Strafe left if (Input.GetKey(KeyCode.Q) || Input.GetKey(KeyCode.LeftArrow)) { movement.x--; } // Strafe right if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) { movement.x++; } // Normalize movement vector movement.Normalize(); // Sprint if (Input.GetKey(KeyCode.LeftShift)) { sprint = true; } // Move if (movement != Vector3.zero) { m_Character.Move(movement, sprint); } } /// <summary> /// Manage basically jumping and gravity /// </summary> void Jump() { // Jump on space key if landing if (Input.GetKeyDown(KeyCode.Space)) { m_Character.Jump(); } } #endregion } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | using UnityEngine; using System.Collections; public class CameraTPS : MonoBehaviour { #region Members // Target to look at private CharacterTPS m_Target = null; // Offset public Vector3 m_Offset; // Speed public float m_Speed = 20.0f; public float m_CollideSpeed = 5.0f; public float m_ReturnSpeed = 2.0f; // Timer no movement private const float c_TimeToWait = 1; private float m_Timer = 0; // Camera ray offset public float m_RayOffset = 3.0f; // Camera angle X limits private const float c_AngleXMin = 340.0f; private const float c_AngleXMax = 50.0f; // Angle coefficient for camera replacing public float m_AngleCoefReplacing = 0.1f; #endregion #region MonoBehaviour // Use this for initialization void Start() { // Get Target m_Target = GameObject.Find("Player").GetComponent<CharacterTPS>(); // Offset //m_Offset = new Vector3(0, 2, -4); } // Update is called once per frame void Update() { UpdatePosition(); UpdateRotation(); } #endregion #region Private Camera Manipulators /// <summary> /// Updates the position. /// </summary> private void UpdatePosition() { Vector3 desiredPosition; // Forbid timer to launch if movement if (Input.GetAxis("Mouse Y") != 0.0f || m_Target.IsMoving()) { m_Timer = Time.time; } // If no movement for x seconds if (Time.time > m_Timer + c_TimeToWait) { // Replace camera behind player Replace(); } // Get angles and mouse mouvements Vector3 angles = Vector3.zero; angles.x = transform.eulerAngles.x - Input.GetAxis("Mouse Y") * m_Speed * 0.5f; angles.y = transform.eulerAngles.y + Input.GetAxis("Mouse X") * m_Speed * 0.5f; // Angle x limits if (angles.x >= c_AngleXMax && angles.x < 180) { angles.x = c_AngleXMax; } if (angles.x <= c_AngleXMin && angles.x > 180) { angles.x = c_AngleXMin; } // Convert euler angles in quaternion Quaternion rotation = Quaternion.Euler(angles); // Multiply z axis vector3 with the quaternion Vector3 direction = rotation * Vector3.forward; //direction += m_Target.transform.right * m_Offset.x + m_Target.transform.up * m_Offset.y; // Desired position desiredPosition = m_Target.transform.position + direction * m_Offset.z; // Camera collision Ray raycast = new Ray(m_Target.transform.position, transform.position - m_Target.transform.position); RaycastHit hitLocation; bool isColliding = false; if (Physics.Raycast(raycast, out hitLocation, (transform.position - m_Target.transform.position).magnitude + m_RayOffset)) { isColliding = true; } // If collide, move smoother if (isColliding) { // Position camera transform.position = Vector3.Lerp(transform.position, desiredPosition, Time.deltaTime * m_CollideSpeed); // Recalculate camera position transform.position = Vector3.Lerp(transform.position, hitLocation.point + (transform.forward).normalized * m_RayOffset, Time.deltaTime * m_CollideSpeed); } else { // Position camera transform.position = Vector3.Lerp(transform.position, desiredPosition, Time.deltaTime * m_Speed); } } /// <summary> /// Updates the rotation. /// </summary> private void UpdateRotation() { // Look at player transform.LookAt(m_Target.transform); } #endregion #region Public Camera Manipulators public float GetAngleY() { return transform.eulerAngles.y; } /// <summary> /// Replace camera /// </summary> public void Replace() { // Replace Camera behind character Vector3 desiredPosition = m_Target.transform.position + m_Target.transform.forward * m_Offset.z + m_Target.transform.up * m_Offset.y + m_Target.transform.right * m_Offset.x; // Vector3 from and to position (eliminate Y component for angle calcul on the XZ plane) Vector3 from = new Vector3(transform.position.x, 0, transform.position.z) - new Vector3(m_Target.transform.position.x, 0, m_Target.transform.position.z); Vector3 to = new Vector3(desiredPosition.x, 0, desiredPosition.z) - new Vector3(m_Target.transform.position.x, 0, m_Target.transform.position.z); // Calculate angle float angle = Vector3.Angle(from, to); // Know in which direction rotate if (Vector3.Cross(transform.position - m_Target.transform.position, desiredPosition - m_Target.transform.position).y < 0) { angle = -angle; } // Rotation to perform Quaternion rotation = Quaternion.Euler(0, angle * m_AngleCoefReplacing, 0); // Perform rotation transform.forward = rotation * transform.forward; } #endregion #region DEBUG void OnDrawGizmos() { if (m_Target) { Vector3 from = m_Target.transform.position; Vector3 to = from + (transform.position - m_Target.transform.position) + (transform.position - m_Target.transform.position).normalized * m_RayOffset; Gizmos.DrawLine(from, to); } } #endregion } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | using UnityEngine; using System.Collections; public class CharacterTPS : MonoBehaviour { #region Members // Speed public float m_Speed = 3.0f; public float m_ShiftSpeedCoef = 2.0f; public float m_RotationSpeed = 35.0f; // Jumping public float m_JumpCoef = 2.0f; private float m_JumpTimer = 0; public float m_JumpTimeWait = 0.5f; // Camera private CameraTPS m_Camera = null; // Old position private Vector3 m_OldPosition; // Animations speed public float m_JumpAnimSpeed = 0.3f; public float m_WalkAnimSpeed = 1.4f; public float m_RunAnimSpeed = 0.9f; #endregion #region MonoBehaviour // Use this for initialization void Start() { // Get camera m_Camera = GameObject.Find("Main Camera").GetComponent<CameraTPS>(); // Animations speeds initialization animation["jump_pose"].speed = m_JumpAnimSpeed; animation["walk"].speed = m_WalkAnimSpeed; animation["run"].speed = m_RunAnimSpeed; } // Update is called once per frame void Update() { // Idle animation if not moving if (!IsMoving() && IsOnFloor()) { animation.Play("idle"); } // Store this position as old position for next frame m_OldPosition = transform.position; } #endregion #region Public Manipulators /// <summary> /// Move in direction specified /// </summary> /// <param name="direction">Direction to move</param> /// <param name="sprint">Know if character is sprinting or not</param> public void Move(Vector3 direction, bool sprint) { // Get the same Y angle as camera float angle = Mathf.LerpAngle(transform.eulerAngles.y, m_Camera.GetAngleY(), Time.deltaTime * m_RotationSpeed); // Know if character move backward bool backward = false; // Return character if moving backward if (direction.z < 0) { // Set angle angle = Mathf.LerpAngle(transform.eulerAngles.y, m_Camera.GetAngleY() + 180, Time.deltaTime * m_RotationSpeed); // Move direction.z = 1; // Set backward backward = true; } // Modify character angle Y if (direction.x > 0) { // Move if not moving and rotate of 90° if (direction.z == 0) { // Move direction.z = 1; // Rotate character angle = Mathf.LerpAngle(angle, angle + 90, Time.deltaTime * m_RotationSpeed); } else { // Rotate character if (!backward) angle = Mathf.LerpAngle(angle, angle + 45, Time.deltaTime * m_RotationSpeed); else angle = Mathf.LerpAngle(angle, angle - 45, Time.deltaTime * m_RotationSpeed); } } else if (direction.x < 0) { // Move if not moving and rotate of 90° if (direction.z == 0) { // Move direction.z = 1; // Rotate character angle = Mathf.LerpAngle(angle, angle - 90, Time.deltaTime * m_RotationSpeed); } else { // Rotate character if (!backward) angle = Mathf.LerpAngle(angle, angle - 45, Time.deltaTime * m_RotationSpeed); else angle = Mathf.LerpAngle(angle, angle + 45, Time.deltaTime * m_RotationSpeed); } } // Forbid strafing direction.x = 0; // Rotate character transform.eulerAngles = new Vector3(transform.eulerAngles.x, angle, transform.eulerAngles.z); // Speed float speed = m_Speed; // Speed management if (sprint) { // Sprint speed speed *= m_ShiftSpeedCoef; // Run animation if (!animation.IsPlaying("jump_pose")) { animation.Play("run"); } } else { // Walk animation if (!animation.IsPlaying("jump_pose")) { animation.Play("walk"); } } // Auto-jumping on sprint Vector3 footOffset = new Vector3(0, collider.bounds.size.y * 0.25f, 0); Ray footRay = new Ray(transform.position - footOffset, transform.forward); Ray midRay = new Ray(transform.position, transform.forward); if (sprint) { if (Physics.Raycast(footRay, 1.5f)) { if (!Physics.Raycast(midRay, 1.5f)) { if (CanJump()) Jump(); } } } // Lerp direction direction = Vector3.Lerp(Vector3.zero, direction * speed, Time.deltaTime); // Move //transform.Translate(direction); rigidbody.MovePosition(rigidbody.position + transform.rotation * direction); } /// <summary> /// Jumping management /// </summary> public void Jump() { // Check character is on floor if (IsOnFloor()) { // Set force to UP rigidbody.AddForce(0, 100 * m_JumpCoef, 0); // Play jump animation animation.Play("jump_pose"); // Jump timer (force auto-jumping to do ONE jump only) m_JumpTimer = Time.time; } } /// <summary> /// Know if character is moving /// </summary> /// <returns>True if character is moving, False otherwise</returns> public bool IsMoving() { return transform.position != m_OldPosition; } #endregion #region Private Manipulators /// <summary> /// Know if character is ont the floor /// </summary> /// <returns>True if on the floor, False otherwise</returns> bool IsOnFloor() { // Ray cast from character to under its foots Vector3 origin = new Vector3(transform.position.x, transform.position.y, transform.position.z); Vector3 direction = -transform.up; Ray raycast = new Ray(origin, direction); return Physics.Raycast(raycast, collider.bounds.size.y * 0.55f); } /// <summary> /// Determines whether this instance can jump. /// </summary> /// <returns><c>true</c> if this instance can jump; otherwise, <c>false</c>.</returns> bool CanJump() { return IsOnFloor() && Time.time > m_JumpTimer + m_JumpTimeWait; } #endregion #region DEBUG void OnDrawGizmos() { Vector3 origin = new Vector3(transform.position.x, transform.position.y, transform.position.z); Vector3 direction = -transform.up; Gizmos.DrawLine(origin, origin + direction * collider.bounds.size.y * 0.55f); } #endregion } |
Comments
Post a Comment