Unity3D之第一人称第三人称角色控制组件修改C#版本

转自: 雨松MOMO 2012年07月01日 于 雨松MOMO程序研究院 发表

之前MOMO在 Unity3D研究院之角色控制器组件研究(二十二)文章中向大家介绍了角色控制器组件。默认系统提供了JavaScript脚本的支持,可是我们还是喜欢用C#来编写脚本,本篇文章MOMO将把角色控制器的所有脚本全部改成C#语言。方便自己也方便大家学习,哇咔咔。首先,我们将角色控制器包引入工程中。如下图所示,默认提供的脚本除了MouseLook以外其它的都是js脚本,本篇文章MOMO将把它们全部修改成C#。刚好也是答应Unity圣典的站长录制游戏开发视频,视频中我说下一节我将教大家怎么把角色控制器组件的脚本全部改成C#。

Unity3D研究院之第一人称第三人称角色控制组件修改C#版本(二十九) - 雨松MOMO程序研究院 - 1

首先把CharacterMotor.js修改成C# 它主要设置角色控制的系数,如运动、跳跃、移动、滑动等。第一人称与第三人称主角模型的移动与旋转的角度都最后都是在这里计算的,请大家好好看看这个类, 尤其是UpdateFunction()方法。

CharacterMotor.cs  

 

