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

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

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

CharacterMotor.cs  

 

001using UnityEngine;
002using System.Collections;
003  
004/**
005 *  @Author : www.xuanyusong.com
006 */
007  
008[RequireComponent(typeof(CharacterController))]
009[AddComponentMenu("Character/Character Motor")]
010  
011public class CharacterMotor : MonoBehaviour {
012  
013// Does this script currently respond to input?
014public bool canControl  = true;
015  
016public bool useFixedUpdate = true;
017  
018// For the next variables, @System.NonSerialized tells Unity to not serialize the variable or show it in the inspector view.
019// Very handy for organization!
020  
021// The current global direction we want the character to move in.
022[System.NonSerialized]
023public Vector3 inputMoveDirection = Vector3.zero;
024  
025// Is the jump button held down? We use this interface instead of checking
026// for the jump button directly so this script can also be used by AIs.
027[System.NonSerialized]
028public bool inputJump  = false;
029  
030[System.Serializable]
031public class CharacterMotorMovement
032{
033  
034    // The maximum horizontal speed when moving
035    public float maxForwardSpeed = 10.0f;
036    public float maxSidewaysSpeed = 10.0f;
037    public float maxBackwardsSpeed = 10.0f;
038  
039    // Curve for multiplying speed based on slope (negative = downwards)
040    public AnimationCurve slopeSpeedMultiplier = new AnimationCurve(new Keyframe(-90, 1), new Keyframe(0, 1), new Keyframe(90, 0));
041  
042    // How fast does the character change speeds?  Higher is faster.
043    public float maxGroundAcceleration = 30.0f;
044    public float maxAirAcceleration = 20.0f;
045  
046    // The gravity for the character
047    public float gravity = 10.0f;
048    public float maxFallSpeed = 20.0f;
049  
050    // For the next variables, @System.NonSerialized tells Unity to not serialize the variable or show it in the inspector view.
051    // Very handy for organization!
052  
053    // The last collision flags returned from controller.Move
054    [System.NonSerialized]
055    public CollisionFlags collisionFlags; 
056  
057    // We will keep track of the character's current velocity,
058    [System.NonSerialized]
059    public Vector3 velocity;
060  
061    // This keeps track of our current velocity while we're not grounded
062    [System.NonSerialized]
063    public Vector3 frameVelocity = Vector3.zero;
064  
065    [System.NonSerialized]
066    public Vector3 hitPoint = Vector3.zero;
067  
068    [System.NonSerialized]
069    public Vector3 lastHitPoint = new Vector3(Mathf.Infinity, 0, 0);
070}
071  
072public CharacterMotorMovement movement = new CharacterMotorMovement();
073  
074public enum MovementTransferOnJump {
075    None, // The jump is not affected by velocity of floor at all.
076    InitTransfer, // Jump gets its initial velocity from the floor, then gradualy comes to a stop.
077    PermaTransfer, // Jump gets its initial velocity from the floor, and keeps that velocity until landing.
078    PermaLocked // Jump is relative to the movement of the last touched floor and will move together with that floor.
079}
080  
081// We will contain all the jumping related variables in one helper class for clarity.
082[System.Serializable]
083public class CharacterMotorJumping {
084    // Can the character jump?
085    public bool enabled = true;
086  
087    // How high do we jump when pressing jump and letting go immediately
088    public float baseHeight = 1.0f;
089  
090    // We add extraHeight units (meters) on top when holding the button down longer while jumping
091    public float extraHeight = 4.1f;
092  
093    // How much does the character jump out perpendicular to the surface on walkable surfaces?
094    // 0 means a fully vertical jump and 1 means fully perpendicular.
095    public float perpAmount  = 0.0f;
096  
097    // How much does the character jump out perpendicular to the surface on too steep surfaces?
098    // 0 means a fully vertical jump and 1 means fully perpendicular.
099    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  
123public CharacterMotorJumping  jumping = new CharacterMotorJumping();
124  
125[System.Serializable]
126public 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  
159public CharacterMotorMovingPlatform movingPlatform  = new CharacterMotorMovingPlatform();
160  
161[System.Serializable]
162public 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  
178public CharacterMotorSliding sliding  = new CharacterMotorSliding();
179  
180[System.NonSerialized]
181public bool grounded = true;
182  
183[System.NonSerialized]
184public Vector3 groundNormal = Vector3.zero;
185  
186private Vector3  lastGroundNormal = Vector3.zero;
187  
188private Transform tr;
189  
190private CharacterController  controller ;
191  
192void Awake () {
193    controller = GetComponent <CharacterController>();
194    tr = transform;
195}
196  
197private 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  
325void 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  
348void Update () {
349    if (!useFixedUpdate)
350        UpdateFunction();
351}
352  
353private 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  
403private 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  
475void 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  
488private 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  
508private bool MoveWithPlatform () {
509    return (
510        movingPlatform.enabled
511        && (grounded || movingPlatform.movementTransfer == MovementTransferOnJump.PermaLocked)
512        && movingPlatform.activePlatform != null
513    );
514}
515  
516private 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  
528private 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  
533private bool IsGroundedTest () {
534    return (groundNormal.y > 0.01);
535}
536  
537float 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  
545float 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  
551bool IsJumping () {
552    return jumping.jumping;
553}
554  
555bool IsSliding () {
556    return (grounded && sliding.enabled && TooSteep());
557}
558  
559bool IsTouchingCeiling () {
560    return (movement.collisionFlags & CollisionFlags.CollidedAbove) != 0;
561}
562  
563bool IsGrounded () {
564    return grounded;
565}
566  
567bool TooSteep () {
568    return (groundNormal.y <= Mathf.Cos(controller.slopeLimit * Mathf.Deg2Rad));
569}
570  
571Vector3 GetDirection () {
572    return inputMoveDirection;
573}
574  
575void  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.
581float 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  
592void 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

01using UnityEngine;
02using System.Collections;
03  
04/**
05 *  @Author : www.xuanyusong.com
06 */
07  
08[RequireComponent(typeof(CharacterMotor))]
09[AddComponentMenu("Character/FPS Input Controller")]
10  
11public class FPSInputController : MonoBehaviour {
12  
13private CharacterMotor motor ;
14  
15// Use this for initialization
16void Awake () {
17    motor = GetComponent<CharacterMotor>();
18}
19  
20// Update is called once per frame
21void 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}

 

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

PlatformInputController.cs

01using UnityEngine;
02using System.Collections;
03  
04/**
05 *  @Author : www.xuanyusong.com
06 */
07  
08[RequireComponent(typeof(CharacterController))]
09[AddComponentMenu("Character/Platform Input Controller")]
10public class PlatformInputController : MonoBehaviour {
11  
12public bool autoRotate = true;
13public float  maxRotationSpeed = 360;
14  
15private CharacterMotor motor ;
16  
17// Use this for initialization
18void Awake () {
19    motor = GetComponent<CharacterMotor>();
20}
21  
22// Update is called once per frame
23void 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  
67Vector3 ProjectOntoPlane (Vector3 v, Vector3 normal) {
68    return v - Vector3.Project(v, normal);
69}
70  
71Vector3 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 我们把它改成C#语言。它主要控制第三人称视角时摄像机的控制。

ThirdPersonCamera.cs

001using UnityEngine;
002using System.Collections;
003  
004/**
005 *  @Author : www.xuanyusong.com
006 */
007  
008public class ThirdPersonCamera : MonoBehaviour {
009  
010public Transform cameraTransform;
011private Transform _target;
012  
013public float distance = 7.0f;
014  
015public float height = 3.0f;
016  
017public float angularSmoothLag = 0.3f;
018public float angularMaxSpeed = 15.0f;
019  
020public float heightSmoothLag = 0.3f;
021  
022public float snapSmoothLag = 0.2f;
023public float snapMaxSpeed = 720.0f;
024  
025public float clampHeadPositionScreenSpace = 0.75f;
026  
027public float lockCameraTimeout = 0.2f;
028  
029private Vector3 headOffset = Vector3.zero;
030private Vector3 centerOffset = Vector3.zero;
031  
032private float heightVelocity = 0.0f;
033private float  angleVelocity = 0.0f;
034private bool snap = false;
035private ThirdPersonController controller;
036private float targetHeight = 100000.0f; 
037  
038void Awake ()
039{
040    if(!cameraTransform && Camera.main)
041        cameraTransform = Camera.main.transform;
042    if(!cameraTransform) {
043        Debug.Log("Please assign a camera to the ThirdPersonCamera script.");
044        enabled = false;
045    }
046  
047    _target = transform;
048    if (_target)
049    {
050        controller = _target.GetComponent<ThirdPersonController>();
051    }
052  
053    if (controller)
054    {
055        CharacterController characterController  = (CharacterController)_target.collider;
056        centerOffset = characterController.bounds.center - _target.position;
057        headOffset = centerOffset;
058        headOffset.y = characterController.bounds.max.y - _target.position.y;
059    }
060    else
061        Debug.Log("Please assign a target to the camera that has a ThirdPersonController script attached.");
062  
063    Cut(_target, centerOffset);
064}
065  
066void DebugDrawStuff ()
067{
068    Debug.DrawLine(_target.position, _target.position + headOffset);
069  
070}
071  
072float  AngleDistance (float a , float b )
073{
074    a = Mathf.Repeat(a, 360);
075    b = Mathf.Repeat(b, 360);
076  
077    return Mathf.Abs(b - a);
078}
079  
080void  Apply (Transform dummyTarget, Vector3 dummyCenter)
081{
082    // Early out if we don't have a target
083    if (!controller)
084        return;
085  
086    Vector3 targetCenter = _target.position + centerOffset;
087    Vector3 targetHead = _target.position + headOffset;
088  
089//  DebugDrawStuff();
090  
091    // Calculate the current & target rotation angles
092    float originalTargetAngle = _target.eulerAngles.y;
093    float currentAngle = cameraTransform.eulerAngles.y;
094  
095    // Adjust real target angle when camera is locked
096    float targetAngle = originalTargetAngle; 
097  
098    // When pressing Fire2 (alt) the camera will snap to the target direction real quick.
099    // 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  
161void LateUpdate () {
162    Apply (transform, Vector3.zero);
163}
164  
165void  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  
183void 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

001using UnityEngine;
002using System.Collections;
003  
004/**
005 *  @Author : www.xuanyusong.com
006 */
007  
008[RequireComponent(typeof(CharacterController))]
009  
010public class ThirdPersonController : MonoBehaviour {
011  
012public AnimationClip idleAnimation ;
013public AnimationClip walkAnimation ;
014public AnimationClip runAnimation ;
015public AnimationClip jumpPoseAnimation;
016  
017public float walkMaxAnimationSpeed  = 0.75f;
018public float trotMaxAnimationSpeed  = 1.0f;
019public float runMaxAnimationSpeed  = 1.0f;
020public float jumpAnimationSpeed  = 1.15f;
021public float landAnimationSpeed  = 1.0f;
022  
023private Animation _animation;
024  
025enum CharacterState
026{
027    Idle = 0,
028    Walking = 1,
029    Trotting = 2,
030    Running = 3,
031    Jumping = 4,
032}
033  
034private CharacterState _characterState;
035  
036// The speed when walking
037float walkSpeed = 2.0f;
038// after trotAfterSeconds of walking we trot with trotSpeed
039float trotSpeed = 4.0f;
040// when pressing "Fire3" button (cmd) we start running
041float runSpeed = 6.0f;
042  
043float inAirControlAcceleration = 3.0f;
044  
045// How high do we jump when pressing jump and letting go immediately
046float jumpHeight = 0.5f;
047  
048// The gravity for the character
049float gravity = 20.0f;
050// The gravity in controlled descent mode
051float speedSmoothing = 10.0f;
052float rotateSpeed = 500.0f;
053float trotAfterSeconds = 3.0f;
054  
055bool canJump = true;
056  
057private float jumpRepeatTime = 0.05f;
058private float jumpTimeout = 0.15f;
059private float groundedTimeout = 0.25f;
060  
061// The camera doesnt start following the target immediately but waits for a split second to avoid too much waving around.
062private float lockCameraTimer = 0.0f;
063  
064// The current move direction in x-z
065private Vector3 moveDirection = Vector3.zero;
066// The current vertical speed
067private float verticalSpeed = 0.0f;
068// The current x-z move speed
069private float moveSpeed = 0.0f;
070  
071// The last collision flags returned from controller.Move
072private CollisionFlags collisionFlags; 
073  
074// Are we jumping? (Initiated with jump button and not grounded yet)
075private bool jumping = false;
076private bool jumpingReachedApex = false;
077  
078// Are we moving backwards (This locks the camera to not do a 180 degree spin)
079private bool movingBack = false;
080// Is the user pressing any keys?
081private bool isMoving = false;
082// When did the user start walking (Used for going into trot after a while)
083private float walkTimeStart = 0.0f;
084// Last time the jump button was clicked down
085private float lastJumpButtonTime = -10.0f;
086// Last time we performed a jump
087private float lastJumpTime = -1.0f;
088  
089// the height we jumped from (Used to determine for how long to apply extra jump power after jumping.)
090private float lastJumpStartHeight = 0.0f;
091  
092private Vector3 inAirVelocity = Vector3.zero;
093  
094private float lastGroundedTime = 0.0f;
095  
096private bool isControllable = true;
097  
098void Awake ()
099{
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    /*
107public var idleAnimation : AnimationClip;
108public var walkAnimation : AnimationClip;
109public var runAnimation : AnimationClip;
110public 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  
131void 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  
232void 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  
249void 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  
270float 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  
277void  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  
288void  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  
388void  OnControllerColliderHit (ControllerColliderHit hit )
389{
390//  Debug.DrawRay(hit.point, hit.normal);
391    if (hit.moveDirection.y > 0.01f)
392        return;
393}
394  
395float GetSpeed () {
396    return moveSpeed;
397}
398  
399public bool IsJumping () {
400    return jumping;
401}
402  
403bool IsGrounded () {
404    return (collisionFlags & CollisionFlags.CollidedBelow) != 0;
405}
406  
407Vector3 GetDirection () {
408    return moveDirection;
409}
410  
411public bool IsMovingBackwards () {
412    return movingBack;
413}
414  
415public float GetLockCameraTimer ()
416{
417    return lockCameraTimer;
418}
419  
420bool IsMoving ()
421{
422    return Mathf.Abs(Input.GetAxisRaw("Vertical")) + Mathf.Abs(Input.GetAxisRaw("Horizontal")) > 0.5f;
423}
424  
425bool HasJumpReachedApex ()
426{
427    return jumpingReachedApex;
428}
429  
430bool IsGroundedWithTimeout ()
431{
432    return lastGroundedTime + groundedTimeout > Time.time;
433}
434  
435void Reset ()
436{
437    gameObject.tag = "Player";
438}
439  
440}

 最后我们用修改的脚本来控制第三人称视角主角的移动,直接上图大家仔细看看监测面板视图中的脚本绑定,这里问题不大,图片如果看不清点击即可查看大图。乖~~~

 

 

脚本终于全部翻译完毕,其实在开发中大家可以去丰富这些脚本,灵活的运用它们。感谢Unity圣典的站长专门花钱买模型让我来写教程与录制视频教程。嚯嚯 既然是买的模型 我就不提供下载了 哇咔咔。

最后MOMO祝大家学习愉快。下回写点游戏AI的东西,让游戏中的怪物在更加聪明点吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是使用 C# 在 Unity 中编写一个基本的第一人称角色控制器的示例代码。这个控制器将使用键盘和鼠标来移动和旋转角色。 首先,你需要在 Unity 中创建一个空对象,并将其命名为“Player”。然后将以下代码添加到该对象的脚本组件中: ``` using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerController : MonoBehaviour { public float speed = 10.0f; public float sensitivity = 5.0f; private CharacterController controller; private Camera cam; private float moveFB; private float moveLR; private float rotX; private float rotY; // Start is called before the first frame update void Start() { controller = GetComponent<CharacterController>(); cam = GetComponentInChildren<Camera>(); } // Update is called once per frame void Update() { moveFB = Input.GetAxis("Vertical") * speed; moveLR = Input.GetAxis("Horizontal") * speed; rotX = Input.GetAxis("Mouse X") * sensitivity; rotY = Input.GetAxis("Mouse Y") * sensitivity; Vector3 movement = new Vector3(moveLR, 0, moveFB); transform.Rotate(0, rotX, 0); cam.transform.Rotate(-rotY, 0, 0); movement = transform.rotation * movement; controller.Move(movement * Time.deltaTime); } } ``` 这段代码首先定义了一些公共变量,包括速度和灵敏度。然后在 Start() 方法中,它获取了该对象的 CharacterController 和 Camera 组件。在 Update() 方法中,它获取了键盘和鼠标输入,并使用它们来移动和旋转玩家角色。 在这个示例中,键盘的 W 和 S 键控制前后移动,A 和 D 键控制左右移动。鼠标的 X 和 Y 轴控制左右旋转和上下旋转。 你可以根据需要修改这段代码,以便更好地适应你的项目需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值