标签:
将官方自带的角色控制器脚本,改写为C#版,以下为所有代码:
CharacterMotor.cs 主要设置角色控制的系数,如运动,跳跃,移动,滑动等。第一人称与第三人称主角模型的移动与旋转的角度最后都是在这里计算的。
CharacterMotor.cs 代码:
1 using UnityEngine; 2 using System.Collections; 3 4 /** 5 *主要设置角色控制的系数,如运动,跳跃,移动,滑动等。第一人称与第三人称主角模型的移动与旋转的角度最后都是在这里计算的。 6 */ 7 8 [RequireComponent(typeof(CharacterController))] 9 [AddComponentMenu("Character/Character Motor")] 10 11 public class CharacterMotor : MonoBehaviour { 12 13 // Does this script currently respond to input? 14 public bool canControl = true; 15 16 public bool useFixedUpdate = true; 17 18 // For the next variables, @System.NonSerialized tells Unity to not serialize the variable or show it in the inspector view. 19 // Very handy for organization! 20 21 // The current global direction we want the character to move in. 22 [System.NonSerialized] 23 public Vector3 inputMoveDirection = Vector3.zero; 24 25 // Is the jump button held down? We use this interface instead of checking 26 // for the jump button directly so this script can also be used by AIs. 27 [System.NonSerialized] 28 public bool inputJump = false; 29 30 [System.Serializable] 31 public class CharacterMotorMovement 32 { 33 34 // The maximum horizontal speed when moving 35 public float maxForwardSpeed = 10.0f; 36 public float maxSidewaysSpeed = 10.0f; 37 public float maxBackwardsSpeed = 10.0f; 38 39 // Curve for multiplying speed based on slope (negative = downwards) 40 public AnimationCurve slopeSpeedMultiplier = new AnimationCurve(new Keyframe(-90, 1), new Keyframe(0, 1), new Keyframe(90, 0)); 41 42 // How fast does the character change speeds? Higher is faster. 43 public float maxGroundAcceleration = 30.0f; 44 public float maxAirAcceleration = 20.0f; 45 46 // The gravity for the character 47 public float gravity = 10.0f; 48 public float maxFallSpeed = 20.0f; 49 50 // For the next variables, @System.NonSerialized tells Unity to not serialize the variable or show it in the inspector view. 51 // Very handy for organization! 52 53 // The last collision flags returned from controller.Move 54 [System.NonSerialized] 55 public CollisionFlags collisionFlags; 56 57 // We will keep track of the character‘s current velocity, 58 [System.NonSerialized] 59 public Vector3 velocity; 60 61 // This keeps track of our current velocity while we‘re not grounded 62 [System.NonSerialized] 63 public Vector3 frameVelocity = Vector3.zero; 64 65 [System.NonSerialized] 66 public Vector3 hitPoint = Vector3.zero; 67 68 [System.NonSerialized] 69 public Vector3 lastHitPoint = new Vector3(Mathf.Infinity, 0, 0); 70 } 71 72 public CharacterMotorMovement movement = new CharacterMotorMovement(); 73 74 public enum MovementTransferOnJump { 75 None, // The jump is not affected by velocity of floor at all. 76 InitTransfer, // Jump gets its initial velocity from the floor, then gradualy comes to a stop. 77 PermaTransfer, // Jump gets its initial velocity from the floor, and keeps that velocity until landing. 78 PermaLocked // Jump is relative to the movement of the last touched floor and will move together with that floor. 79 } 80 81 // We will contain all the jumping related variables in one helper class for clarity. 82 [System.Serializable] 83 public class CharacterMotorJumping { 84 // Can the character jump? 85 public bool enabled = true; 86 87 // How high do we jump when pressing jump and letting go immediately 88 public float baseHeight = 1.0f; 89 90 // We add extraHeight units (meters) on top when holding the button down longer while jumping 91 public float extraHeight = 4.1f; 92 93 // How much does the character jump out perpendicular to the surface on walkable surfaces? 94 // 0 means a fully vertical jump and 1 means fully perpendicular. 95 public float perpAmount = 0.0f; 96 97 // How much does the character jump out perpendicular to the surface on too steep surfaces? 98 // 0 means a fully vertical jump and 1 means fully perpendicular. 99 public float steepPerpAmount = 0.5f; 100 101 // For the next variables, @System.NonSerialized tells Unity to not serialize the variable or show it in the inspector view. 102 // Very handy for organization! 103 104 // Are we jumping? (Initiated with jump button and not grounded yet) 105 // To see if we are just in the air (initiated by jumping OR falling) see the grounded variable. 106 [System.NonSerialized] 107 public bool jumping = false; 108 109 [System.NonSerialized] 110 public bool holdingJumpButton = false; 111 112 // the time we jumped at (Used to determine for how long to apply extra jump power after jumping.) 113 [System.NonSerialized] 114 public float lastStartTime = 0.0f; 115 116 [System.NonSerialized] 117 public float lastButtonDownTime = -100f; 118 119 [System.NonSerialized] 120 public Vector3 jumpDir = Vector3.up; 121 } 122 123 public CharacterMotorJumping jumping = new CharacterMotorJumping(); 124 125 [System.Serializable] 126 public class CharacterMotorMovingPlatform { 127 public bool enabled = true; 128 129 public MovementTransferOnJump movementTransfer = MovementTransferOnJump.PermaTransfer; 130 131 [System.NonSerialized] 132 public Transform hitPlatform; 133 134 [System.NonSerialized] 135 public Transform activePlatform; 136 137 [System.NonSerialized] 138 public Vector3 activeLocalPoint; 139 140 [System.NonSerialized] 141 public Vector3 activeGlobalPoint; 142 143 [System.NonSerialized] 144 public Quaternion activeLocalRotation; 145 146 [System.NonSerialized] 147 public Quaternion activeGlobalRotation; 148 149 [System.NonSerialized] 150 public Matrix4x4 lastMatrix; 151 152 [System.NonSerialized] 153 public Vector3 platformVelocity; 154 155 [System.NonSerialized] 156 public bool newPlatform; 157 } 158 159 public CharacterMotorMovingPlatform movingPlatform = new CharacterMotorMovingPlatform(); 160 161 [System.Serializable] 162 public class CharacterMotorSliding { 163 // Does the character slide on too steep surfaces? 164 public bool enabled = true; 165 166 // How fast does the character slide on steep surfaces? 167 public float slidingSpeed = 15f; 168 169 // How much can the player control the sliding direction? 170 // If the value is 0.5 the player can slide sideways with half the speed of the downwards sliding speed. 171 public float sidewaysControl = 1.0f; 172 173 // How much can the player influence the sliding speed? 174 // If the value is 0.5 the player can speed the sliding up to 150% or slow it down to 50%. 175 public float speedControl = 0.4f; 176 } 177 178 public CharacterMotorSliding sliding = new CharacterMotorSliding(); 179 180 [System.NonSerialized] 181 public bool grounded = true; 182 183 [System.NonSerialized] 184 public Vector3 groundNormal = Vector3.zero; 185 186 private Vector3 lastGroundNormal = Vector3.zero; 187 188 private Transform tr; 189 190 private CharacterController controller ; 191 192 void Awake () { 193 controller = GetComponent <CharacterController>(); 194 tr = transform; 195 } 196 197 //======================================================= 198 private void UpdateFunction () { 199 // We copy the actual velocity into a temporary variable that we can manipulate. 200 Vector3 velocity = movement.velocity; 201 202 // Update velocity based on input 203 velocity = ApplyInputVelocityChange(velocity); 204 205 // Apply gravity and jumping force 206 velocity = ApplyGravityAndJumping (velocity); 207 208 // Moving platform support 209 Vector3 moveDistance = Vector3.zero; 210 if (MoveWithPlatform()) { 211 Vector3 newGlobalPoint = movingPlatform.activePlatform.TransformPoint(movingPlatform.activeLocalPoint); 212 moveDistance = (newGlobalPoint - movingPlatform.activeGlobalPoint); 213 if (moveDistance != Vector3.zero) 214 controller.Move(moveDistance); 215 216 // Support moving platform rotation as well: 217 Quaternion newGlobalRotation = movingPlatform.activePlatform.rotation * movingPlatform.activeLocalRotation; 218 Quaternion rotationDiff = newGlobalRotation * Quaternion.Inverse(movingPlatform.activeGlobalRotation); 219 220 var yRotation = rotationDiff.eulerAngles.y; 221 if (yRotation != 0) { 222 // Prevent rotation of the local up vector 223 tr.Rotate(0, yRotation, 0); 224 } 225 } 226 227 // Save lastPosition for velocity calculation. 228 Vector3 lastPosition = tr.position; 229 230 // We always want the movement to be framerate independent. Multiplying by Time.deltaTime does this. 231 Vector3 currentMovementOffset = velocity * Time.deltaTime; 232 233 // Find out how much we need to push towards the ground to avoid loosing grouning 234 // when walking down a step or over a sharp change in slope. 235 float pushDownOffset = Mathf.Max(controller.stepOffset, new Vector3(currentMovementOffset.x, 0, currentMovementOffset.z).magnitude); 236 if (grounded) 237 currentMovementOffset -= pushDownOffset * Vector3.up; 238 239 // Reset variables that will be set by collision function 240 movingPlatform.hitPlatform = null; 241 groundNormal = Vector3.zero; 242 243 // Move our character! 244 movement.collisionFlags = controller.Move (currentMovementOffset); 245 246 movement.lastHitPoint = movement.hitPoint; 247 lastGroundNormal = groundNormal; 248 249 if (movingPlatform.enabled && movingPlatform.activePlatform != movingPlatform.hitPlatform) { 250 if (movingPlatform.hitPlatform != null) { 251 movingPlatform.activePlatform = movingPlatform.hitPlatform; 252 movingPlatform.lastMatrix = movingPlatform.hitPlatform.localToWorldMatrix; 253 movingPlatform.newPlatform = true; 254 } 255 } 256 257 // Calculate the velocity based on the current and previous position. 258 // This means our velocity will only be the amount the character actually moved as a result of collisions. 259 Vector3 oldHVelocity = new Vector3(velocity.x, 0, velocity.z); 260 movement.velocity = (tr.position - lastPosition) / Time.deltaTime; 261 Vector3 newHVelocity = new Vector3(movement.velocity.x, 0, movement.velocity.z); 262 263 // The CharacterController can be moved in unwanted directions when colliding with things. 264 // We want to prevent this from influencing the recorded velocity. 265 if (oldHVelocity == Vector3.zero) { 266 movement.velocity = new Vector3(0, movement.velocity.y, 0); 267 } 268 else { 269 float projectedNewVelocity = Vector3.Dot(newHVelocity, oldHVelocity) / oldHVelocity.sqrMagnitude; 270 movement.velocity = oldHVelocity * Mathf.Clamp01(projectedNewVelocity) + movement.velocity.y * Vector3.up; 271 } 272 273 if (movement.velocity.y < velocity.y - 0.001) { 274 if (movement.velocity.y < 0) { 275 // Something is forcing the CharacterController down faster than it should. 276 // Ignore this 277 movement.velocity.y = velocity.y; 278 } 279 else { 280 // The upwards movement of the CharacterController has been blocked. 281 // This is treated like a ceiling collision - stop further jumping here. 282 jumping.holdingJumpButton = false; 283 } 284 } 285 286 // We were grounded but just loosed grounding 287 if (grounded && !IsGroundedTest()) { 288 grounded = false; 289 290 // Apply inertia from platform 291 if (movingPlatform.enabled && 292 (movingPlatform.movementTransfer == MovementTransferOnJump.InitTransfer || 293 movingPlatform.movementTransfer == MovementTransferOnJump.PermaTransfer) 294 ) { 295 movement.frameVelocity = movingPlatform.platformVelocity; 296 movement.velocity += movingPlatform.platformVelocity; 297 } 298 299 SendMessage("OnFall", SendMessageOptions.DontRequireReceiver); 300 // We pushed the character down to ensure it would stay on the ground if there was any. 301 // But there wasn‘t so now we cancel the downwards offset to make the fall smoother. 302 tr.position += pushDownOffset * Vector3.up; 303 } 304 // We were not grounded but just landed on something 305 else if (!grounded && IsGroundedTest()) { 306 grounded = true; 307 jumping.jumping = false; 308 SubtractNewPlatformVelocity(); 309 310 SendMessage("OnLand", SendMessageOptions.DontRequireReceiver); 311 } 312 313 // Moving platforms support 314 if (MoveWithPlatform()) { 315 // Use the center of the lower half sphere of the capsule as reference point. 316 // This works best when the character is standing on moving tilting platforms. 317 movingPlatform.activeGlobalPoint = tr.position + Vector3.up * (controller.center.y - controller.height*0.5f + controller.radius); 318 movingPlatform.activeLocalPoint = movingPlatform.activePlatform.InverseTransformPoint(movingPlatform.activeGlobalPoint); 319 320 // Support moving platform rotation as well: 321 movingPlatform.activeGlobalRotation = tr.rotation; 322 movingPlatform.activeLocalRotation = Quaternion.Inverse(movingPlatform.activePlatform.rotation) * movingPlatform.activeGlobalRotation; 323 } 324 } 325 326 void FixedUpdate () { 327 if (movingPlatform.enabled) { 328 if (movingPlatform.activePlatform != null) { 329 if (!movingPlatform.newPlatform) { 330 Vector3 lastVelocity = movingPlatform.platformVelocity; 331 332 movingPlatform.platformVelocity = ( 333 movingPlatform.activePlatform.localToWorldMatrix.MultiplyPoint3x4(movingPlatform.activeLocalPoint) 334 - movingPlatform.lastMatrix.MultiplyPoint3x4(movingPlatform.activeLocalPoint) 335 ) / Time.deltaTime; 336 } 337 movingPlatform.lastMatrix = movingPlatform.activePlatform.localToWorldMatrix; 338 movingPlatform.newPlatform = false; 339 } 340 else { 341 movingPlatform.platformVelocity = Vector3.zero; 342 } 343 } 344 345 if (useFixedUpdate) 346 UpdateFunction(); 347 } 348 349 void Update () { 350 if (!useFixedUpdate) 351 UpdateFunction(); 352 } 353 354 private Vector3 ApplyInputVelocityChange (Vector3 velocity) { 355 if (!canControl) 356 inputMoveDirection = Vector3.zero; 357 358 // Find desired velocity 359 Vector3 desiredVelocity; 360 if (grounded && TooSteep()) { 361 // The direction we‘re sliding in 362 desiredVelocity = new Vector3(groundNormal.x, 0, groundNormal.z).normalized; 363 // Find the input movement direction projected onto the sliding direction 364 var projectedMoveDir = Vector3.Project(inputMoveDirection, desiredVelocity); 365 // Add the sliding direction, the spped control, and the sideways control vectors 366 desiredVelocity = desiredVelocity + projectedMoveDir * sliding.speedControl + (inputMoveDirection - projectedMoveDir) * sliding.sidewaysControl; 367 // Multiply with the sliding speed 368 desiredVelocity *= sliding.slidingSpeed; 369 } 370 else 371 desiredVelocity = GetDesiredHorizontalVelocity(); 372 373 if (movingPlatform.enabled && movingPlatform.movementTransfer == MovementTransferOnJump.PermaTransfer) { 374 desiredVelocity += movement.frameVelocity; 375 desiredVelocity.y = 0; 376 } 377 378 if (grounded) 379 desiredVelocity = AdjustGroundVelocityToNormal(desiredVelocity, groundNormal); 380 else 381 velocity.y = 0; 382 383 // Enforce max velocity change 384 float maxVelocityChange = GetMaxAcceleration(grounded) * Time.deltaTime; 385 Vector3 velocityChangeVector = (desiredVelocity - velocity); 386 if (velocityChangeVector.sqrMagnitude > maxVelocityChange * maxVelocityChange) { 387 velocityChangeVector = velocityChangeVector.normalized * maxVelocityChange; 388 } 389 // If we‘re in the air and don‘t have control, don‘t apply any velocity change at all. 390 // If we‘re on the ground and don‘t have control we do apply it - it will correspond to friction. 391 if (grounded || canControl) 392 velocity += velocityChangeVector; 393 394 if (grounded) { 395 // When going uphill, the CharacterController will automatically move up by the needed amount. 396 // Not moving it upwards manually prevent risk of lifting off from the ground. 397 // When going downhill, DO move down manually, as gravity is not enough on steep hills. 398 velocity.y = Mathf.Min(velocity.y, 0); 399 } 400 401 return velocity; 402 } 403 404 private Vector3 ApplyGravityAndJumping (Vector3 velocity) { 405 406 if (!inputJump || !canControl) { 407 jumping.holdingJumpButton = false; 408 jumping.lastButtonDownTime = -100; 409 } 410 411 if (inputJump && jumping.lastButtonDownTime < 0 && canControl) 412 jumping.lastButtonDownTime = Time.time; 413 414 if (grounded) 415 velocity.y = Mathf.Min(0, velocity.y) - movement.gravity * Time.deltaTime; 416 else { 417 velocity.y = movement.velocity.y - movement.gravity * Time.deltaTime; 418 419 // When jumping up we don‘t apply gravity for some time when the user is holding the jump button. 420 // This gives more control over jump height by pressing the button longer. 421 if (jumping.jumping && jumping.holdingJumpButton) { 422 // Calculate the duration that the extra jump force should have effect. 423 // If we‘re still less than that duration after the jumping time, apply the force. 424 if (Time.time < jumping.lastStartTime + jumping.extraHeight / CalculateJumpVerticalSpeed(jumping.baseHeight)) { 425 // Negate the gravity we just applied, except we push in jumpDir rather than jump upwards. 426 velocity += jumping.jumpDir * movement.gravity * Time.deltaTime; 427 } 428 } 429 430 // Make sure we don‘t fall any faster than maxFallSpeed. This gives our character a terminal velocity. 431 velocity.y = Mathf.Max (velocity.y, -movement.maxFallSpeed); 432 } 433 434 if (grounded) { 435 // Jump only if the jump button was pressed down in the last 0.2 seconds. 436 // We use this check instead of checking if it‘s pressed down right now 437 // because players will often try to jump in the exact moment when hitting the ground after a jump 438 // and if they hit the button a fraction of a second too soon and no new jump happens as a consequence, 439 // it‘s confusing and it feels like the game is buggy. 440 if (jumping.enabled && canControl && (Time.time - jumping.lastButtonDownTime < 0.2)) { 441 grounded = false; 442 jumping.jumping = true; 443 jumping.lastStartTime = Time.time; 444 jumping.lastButtonDownTime = -100; 445 jumping.holdingJumpButton = true; 446 447 // Calculate the jumping direction 448 if (TooSteep()) 449 jumping.jumpDir = Vector3.Slerp(Vector3.up, groundNormal, jumping.steepPerpAmount); 450 else 451 jumping.jumpDir = Vector3.Slerp(Vector3.up, groundNormal, jumping.perpAmount); 452 453 // Apply the jumping force to the velocity. Cancel any vertical velocity first. 454 velocity.y = 0; 455 velocity += jumping.jumpDir * CalculateJumpVerticalSpeed (jumping.baseHeight); 456 457 // Apply inertia from platform 458 if (movingPlatform.enabled && 459 (movingPlatform.movementTransfer == MovementTransferOnJump.InitTransfer || 460 movingPlatform.movementTransfer == MovementTransferOnJump.PermaTransfer) 461 ) { 462 movement.frameVelocity = movingPlatform.platformVelocity; 463 velocity += movingPlatform.platformVelocity; 464 } 465 466 SendMessage("OnJump", SendMessageOptions.DontRequireReceiver); 467 } 468 else { 469 jumping.holdingJumpButton = false; 470 } 471 } 472 473 return velocity; 474 } 475 476 void OnControllerColliderHit (ControllerColliderHit hit) { 477 if (hit.normal.y > 0 && hit.normal.y > groundNormal.y && hit.moveDirection.y < 0) { 478 if ((hit.point - movement.lastHitPoint).sqrMagnitude > 0.001 || lastGroundNormal == Vector3.zero) 479 groundNormal = hit.normal; 480 else 481 groundNormal = lastGroundNormal; 482 483 movingPlatform.hitPlatform = hit.collider.transform; 484 movement.hitPoint = hit.point; 485 movement.frameVelocity = Vector3.zero; 486 } 487 } 488 489 private IEnumerator SubtractNewPlatformVelocity () { 490 // When landing, subtract the velocity of the new ground from the character‘s velocity 491 // since movement in ground is relative to the movement of the ground. 492 if (movingPlatform.enabled && 493 (movingPlatform.movementTransfer == MovementTransferOnJump.InitTransfer || 494 movingPlatform.movementTransfer == MovementTransferOnJump.PermaTransfer) 495 ) { 496 // If we landed on a new platform, we have to wait for two FixedUpdates 497 // before we know the velocity of the platform under the character 498 if (movingPlatform.newPlatform) { 499 Transform platform = movingPlatform.activePlatform; 500 yield return new WaitForFixedUpdate(); 501 yield return new WaitForFixedUpdate(); 502 if (grounded && platform == movingPlatform.activePlatform) 503 yield return 1; 504 } 505 movement.velocity -= movingPlatform.platformVelocity; 506 } 507 } 508 509 private bool MoveWithPlatform () { 510 return ( 511 movingPlatform.enabled 512 && (grounded || movingPlatform.movementTransfer == MovementTransferOnJump.PermaLocked) 513 && movingPlatform.activePlatform != null 514 ); 515 } 516 517 private Vector3 GetDesiredHorizontalVelocity () { 518 // Find desired velocity 519 Vector3 desiredLocalDirection = tr.InverseTransformDirection(inputMoveDirection); 520 float maxSpeed = MaxSpeedInDirection(desiredLocalDirection); 521 if (grounded) { 522 // Modify max speed on slopes based on slope speed multiplier curve 523 var movementSlopeAngle = Mathf.Asin(movement.velocity.normalized.y) * Mathf.Rad2Deg; 524 maxSpeed *= movement.slopeSpeedMultiplier.Evaluate(movementSlopeAngle); 525 } 526 return tr.TransformDirection(desiredLocalDirection * maxSpeed); 527 } 528 529 private Vector3 AdjustGroundVelocityToNormal (Vector3 hVelocity, Vector3 groundNormal) { 530 Vector3 sideways = Vector3.Cross(Vector3.up, hVelocity); 531 return Vector3.Cross(sideways, groundNormal).normalized * hVelocity.magnitude; 532 } 533 534 private bool IsGroundedTest () { 535 return (groundNormal.y > 0.01); 536 } 537 538 float GetMaxAcceleration (bool grounded) { 539 // Maximum acceleration on ground and in air 540 if (grounded) 541 return movement.maxGroundAcceleration; 542 else 543 return movement.maxAirAcceleration; 544 } 545 546 float CalculateJumpVerticalSpeed (float targetJumpHeight) { 547 // From the jump height and gravity we deduce the upwards speed 548 // for the character to reach at the apex. 549 return Mathf.Sqrt (2 * targetJumpHeight * movement.gravity); 550 } 551 552 bool IsJumping () { 553 return jumping.jumping; 554 } 555 556 bool IsSliding () { 557 return (grounded && sliding.enabled && TooSteep()); 558 } 559 560 bool IsTouchingCeiling () { 561 return (movement.collisionFlags & CollisionFlags.CollidedAbove) != 0; 562 } 563 564 bool IsGrounded () { 565 return grounded; 566 } 567 568 bool TooSteep () { 569 return (groundNormal.y <= Mathf.Cos(controller.slopeLimit * Mathf.Deg2Rad)); 570 } 571 572 Vector3 GetDirection () { 573 return inputMoveDirection; 574 } 575 576 void SetControllable (bool controllable) { 577 canControl = controllable; 578 } 579 580 // Project a direction onto elliptical quater segments based on forward, sideways, and backwards speed. 581 // The function returns the length of the resulting vector. 582 float MaxSpeedInDirection (Vector3 desiredMovementDirection) { 583 if (desiredMovementDirection == Vector3.zero) 584 return 0; 585 else { 586 float zAxisEllipseMultiplier = (desiredMovementDirection.z > 0 ? movement.maxForwardSpeed : movement.maxBackwardsSpeed) / movement.maxSidewaysSpeed; 587 Vector3 temp = new Vector3(desiredMovementDirection.x, 0, desiredMovementDirection.z / zAxisEllipseMultiplier).normalized; 588 float length = new Vector3(temp.x, 0, temp.z * zAxisEllipseMultiplier).magnitude * movement.maxSidewaysSpeed; 589 return length; 590 } 591 } 592 593 void SetVelocity (Vector3 velocity) { 594 grounded = false; 595 movement.velocity = velocity; 596 movement.frameVelocity = Vector3.zero; 597 SendMessage("OnExternalVelocity"); 598 } 599 600 // Require a character controller to be attached to the same game object 601 602 //@script RequireComponent (CharacterController) 603 //@script AddComponentMenu ("Character/Character Motor") 604 605 }
FPSImputController.cs 用于第一人称控制角色移动,这里会监听主角按下的方向键最后传给CharacterMotor去计算模型的位置与旋转的角度
FPSImputController.cs 代码:
1 using UnityEngine; 2 using System.Collections; 3 4 /** 5 *用于第一人称控制角色移动,这里会监听主角按下的方向键最后传给CharacterMotor去计算模型的位置与旋转的角度 6 */ 7 8 [RequireComponent(typeof(CharacterMotor))] 9 [AddComponentMenu("Character/FPS Input Controller")] 10 11 public class FPSInputController : MonoBehaviour { 12 13 private CharacterMotor motor ; 14 15 // Use this for initialization 16 void Awake () { 17 motor = GetComponent<CharacterMotor>(); 18 } 19 20 // Update is called once per frame 21 void Update () { 22 // Get the input vector from kayboard or analog stick 23 Vector3 directionVector = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")); 24 25 if (directionVector != Vector3.zero) { 26 // Get the length of the directon vector and then normalize it 27 // Dividing by the length is cheaper than normalizing when we already have the length anyway 28 var directionLength = directionVector.magnitude; 29 directionVector = directionVector / directionLength; 30 31 // Make sure the length is no bigger than 1 32 directionLength = Mathf.Min(1, directionLength); 33 34 // Make the input vector more sensitive towards the extremes and less sensitive in the middle 35 // This makes it easier to control slow speeds when using analog sticks 36 directionLength = directionLength * directionLength; 37 38 // Multiply the normalized direction vector by the modified length 39 directionVector = directionVector * directionLength; 40 } 41 42 // Apply the direction to the CharacterMotor 43 motor.inputMoveDirection = transform.rotation * directionVector; 44 motor.inputJump = Input.GetButton("Jump"); 45 } 46 47 }
PlatFormInputController.cs 与FPSInputController一样会控制主角,但是会更加精细的计算模型的旋转的插值系数
PlatFormInputController.cs 代码:
1 using UnityEngine; 2 using System.Collections; 3 4 /** 5 * 与FPSInputController一样会控制主角,但是会更加精细的计算模型的旋转的插值系数 6 */ 7 8 [RequireComponent(typeof(CharacterController))] 9 [AddComponentMenu("Character/Platform Input Controller")] 10 public class PlatformInputController : MonoBehaviour { 11 12 public bool autoRotate = true; 13 public float maxRotationSpeed = 360; 14 15 private CharacterMotor motor ; 16 17 // Use this for initialization 18 void Awake () { 19 motor = GetComponent<CharacterMotor>(); 20 } 21 22 // Update is called once per frame 23 void Update () { 24 // Get the input vector from kayboard or analog stick 25 Vector3 directionVector = new Vector3(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"), 0); 26 27 if (directionVector != Vector3.zero) { 28 // Get the length of the directon vector and then normalize it 29 // Dividing by the length is cheaper than normalizing when we already have the length anyway 30 var directionLength = directionVector.magnitude; 31 directionVector = directionVector / directionLength; 32 33 // Make sure the length is no bigger than 1 34 directionLength = Mathf.Min(1, directionLength); 35 36 // Make the input vector more sensitive towards the extremes and less sensitive in the middle 37 // This makes it easier to control slow speeds when using analog sticks 38 directionLength = directionLength * directionLength; 39 40 // Multiply the normalized direction vector by the modified length 41 directionVector = directionVector * directionLength; 42 } 43 44 // Rotate the input vector into camera space so up is camera‘s up and right is camera‘s right 45 directionVector = Camera.main.transform.rotation * directionVector; 46 47 // Rotate input vector to be perpendicular to character‘s up vector 48 var camToCharacterSpace = Quaternion.FromToRotation(-Camera.main.transform.forward, transform.up); 49 directionVector = (camToCharacterSpace * directionVector); 50 51 // Apply the direction to the CharacterMotor 52 motor.inputMoveDirection = directionVector; 53 motor.inputJump = Input.GetButton("Jump"); 54 55 // Set rotation to the move direction 56 if (autoRotate && directionVector.sqrMagnitude > 0.01) { 57 Vector3 newForward = ConstantSlerp( 58 transform.forward, 59 directionVector, 60 maxRotationSpeed * Time.deltaTime 61 ); 62 newForward = ProjectOntoPlane(newForward, transform.up); 63 transform.rotation = Quaternion.LookRotation(newForward, transform.up); 64 } 65 } 66 67 Vector3 ProjectOntoPlane (Vector3 v, Vector3 normal) { 68 return v - Vector3.Project(v, normal); 69 } 70 71 Vector3 ConstantSlerp (Vector3 from, Vector3 to, float angle) { 72 float value = Mathf.Min(1, angle / Vector3.Angle(from, to)); 73 return Vector3.Slerp(from, to, value); 74 } 75 76 }
ThirdPersonCamera.cs 主要控制第三人称视角时摄像机的控制
ThirdPersonCamera.cs 代码:
1 using UnityEngine; 2 using System.Collections; 3 4 /** 5 * 主要控制第三人称视角时摄像机的控制 6 */ 7 8 public class ThirdPersonCamera : MonoBehaviour { 9 10 public Transform cameraTransform; 11 private Transform _target; 12 13 public float distance = 7.0f; 14 15 public float height = 3.0f; 16 17 public float angularSmoothLag = 0.3f; 18 public float angularMaxSpeed = 15.0f; 19 20 public float heightSmoothLag = 0.3f; 21 22 public float snapSmoothLag = 0.2f; 23 public float snapMaxSpeed = 720.0f; 24 25 public float clampHeadPositionScreenSpace = 0.75f; 26 27 public float lockCameraTimeout = 0.2f; 28 29 private Vector3 headOffset = Vector3.zero; 30 private Vector3 centerOffset = Vector3.zero; 31 32 private float heightVelocity = 0.0f; 33 private float angleVelocity = 0.0f; 34 private bool snap = false; 35 private ThirdPersonController controller; 36 private float targetHeight = 100000.0f; 37 38 void Awake () 39 { 40 if(!cameraTransform && Camera.main) 41 cameraTransform = Camera.main.transform; 42 if(!cameraTransform) { 43 Debug.Log("Please assign a camera to the ThirdPersonCamera script."); 44 enabled = false; 45 } 46 47 _target = transform; 48 if (_target) 49 { 50 controller = _target.GetComponent<ThirdPersonController>(); 51 } 52 53 if (controller) 54 { 55 CharacterController characterController = (CharacterController)_target.collider; 56 centerOffset = characterController.bounds.center - _target.position; 57 headOffset = centerOffset; 58 headOffset.y = characterController.bounds.max.y - _target.position.y; 59 } 60 else 61 Debug.Log("Please assign a target to the camera that has a ThirdPersonController script attached."); 62 63 Cut(_target, centerOffset); 64 } 65 66 void DebugDrawStuff () 67 { 68 Debug.DrawLine(_target.position, _target.position + headOffset); 69 70 } 71 72 float AngleDistance (float a , float b ) 73 { 74 a = Mathf.Repeat(a, 360); 75 b = Mathf.Repeat(b, 360); 76 77 return Mathf.Abs(b - a); 78 } 79 80 void Apply (Transform dummyTarget, Vector3 dummyCenter) 81 { 82 // Early out if we don‘t have a target 83 if (!controller) 84 return; 85 86 Vector3 targetCenter = _target.position + centerOffset; 87 Vector3 targetHead = _target.position + headOffset; 88 89 // DebugDrawStuff(); 90 91 // Calculate the current & target rotation angles 92 float originalTargetAngle = _target.eulerAngles.y; 93 float currentAngle = cameraTransform.eulerAngles.y; 94 95 // Adjust real target angle when camera is locked 96 float targetAngle = originalTargetAngle; 97 98 // When pressing Fire2 (alt) the camera will snap to the target direction real quick. 99 // It will stop snapping when it reaches the target 100 if (Input.GetButton("Fire2")) 101 snap = true; 102 103 if (snap) 104 { 105 // We are close to the target, so we can stop snapping now! 106 if (AngleDistance (currentAngle, originalTargetAngle) < 3.0) 107 snap = false; 108 109 currentAngle = Mathf.SmoothDampAngle(currentAngle, targetAngle, ref angleVelocity, snapSmoothLag, snapMaxSpeed); 110 } 111 // Normal camera motion 112 else 113 { 114 115 if (controller.GetLockCameraTimer () < lockCameraTimeout) 116 { 117 targetAngle = currentAngle; 118 } 119 120 // Lock the camera when moving backwards! 121 // * It is really confusing to do 180 degree spins when turning around. 122 if (AngleDistance (currentAngle, targetAngle) > 160 && controller.IsMovingBackwards ()) 123 targetAngle += 180; 124 125 currentAngle = Mathf.SmoothDampAngle(currentAngle, targetAngle, ref angleVelocity, angularSmoothLag, angularMaxSpeed); 126 } 127 128 // When jumping don‘t move camera upwards but only down! 129 if (controller.IsJumping ()) 130 { 131 // We‘d be moving the camera upwards, do that only if it‘s really high 132 float newTargetHeight = targetCenter.y + height; 133 if (newTargetHeight < targetHeight || newTargetHeight - targetHeight > 5) 134 targetHeight = targetCenter.y + height; 135 } 136 // When walking always update the target height 137 else 138 { 139 targetHeight = targetCenter.y + height; 140 } 141 142 // Damp the height 143 float currentHeight = cameraTransform.position.y; 144 currentHeight = Mathf.SmoothDamp (currentHeight, targetHeight, ref heightVelocity, heightSmoothLag); 145 146 // Convert the angle into a rotation, by which we then reposition the camera 147 Quaternion currentRotation = Quaternion.Euler (0, currentAngle, 0); 148 149 // Set the position of the camera on the x-z plane to: 150 // distance meters behind the target 151 cameraTransform.position = targetCenter; 152 cameraTransform.position += currentRotation * Vector3.back * distance; 153 154 // Set the height of the camera 155 cameraTransform.position = new Vector3(cameraTransform.position.x,currentHeight,cameraTransform.position.z); 156 157 // Always look at the target 158 SetUpRotation(targetCenter, targetHead); 159 } 160 161 void LateUpdate () { 162 Apply (transform, Vector3.zero); 163 } 164 165 void Cut (Transform dummyTarget , Vector3 dummyCenter) 166 { 167 float oldHeightSmooth = heightSmoothLag; 168 float oldSnapMaxSpeed = snapMaxSpeed; 169 float oldSnapSmooth = snapSmoothLag; 170 171 snapMaxSpeed = 10000; 172 snapSmoothLag = 0.001f; 173 heightSmoothLag = 0.001f; 174 175 snap = true; 176 Apply (transform, Vector3.zero); 177 178 heightSmoothLag = oldHeightSmooth; 179 snapMaxSpeed = oldSnapMaxSpeed; 180 snapSmoothLag = oldSnapSmooth; 181 } 182 183 void SetUpRotation (Vector3 centerPos,Vector3 headPos) 184 { 185 // Now it‘s getting hairy. The devil is in the details here, the big issue is jumping of course. 186 // * When jumping up and down we don‘t want to center the guy in screen space. 187 // This is important to give a feel for how high you jump and avoiding large camera movements. 188 // 189 // * At the same time we dont want him to ever go out of screen and we want all rotations to be totally smooth. 190 // 191 // So here is what we will do: 192 // 193 // 1. We first find the rotation around the y axis. Thus he is always centered on the y-axis 194 // 2. When grounded we make him be centered 195 // 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 196 // 4. When landing we smoothly interpolate towards centering him on screen 197 Vector3 cameraPos = cameraTransform.position; 198 Vector3 offsetToCenter = centerPos - cameraPos; 199 200 // Generate base rotation only around y-axis 201 Quaternion yRotation = Quaternion.LookRotation(new Vector3(offsetToCenter.x, 0, offsetToCenter.z)); 202 203 Vector3 relativeOffset = Vector3.forward * distance + Vector3.down * height; 204 cameraTransform.rotation = yRotation * Quaternion.LookRotation(relativeOffset); 205 206 // Calculate the projected center position and top position in world space 207 Ray centerRay = cameraTransform.camera.ViewportPointToRay(new Vector3(0.5f, 0.5f, 1f)); 208 Ray topRay = cameraTransform.camera.ViewportPointToRay(new Vector3(0.5f, clampHeadPositionScreenSpace, 1f)); 209 210 Vector3 centerRayPos = centerRay.GetPoint(distance); 211 Vector3 topRayPos = topRay.GetPoint(distance); 212 213 float centerToTopAngle = Vector3.Angle(centerRay.direction, topRay.direction); 214 215 float heightToAngle = centerToTopAngle / (centerRayPos.y - topRayPos.y); 216 217 float extraLookAngle = heightToAngle * (centerRayPos.y - centerPos.y); 218 if (extraLookAngle < centerToTopAngle) 219 { 220 extraLookAngle = 0; 221 } 222 else 223 { 224 extraLookAngle = extraLookAngle - centerToTopAngle; 225 cameraTransform.rotation *= Quaternion.Euler(-extraLookAngle, 0, 0); 226 } 227 } 228 229 Vector3 GetCenterOffset () 230 { 231 return centerOffset; 232 } 233 234 }
ThirdPersonController.cs 主要更新第三人称视角控制主角时播放的各种动画,主角的移动等
ThirdPersonController.cs 代码:
1 using UnityEngine; 2 using System.Collections; 3 4 /** 5 * 主要更新第三人称视角控制主角时播放的各种动画,主角的移动等 6 */ 7 8 [RequireComponent(typeof(CharacterController))] 9 10 public class ThirdPersonController : MonoBehaviour { 11 12 public AnimationClip idleAnimation ; 13 public AnimationClip walkAnimation ; 14 public AnimationClip runAnimation ; 15 public AnimationClip jumpPoseAnimation; 16 17 public float walkMaxAnimationSpeed = 0.75f; 18 public float trotMaxAnimationSpeed = 1.0f; 19 public float runMaxAnimationSpeed = 1.0f; 20 public float jumpAnimationSpeed = 1.15f; 21 public float landAnimationSpeed = 1.0f; 22 23 private Animation _animation; 24 25 enum CharacterState 26 { 27 Idle = 0, 28 Walking = 1, 29 Trotting = 2, 30 Running = 3, 31 Jumping = 4, 32 } 33 34 private CharacterState _characterState; 35 36 // The speed when walking 37 float walkSpeed = 2.0f; 38 // after trotAfterSeconds of walking we trot with trotSpeed 39 float trotSpeed = 4.0f; 40 // when pressing "Fire3" button (cmd) we start running 41 float runSpeed = 6.0f; 42 43 float inAirControlAcceleration = 3.0f; 44 45 // How high do we jump when pressing jump and letting go immediately 46 float jumpHeight = 0.5f; 47 48 // The gravity for the character 49 float gravity = 20.0f; 50 // The gravity in controlled descent mode 51 float speedSmoothing = 10.0f; 52 float rotateSpeed = 500.0f; 53 float trotAfterSeconds = 3.0f; 54 55 bool canJump = true; 56 57 private float jumpRepeatTime = 0.05f; 58 private float jumpTimeout = 0.15f; 59 private float groundedTimeout = 0.25f; 60 61 // The camera doesnt start following the target immediately but waits for a split second to avoid too much waving around. 62 private float lockCameraTimer = 0.0f; 63 64 // The current move direction in x-z 65 private Vector3 moveDirection = Vector3.zero; 66 // The current vertical speed 67 private float verticalSpeed = 0.0f; 68 // The current x-z move speed 69 private float moveSpeed = 0.0f; 70 71 // The last collision flags returned from controller.Move 72 private CollisionFlags collisionFlags; 73 74 // Are we jumping? (Initiated with jump button and not grounded yet) 75 private bool jumping = false; 76 private bool jumpingReachedApex = false; 77 78 // Are we moving backwards (This locks the camera to not do a 180 degree spin) 79 private bool movingBack = false; 80 // Is the user pressing any keys? 81 private bool isMoving = false; 82 // When did the user start walking (Used for going into trot after a while) 83 private float walkTimeStart = 0.0f; 84 // Last time the jump button was clicked down 85 private float lastJumpButtonTime = -10.0f; 86 // Last time we performed a jump 87 private float lastJumpTime = -1.0f; 88 89 // the height we jumped from (Used to determine for how long to apply extra jump power after jumping.) 90 private float lastJumpStartHeight = 0.0f; 91 92 private Vector3 inAirVelocity = Vector3.zero; 93 94 private float lastGroundedTime = 0.0f; 95 96 private bool isControllable = true; 97 98 void Awake () 99 { 100 moveDirection = transform.TransformDirection(Vector3.forward); 101 102 _animation = GetComponent<Animation>(); 103 if(!_animation) 104 Debug.Log("The character you would like to control doesn‘t have animations. Moving her might look weird."); 105 106 /* 107 public var idleAnimation : AnimationClip; 108 public var walkAnimation : AnimationClip; 109 public var runAnimation : AnimationClip; 110 public var jumpPoseAnimation : AnimationClip; 111 */ 112 if(!idleAnimation) { 113 _animation = null; 114 Debug.Log("No idle animation found. Turning off animations."); 115 } 116 if(!walkAnimation) { 117 _animation = null; 118 Debug.Log("No walk animation found. Turning off animations."); 119 } 120 if(!runAnimation) { 121 _animation = null; 122 Debug.Log("No run animation found. Turning off animations."); 123 } 124 if(!jumpPoseAnimation && canJump) { 125 _animation = null; 126 Debug.Log("No jump animation found and the character has canJump enabled. Turning off animations."); 127 } 128 129 } 130 131 void UpdateSmoothedMovementDirection () 132 { 133 Transform cameraTransform = Camera.main.transform; 134 bool grounded = IsGrounded(); 135 136 // Forward vector relative to the camera along the x-z plane 137 Vector3 forward = cameraTransform.TransformDirection(Vector3.forward); 138 forward.y = 0; 139 forward = forward.normalized; 140 141 // Right vector relative to the camera 142 // Always orthogonal to the forward vector 143 Vector3 right = new Vector3(forward.z, 0, -forward.x); 144 145 float v = Input.GetAxisRaw("Vertical"); 146 float h = Input.GetAxisRaw("Horizontal"); 147 148 // Are we moving backwards or looking backwards 149 if (v < -0.2f) 150 movingBack = true; 151 else 152 movingBack = false; 153 154 bool wasMoving = isMoving; 155 isMoving = Mathf.Abs (h) > 0.1f || Mathf.Abs (v) > 0.1f; 156 157 // Target direction relative to the camera 158 Vector3 targetDirection = h * right + v * forward; 159 160 // Grounded controls 161 if (grounded) 162 { 163 // Lock camera for short period when transitioning moving & standing still 164 lockCameraTimer += Time.deltaTime; 165 if (isMoving != wasMoving) 166 lockCameraTimer = 0.0f; 167 168 // We store speed and direction seperately, 169 // so that when the character stands still we still have a valid forward direction 170 // moveDirection is always normalized, and we only update it if there is user input. 171 if (targetDirection != Vector3.zero) 172 { 173 // If we are really slow, just snap to the target direction 174 if (moveSpeed < walkSpeed * 0.9f && grounded) 175 { 176 moveDirection = targetDirection.normalized; 177 } 178 // Otherwise smoothly turn towards it 179 else 180 { 181 moveDirection = Vector3.RotateTowards(moveDirection, targetDirection, rotateSpeed * Mathf.Deg2Rad * Time.deltaTime, 1000); 182 183 moveDirection = moveDirection.normalized; 184 } 185 } 186 187 // Smooth the speed based on the current target direction 188 float curSmooth = speedSmoothing * Time.deltaTime; 189 190 // Choose target speed 191 //* We want to support analog input but make sure you cant walk faster diagonally than just forward or sideways 192 float targetSpeed = Mathf.Min(targetDirection.magnitude, 1.0f); 193 194 _characterState = CharacterState.Idle; 195 196 // Pick speed modifier 197 if (Input.GetKey (KeyCode.LeftShift) | Input.GetKey (KeyCode.RightShift)) 198 { 199 targetSpeed *= runSpeed; 200 _characterState = CharacterState.Running; 201 } 202 else if (Time.time - trotAfterSeconds > walkTimeStart) 203 { 204 targetSpeed *= trotSpeed; 205 _characterState = CharacterState.Trotting; 206 } 207 else 208 { 209 targetSpeed *= walkSpeed; 210 _characterState = CharacterState.Walking; 211 } 212 213 moveSpeed = Mathf.Lerp(moveSpeed, targetSpeed, curSmooth); 214 215 // Reset walk time start when we slow down 216 if (moveSpeed < walkSpeed * 0.3f) 217 walkTimeStart = Time.time; 218 } 219 // In air controls 220 else 221 { 222 // Lock camera while in air 223 if (jumping) 224 lockCameraTimer = 0.0f; 225 226 if (isMoving) 227 inAirVelocity += targetDirection.normalized * Time.deltaTime * inAirControlAcceleration; 228 } 229 230 } 231 232 void ApplyJumping () 233 { 234 // Prevent jumping too fast after each other 235 if (lastJumpTime + jumpRepeatTime > Time.time) 236 return; 237 238 if (IsGrounded()) { 239 // Jump 240 // - Only when pressing the button down 241 // - With a timeout so you can press the button slightly before landing 242 if (canJump && Time.time < lastJumpButtonTime + jumpTimeout) { 243 verticalSpeed = CalculateJumpVerticalSpeed (jumpHeight); 244 SendMessage("DidJump", SendMessageOptions.DontRequireReceiver); 245 } 246 } 247 } 248 249 void ApplyGravity () 250 { 251 if (isControllable) // don‘t move player at all if not controllable. 252 { 253 // Apply gravity 254 bool jumpButton = Input.GetButton("Jump"); 255 256 // When we reach the apex of the jump we send out a message 257 if (jumping && !jumpingReachedApex && verticalSpeed <= 0.0f) 258 { 259 jumpingReachedApex = true; 260 SendMessage("DidJumpReachApex", SendMessageOptions.DontRequireReceiver); 261 } 262 263 if (IsGrounded ()) 264 verticalSpeed = 0.0f; 265 else 266 verticalSpeed -= gravity * Time.deltaTime; 267 } 268 } 269 270 float CalculateJumpVerticalSpeed (float targetJumpHeight) 271 { 272 // From the jump height and gravity we deduce the upwards speed 273 // for the character to reach at the apex. 274 return Mathf.Sqrt(2 * targetJumpHeight * gravity); 275 } 276 277 void DidJump () 278 { 279 jumping = true; 280 jumpingReachedApex = false; 281 lastJumpTime = Time.time; 282 lastJumpStartHeight = transform.position.y; 283 lastJumpButtonTime = -10; 284 285 _characterState = CharacterState.Jumping; 286 } 287 288 void Update() { 289 290 if (!isControllable) 291 { 292 // kill all inputs if not controllable. 293 Input.ResetInputAxes(); 294 } 295 296 if (Input.GetButtonDown ("Jump")) 297 { 298 lastJumpButtonTime = Time.time; 299 } 300 301 UpdateSmoothedMovementDirection(); 302 303 // Apply gravity 304 // - extra power jump modifies gravity 305 // - controlledDescent mode modifies gravity 306 ApplyGravity (); 307 308 // Apply jumping logic 309 ApplyJumping (); 310 311 // Calculate actual motion 312 Vector3 movement = moveDirection * moveSpeed + new Vector3 (0, verticalSpeed, 0) + inAirVelocity; 313 movement *= Time.deltaTime; 314 315 // Move the controller 316 CharacterController controller = GetComponent<CharacterController>(); 317 collisionFlags = controller.Move(movement); 318 319 // ANIMATION sector 320 if(_animation) { 321 if(_characterState == CharacterState.Jumping) 322 { 323 if(!jumpingReachedApex) { 324 _animation[jumpPoseAnimation.name].speed = jumpAnimationSpeed; 325 _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever; 326 _animation.CrossFade(jumpPoseAnimation.name); 327 } else { 328 _animation[jumpPoseAnimation.name].speed = -landAnimationSpeed; 329 _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever; 330 _animation.CrossFade(jumpPoseAnimation.name); 331 } 332 } 333 else 334 { 335 if(controller.velocity.sqrMagnitude < 0.1f) { 336 _animation.CrossFade(idleAnimation.name); 337 } 338 else 339 { 340 if(_characterState == CharacterState.Running) { 341 _animation[runAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0f, runMaxAnimationSpeed); 342 _animation.CrossFade(runAnimation.name); 343 } 344 else if(_characterState == CharacterState.Trotting) { 345 _animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0f, trotMaxAnimationSpeed); 346 _animation.CrossFade(walkAnimation.name); 347 } 348 else if(_characterState == CharacterState.Walking) { 349 _animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0f, walkMaxAnimationSpeed); 350 _animation.CrossFade(walkAnimation.name); 351 } 352 353 } 354 } 355 } 356 // ANIMATION sector 357 358 // Set rotation to the move direction 359 if (IsGrounded()) 360 { 361 362 transform.rotation = Quaternion.LookRotation(moveDirection); 363 364 } 365 else 366 { 367 Vector3 xzMove = movement; 368 xzMove.y = 0; 369 if (xzMove.sqrMagnitude > 0.001f) 370 { 371 transform.rotation = Quaternion.LookRotation(xzMove); 372 } 373 } 374 375 // We are in jump mode but just became grounded 376 if (IsGrounded()) 377 { 378 lastGroundedTime = Time.time; 379 inAirVelocity = Vector3.zero; 380 if (jumping) 381 { 382 jumping = false; 383 SendMessage("DidLand", SendMessageOptions.DontRequireReceiver); 384 } 385 } 386 } 387 388 void OnControllerColliderHit (ControllerColliderHit hit ) 389 { 390 // Debug.DrawRay(hit.point, hit.normal); 391 if (hit.moveDirection.y > 0.01f) 392 return; 393 } 394 395 float GetSpeed () { 396 return moveSpeed; 397 } 398 399 public bool IsJumping () { 400 return jumping; 401 } 402 403 bool IsGrounded () { 404 return (collisionFlags & CollisionFlags.CollidedBelow) != 0; 405 } 406 407 Vector3 GetDirection () { 408 return moveDirection; 409 } 410 411 public bool IsMovingBackwards () { 412 return movingBack; 413 } 414 415 public float GetLockCameraTimer () 416 { 417 return lockCameraTimer; 418 } 419 420 bool IsMoving () 421 { 422 return Mathf.Abs(Input.GetAxisRaw("Vertical")) + Mathf.Abs(Input.GetAxisRaw("Horizontal")) > 0.5f; 423 } 424 425 bool HasJumpReachedApex () 426 { 427 return jumpingReachedApex; 428 } 429 430 bool IsGroundedWithTimeout () 431 { 432 return lastGroundedTime + groundedTimeout > Time.time; 433 } 434 435 void Reset () 436 { 437 gameObject.tag = "Player"; 438 } 439 440 }
MouseLook.cs 自带的C# 代码:
1 using UnityEngine; 2 using System.Collections; 3 4 /// MouseLook rotates the transform based on the mouse delta. 5 /// Minimum and Maximum values can be used to constrain the possible rotation 6 7 /// To make an FPS style character: 8 /// - Create a capsule. 9 /// - Add the MouseLook script to the capsule. 10 /// -> Set the mouse look to use LookX. (You want to only turn character but not tilt it) 11 /// - Add FPSInputController script to the capsule 12 /// -> A CharacterMotor and a CharacterController component will be automatically added. 13 14 /// - Create a camera. Make the camera a child of the capsule. Reset it‘s transform. 15 /// - Add a MouseLook script to the camera. 16 /// -> Set the mouse look to use LookY. (You want the camera to tilt up and down like a head. The character already turns.) 17 [AddComponentMenu("Camera-Control/Mouse Look")] 18 public class MouseLook : MonoBehaviour { 19 20 public enum RotationAxes { MouseXAndY = 0, MouseX = 1, MouseY = 2 } 21 public RotationAxes axes = RotationAxes.MouseXAndY; 22 public float sensitivityX = 15F; 23 public float sensitivityY = 15F; 24 25 public float minimumX = -360F; 26 public float maximumX = 360F; 27 28 public float minimumY = -60F; 29 public float maximumY = 60F; 30 31 float rotationY = 0F; 32 33 void Update () 34 { 35 if (axes == RotationAxes.MouseXAndY) 36 { 37 float rotationX = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivityX; 38 39 rotationY += Input.GetAxis("Mouse Y") * sensitivityY; 40 rotationY = Mathf.Clamp (rotationY, minimumY, maximumY); 41 42 transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0); 43 } 44 else if (axes == RotationAxes.MouseX) 45 { 46 transform.Rotate(0, Input.GetAxis("Mouse X") * sensitivityX, 0); 47 } 48 else 49 { 50 rotationY += Input.GetAxis("Mouse Y") * sensitivityY; 51 rotationY = Mathf.Clamp (rotationY, minimumY, maximumY); 52 53 transform.localEulerAngles = new Vector3(-rotationY, transform.localEulerAngles.y, 0); 54 } 55 } 56 57 void Start () 58 { 59 // Make the rigid body not change rotation 60 if (GetComponent<Rigidbody>()) 61 GetComponent<Rigidbody>().freezeRotation = true; 62 } 63 }
标签:
原文地址:http://www.cnblogs.com/shakyamuni/p/5115371.html