[csharp]  view plain  copy
  1. using UnityEngine;  
  2. using System.Collections;  
  3.    
  4. /** 
  5.  *  @Author : www.xuanyusong.com  
  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. private void UpdateFunction () {  
  198.     // We copy the actual velocity into a temporary variable that we can manipulate.  
  199.     Vector3 velocity  = movement.velocity;  
  200.    
  201.     // Update velocity based on input  
  202.     velocity = ApplyInputVelocityChange(velocity);  
  203.    
  204.     // Apply gravity and jumping force  
  205.     velocity = ApplyGravityAndJumping (velocity);  
  206.    
  207.     // Moving platform support  
  208.     Vector3 moveDistance  = Vector3.zero;  
  209.     if (MoveWithPlatform()) {  
  210.         Vector3 newGlobalPoint  = movingPlatform.activePlatform.TransformPoint(movingPlatform.activeLocalPoint);  
  211.         moveDistance = (newGlobalPoint - movingPlatform.activeGlobalPoint);  
  212.         if (moveDistance != Vector3.zero)  
  213.             controller.Move(moveDistance);  
  214.    
  215.         // Support moving platform rotation as well:  
  216.         Quaternion newGlobalRotation  = movingPlatform.activePlatform.rotation * movingPlatform.activeLocalRotation;  
  217.         Quaternion rotationDiff  = newGlobalRotation * Quaternion.Inverse(movingPlatform.activeGlobalRotation);  
  218.    
  219.         var yRotation = rotationDiff.eulerAngles.y;  
  220.         if (yRotation != 0) {  
  221.             // Prevent rotation of the local up vector  
  222.             tr.Rotate(0, yRotation, 0);  
  223.         }  
  224.     }  
  225.    
  226.     // Save lastPosition for velocity calculation.  
  227.     Vector3 lastPosition  = tr.position;  
  228.    
  229.     // We always want the movement to be framerate independent.  Multiplying by Time.deltaTime does this.  
  230.     Vector3 currentMovementOffset = velocity * Time.deltaTime;  
  231.    
  232.     // Find out how much we need to push towards the ground to avoid loosing grouning  
  233.     // when walking down a step or over a sharp change in slope.  
  234.     float pushDownOffset  = Mathf.Max(controller.stepOffset, new Vector3(currentMovementOffset.x, 0, currentMovementOffset.z).magnitude);  
  235.     if (grounded)  
  236.         currentMovementOffset -= pushDownOffset * Vector3.up;  
  237.    
  238.     // Reset variables that will be set by collision function  
  239.     movingPlatform.hitPlatform = null;  
  240.     groundNormal = Vector3.zero;  
  241.    
  242.     // Move our character!  
  243.     movement.collisionFlags = controller.Move (currentMovementOffset);  
  244.    
  245.     movement.lastHitPoint = movement.hitPoint;  
  246.     lastGroundNormal = groundNormal;  
  247.    
  248.     if (movingPlatform.enabled && movingPlatform.activePlatform != movingPlatform.hitPlatform) {  
  249.         if (movingPlatform.hitPlatform != null) {  
  250.             movingPlatform.activePlatform = movingPlatform.hitPlatform;  
  251.             movingPlatform.lastMatrix = movingPlatform.hitPlatform.localToWorldMatrix;  
  252.             movingPlatform.newPlatform = true;  
  253.         }  
  254.     }  
  255.    
  256.     // Calculate the velocity based on the current and previous position.    
  257.     // This means our velocity will only be the amount the character actually moved as a result of collisions.  
  258.     Vector3 oldHVelocity  = new Vector3(velocity.x, 0, velocity.z);  
  259.     movement.velocity = (tr.position - lastPosition) / Time.deltaTime;  
  260.     Vector3 newHVelocity  = new Vector3(movement.velocity.x, 0, movement.velocity.z);  
  261.    
  262.     // The CharacterController can be moved in unwanted directions when colliding with things.  
  263.     // We want to prevent this from influencing the recorded velocity.  
  264.     if (oldHVelocity == Vector3.zero) {  
  265.         movement.velocity = new Vector3(0, movement.velocity.y, 0);  
  266.     }  
  267.     else {  
  268.         float projectedNewVelocity  = Vector3.Dot(newHVelocity, oldHVelocity) / oldHVelocity.sqrMagnitude;  
  269.         movement.velocity = oldHVelocity * Mathf.Clamp01(projectedNewVelocity) + movement.velocity.y * Vector3.up;  
  270.     }  
  271.    
  272.     if (movement.velocity.y < velocity.y - 0.001) {  
  273.         if (movement.velocity.y < 0) {  
  274.             // Something is forcing the CharacterController down faster than it should.  
  275.             // Ignore this  
  276.             movement.velocity.y = velocity.y;  
  277.         }  
  278.         else {  
  279.             // The upwards movement of the CharacterController has been blocked.  
  280.             // This is treated like a ceiling collision - stop further jumping here.  
  281.             jumping.holdingJumpButton = false;  
  282.         }  
  283.     }  
  284.    
  285.     // We were grounded but just loosed grounding  
  286.     if (grounded && !IsGroundedTest()) {  
  287.         grounded = false;  
  288.    
  289.         // Apply inertia from platform  
  290.         if (movingPlatform.enabled &&  
  291.             (movingPlatform.movementTransfer == MovementTransferOnJump.InitTransfer ||  
  292.             movingPlatform.movementTransfer == MovementTransferOnJump.PermaTransfer)  
  293.         ) {  
  294.             movement.frameVelocity = movingPlatform.platformVelocity;  
  295.             movement.velocity += movingPlatform.platformVelocity;  
  296.         }  
  297.    
  298.         SendMessage("OnFall", SendMessageOptions.DontRequireReceiver);  
  299.         // We pushed the character down to ensure it would stay on the ground if there was any.  
  300.         // But there wasn't so now we cancel the downwards offset to make the fall smoother.  
  301.         tr.position += pushDownOffset * Vector3.up;  
  302.     }  
  303.     // We were not grounded but just landed on something  
  304.     else if (!grounded && IsGroundedTest()) {  
  305.         grounded = true;  
  306.         jumping.jumping = false;  
  307.         SubtractNewPlatformVelocity();  
  308.    
  309.         SendMessage("OnLand", SendMessageOptions.DontRequireReceiver);  
  310.     }  
  311.    
  312.     // Moving platforms support  
  313.     if (MoveWithPlatform()) {  
  314.         // Use the center of the lower half sphere of the capsule as reference point.  
  315.         // This works best when the character is standing on moving tilting platforms.   
  316.         movingPlatform.activeGlobalPoint = tr.position + Vector3.up * (controller.center.y - controller.height*0.5f + controller.radius);  
  317.         movingPlatform.activeLocalPoint = movingPlatform.activePlatform.InverseTransformPoint(movingPlatform.activeGlobalPoint);  
  318.    
  319.         // Support moving platform rotation as well:  
  320.         movingPlatform.activeGlobalRotation = tr.rotation;  
  321.         movingPlatform.activeLocalRotation = Quaternion.Inverse(movingPlatform.activePlatform.rotation) * movingPlatform.activeGlobalRotation;   
  322.     }  
  323. }  
  324.    
  325. void FixedUpdate () {  
  326.     if (movingPlatform.enabled) {  
  327.         if (movingPlatform.activePlatform != null) {  
  328.             if (!movingPlatform.newPlatform) {  
  329.                 Vector3 lastVelocity  = movingPlatform.platformVelocity;  
  330.    
  331.                 movingPlatform.platformVelocity = (  
  332.                     movingPlatform.activePlatform.localToWorldMatrix.MultiplyPoint3x4(movingPlatform.activeLocalPoint)  
  333.                     - movingPlatform.lastMatrix.MultiplyPoint3x4(movingPlatform.activeLocalPoint)  
  334.                 ) / Time.deltaTime;  
  335.             }  
  336.             movingPlatform.lastMatrix = movingPlatform.activePlatform.localToWorldMatrix;  
  337.             movingPlatform.newPlatform = false;  
  338.         }  
  339.         else {  
  340.             movingPlatform.platformVelocity = Vector3.zero;   
  341.         }  
  342.     }  
  343.    
  344.     if (useFixedUpdate)  
  345.         UpdateFunction();  
  346. }  
  347.    
  348. void Update () {  
  349.     if (!useFixedUpdate)  
  350.         UpdateFunction();  
  351. }  
  352.    
  353. private Vector3 ApplyInputVelocityChange (Vector3 velocity) {     
  354.     if (!canControl)  
  355.         inputMoveDirection = Vector3.zero;  
  356.    
  357.     // Find desired velocity  
  358.     Vector3 desiredVelocity;  
  359.     if (grounded && TooSteep()) {  
  360.         // The direction we're sliding in  
  361.         desiredVelocity = new Vector3(groundNormal.x, 0, groundNormal.z).normalized;  
  362.         // Find the input movement direction projected onto the sliding direction  
  363.         var projectedMoveDir = Vector3.Project(inputMoveDirection, desiredVelocity);  
  364.         // Add the sliding direction, the spped control, and the sideways control vectors  
  365.         desiredVelocity = desiredVelocity + projectedMoveDir * sliding.speedControl + (inputMoveDirection - projectedMoveDir) * sliding.sidewaysControl;  
  366.         // Multiply with the sliding speed  
  367.         desiredVelocity *= sliding.slidingSpeed;  
  368.     }  
  369.     else  
  370.         desiredVelocity = GetDesiredHorizontalVelocity();  
  371.    
  372.     if (movingPlatform.enabled && movingPlatform.movementTransfer == MovementTransferOnJump.PermaTransfer) {  
  373.         desiredVelocity += movement.frameVelocity;  
  374.         desiredVelocity.y = 0;  
  375.     }  
  376.    
  377.     if (grounded)  
  378.         desiredVelocity = AdjustGroundVelocityToNormal(desiredVelocity, groundNormal);  
  379.     else  
  380.         velocity.y = 0;  
  381.    
  382.     // Enforce max velocity change  
  383.     float maxVelocityChange  = GetMaxAcceleration(grounded) * Time.deltaTime;  
  384.     Vector3 velocityChangeVector  = (desiredVelocity - velocity);  
  385.     if (velocityChangeVector.sqrMagnitude > maxVelocityChange * maxVelocityChange) {  
  386.         velocityChangeVector = velocityChangeVector.normalized * maxVelocityChange;  
  387.     }  
  388.     // If we're in the air and don't have control, don't apply any velocity change at all.  
  389.     // If we're on the ground and don't have control we do apply it - it will correspond to friction.  
  390.     if (grounded || canControl)  
  391.         velocity += velocityChangeVector;  
  392.    
  393.     if (grounded) {  
  394.         // When going uphill, the CharacterController will automatically move up by the needed amount.  
  395.         // Not moving it upwards manually prevent risk of lifting off from the ground.  
  396.         // When going downhill, DO move down manually, as gravity is not enough on steep hills.  
  397.         velocity.y = Mathf.Min(velocity.y, 0);  
  398.     }  
  399.    
  400.     return velocity;  
  401. }  
  402.    
  403. private Vector3 ApplyGravityAndJumping (Vector3 velocity) {  
  404.    
  405.     if (!inputJump || !canControl) {  
  406.         jumping.holdingJumpButton = false;  
  407.         jumping.lastButtonDownTime = -100;  
  408.     }  
  409.    
  410.     if (inputJump && jumping.lastButtonDownTime < 0 && canControl)  
  411.         jumping.lastButtonDownTime = Time.time;  
  412.    
  413.     if (grounded)  
  414.         velocity.y = Mathf.Min(0, velocity.y) - movement.gravity * Time.deltaTime;  
  415.     else {  
  416.         velocity.y = movement.velocity.y - movement.gravity * Time.deltaTime;  
  417.    
  418.         // When jumping up we don't apply gravity for some time when the user is holding the jump button.  
  419.         // This gives more control over jump height by pressing the button longer.  
  420.         if (jumping.jumping && jumping.holdingJumpButton) {  
  421.             // Calculate the duration that the extra jump force should have effect.  
  422.             // If we're still less than that duration after the jumping time, apply the force.  
  423.             if (Time.time < jumping.lastStartTime + jumping.extraHeight / CalculateJumpVerticalSpeed(jumping.baseHeight)) {  
  424.                 // Negate the gravity we just applied, except we push in jumpDir rather than jump upwards.  
  425.                 velocity += jumping.jumpDir * movement.gravity * Time.deltaTime;  
  426.             }  
  427.         }  
  428.    
  429.         // Make sure we don't fall any faster than maxFallSpeed. This gives our character a terminal velocity.  
  430.         velocity.y = Mathf.Max (velocity.y, -movement.maxFallSpeed);  
  431.     }  
  432.    
  433.     if (grounded) {  
  434.         // Jump only if the jump button was pressed down in the last 0.2 seconds.  
  435.         // We use this check instead of checking if it's pressed down right now  
  436.         // because players will often try to jump in the exact moment when hitting the ground after a jump  
  437.         // and if they hit the button a fraction of a second too soon and no new jump happens as a consequence,  
  438.         // it's confusing and it feels like the game is buggy.  
  439.         if (jumping.enabled && canControl && (Time.time - jumping.lastButtonDownTime < 0.2)) {  
  440.             grounded = false;  
  441.             jumping.jumping = true;  
  442.             jumping.lastStartTime = Time.time;  
  443.             jumping.lastButtonDownTime = -100;  
  444.             jumping.holdingJumpButton = true;  
  445.    
  446.             // Calculate the jumping direction  
  447.             if (TooSteep())  
  448.                 jumping.jumpDir = Vector3.Slerp(Vector3.up, groundNormal, jumping.steepPerpAmount);  
  449.             else  
  450.                 jumping.jumpDir = Vector3.Slerp(Vector3.up, groundNormal, jumping.perpAmount);  
  451.    
  452.             // Apply the jumping force to the velocity. Cancel any vertical velocity first.  
  453.             velocity.y = 0;  
  454.             velocity += jumping.jumpDir * CalculateJumpVerticalSpeed (jumping.baseHeight);  
  455.    
  456.             // Apply inertia from platform  
  457.             if (movingPlatform.enabled &&  
  458.                 (movingPlatform.movementTransfer == MovementTransferOnJump.InitTransfer ||  
  459.                 movingPlatform.movementTransfer == MovementTransferOnJump.PermaTransfer)  
  460.             ) {  
  461.                 movement.frameVelocity = movingPlatform.platformVelocity;  
  462.                 velocity += movingPlatform.platformVelocity;  
  463.             }  
  464.    
  465.             SendMessage("OnJump", SendMessageOptions.DontRequireReceiver);  
  466.         }  
  467.         else {  
  468.             jumping.holdingJumpButton = false;  
  469.         }  
  470.     }  
  471.    
  472.     return velocity;  
  473. }  
  474.    
  475. void OnControllerColliderHit (ControllerColliderHit hit) {  
  476.     if (hit.normal.y > 0 && hit.normal.y > groundNormal.y && hit.moveDirection.y < 0) {  
  477.         if ((hit.point - movement.lastHitPoint).sqrMagnitude > 0.001 || lastGroundNormal == Vector3.zero)  
  478.             groundNormal = hit.normal;  
  479.         else  
  480.             groundNormal = lastGroundNormal;  
  481.    
  482.         movingPlatform.hitPlatform = hit.collider.transform;  
  483.         movement.hitPoint = hit.point;  
  484.         movement.frameVelocity = Vector3.zero;  
  485.     }  
  486. }  
  487.    
  488. private IEnumerator SubtractNewPlatformVelocity () {  
  489.     // When landing, subtract the velocity of the new ground from the character's velocity  
  490.     // since movement in ground is relative to the movement of the ground.  
  491.     if (movingPlatform.enabled &&  
  492.         (movingPlatform.movementTransfer == MovementTransferOnJump.InitTransfer ||  
  493.         movingPlatform.movementTransfer == MovementTransferOnJump.PermaTransfer)  
  494.     ) {  
  495.         // If we landed on a new platform, we have to wait for two FixedUpdates  
  496.         // before we know the velocity of the platform under the character  
  497.         if (movingPlatform.newPlatform) {  
  498.             Transform platform  = movingPlatform.activePlatform;  
  499.             yield return new WaitForFixedUpdate();  
  500.             yield return new WaitForFixedUpdate();  
  501.             if (grounded && platform == movingPlatform.activePlatform)  
  502.                 yield return 1;  
  503.         }  
  504.         movement.velocity -= movingPlatform.platformVelocity;  
  505.     }  
  506. }  
  507.    
  508. private bool MoveWithPlatform () {  
  509.     return (  
  510.         movingPlatform.enabled  
  511.         && (grounded || movingPlatform.movementTransfer == MovementTransferOnJump.PermaLocked)  
  512.         && movingPlatform.activePlatform != null  
  513.     );  
  514. }  
  515.    
  516. private Vector3 GetDesiredHorizontalVelocity () {  
  517.     // Find desired velocity  
  518.     Vector3 desiredLocalDirection  = tr.InverseTransformDirection(inputMoveDirection);  
  519.     float maxSpeed  = MaxSpeedInDirection(desiredLocalDirection);  
  520.     if (grounded) {  
  521.         // Modify max speed on slopes based on slope speed multiplier curve  
  522.         var movementSlopeAngle = Mathf.Asin(movement.velocity.normalized.y)  * Mathf.Rad2Deg;  
  523.         maxSpeed *= movement.slopeSpeedMultiplier.Evaluate(movementSlopeAngle);  
  524.     }  
  525.     return tr.TransformDirection(desiredLocalDirection * maxSpeed);  
  526. }  
  527.    
  528. private Vector3 AdjustGroundVelocityToNormal (Vector3 hVelocity, Vector3 groundNormal) {  
  529.     Vector3 sideways  = Vector3.Cross(Vector3.up, hVelocity);  
  530.     return Vector3.Cross(sideways, groundNormal).normalized * hVelocity.magnitude;  
  531. }  
  532.    
  533. private bool IsGroundedTest () {  
  534.     return (groundNormal.y > 0.01);  
  535. }  
  536.    
  537. float GetMaxAcceleration (bool grounded) {  
  538.     // Maximum acceleration on ground and in air  
  539.     if (grounded)  
  540.         return movement.maxGroundAcceleration;  
  541.     else  
  542.         return movement.maxAirAcceleration;  
  543. }  
  544.    
  545. float CalculateJumpVerticalSpeed (float targetJumpHeight) {  
  546.     // From the jump height and gravity we deduce the upwards speed   
  547.     // for the character to reach at the apex.  
  548.     return Mathf.Sqrt (2 * targetJumpHeight * movement.gravity);  
  549. }  
  550.    
  551. bool IsJumping () {  
  552.     return jumping.jumping;  
  553. }  
  554.    
  555. bool IsSliding () {  
  556.     return (grounded && sliding.enabled && TooSteep());  
  557. }  
  558.    
  559. bool IsTouchingCeiling () {  
  560.     return (movement.collisionFlags & CollisionFlags.CollidedAbove) != 0;  
  561. }  
  562.    
  563. bool IsGrounded () {  
  564.     return grounded;  
  565. }  
  566.    
  567. bool TooSteep () {  
  568.     return (groundNormal.y <= Mathf.Cos(controller.slopeLimit * Mathf.Deg2Rad));  
  569. }  
  570.    
  571. Vector3 GetDirection () {  
  572.     return inputMoveDirection;  
  573. }  
  574.    
  575. void  SetControllable (bool controllable) {  
  576.     canControl = controllable;  
  577. }  
  578.    
  579. // Project a direction onto elliptical quater segments based on forward, sideways, and backwards speed.  
  580. // The function returns the length of the resulting vector.  
  581. float MaxSpeedInDirection (Vector3 desiredMovementDirection) {  
  582.     if (desiredMovementDirection == Vector3.zero)  
  583.         return 0;  
  584.     else {  
  585.         float zAxisEllipseMultiplier = (desiredMovementDirection.z > 0 ? movement.maxForwardSpeed : movement.maxBackwardsSpeed) / movement.maxSidewaysSpeed;  
  586.         Vector3 temp = new Vector3(desiredMovementDirection.x, 0, desiredMovementDirection.z / zAxisEllipseMultiplier).normalized;  
  587.         float length = new Vector3(temp.x, 0, temp.z * zAxisEllipseMultiplier).magnitude * movement.maxSidewaysSpeed;  
  588.         return length;  
  589.     }  
  590. }  
  591.    
  592. void SetVelocity (Vector3 velocity) {  
  593.     grounded = false;  
  594.     movement.velocity = velocity;  
  595.     movement.frameVelocity = Vector3.zero;  
  596.     SendMessage("OnExternalVelocity");  
  597. }  
  598.    
  599. // Require a character controller to be attached to the same game object  
  600.    
  601. //@script RequireComponent (CharacterController)  
  602. //@script AddComponentMenu ("Character/Character Motor")  
  603.    
  604. }  

接着把FPSInputControoler.js修改成C#语言。它用于第一人称控制角色移动,这里会监听主角按下的方向键最后传给CharacterMotor去计算模型的位置与旋转的角度。

FPSInputController.cs

[csharp]  view plain  copy
  1. using UnityEngine;  
  2. using System.Collections;  
  3.    
  4. /** 
  5.  *  @Author : www.xuanyusong.com  
  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. }  

MouseLook.cs因为已经是C#语言所以就不翻译了,然后是PlatFormInputController.cs 把它转成C#语言。它和FPSInputController一样会控制主角,但是它会更加精细的计算模型旋转的插值系数。

PlatformInputController.cs

[csharp]  view plain  copy
  1. using UnityEngine;  
  2. using System.Collections;  
  3.    
  4. /** 
  5.  *  @Author : www.xuanyusong.com  
  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. }  

接着是ThirdPersonCamera 我们把它改成C#语言。它主要控制第三人称视角时摄像机的控制。

ThirdPersonCamera.cs

[csharp]  view plain  copy
  1. using UnityEngine;  
  2. using System.Collections;  
  3.    
  4. /** 
  5.  *  @Author : www.xuanyusong.com  
  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我们同样把它修改成C#语言,它主要更新第三人称视角控制主角时播放的各种动画,主角移动,等等。

ThirdPersonController.cs

[csharp]  view plain  copy
  1. using UnityEngine;  
  2. using System.Collections;  
  3.    
  4. /** 
  5.  *  @Author : www.xuanyusong.com  
  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. }  
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值