1. 程式人生 > >Unity3d之角色控制器

Unity3d之角色控制器

我們要控制角色的移動,可以全部細節都由自己來實現。控制角色模型的移動,同時移動攝影機,改變視角。當然Unity也提供了一些元件,可以讓我們做更少的工作,實現我們所期望的功能。今天我們就一起系統來學習相關的內容吧。

  • Charactor Controller(角色控制器)
"角色控制器允許你在受制於碰撞的情況下很容易的進行運動,而不用處理剛體。角色控制器不受力的影響,僅僅當你呼叫Move函式時才運動。然後它將執行運動,但是受制於碰撞。"(---from unity3d官方文件)  我們通常在人物模型上加上這個元件後,就可以控制模型的移動了。要注意的一點是。加了角色控制器後,他就不受重力影響。所以要自己在move函式中處理重力的情況。即我們要自己出來y軸方向上的速度變化。

  • 兩個重要的函式
1.function SimpleMove (speed : Vector3) : bool
以一定的速度移動。將忽略Y軸上的速度。單位是m/s。重力被自動應用。建議每幀只調用一次Move或者SimpleMove。返回值是是否著地。
例子
  1. CharacterController controller= GetComponent<CharacterController>();  
  2. Vector3 forward= transform.TransformDirection(Vector3.forward);  
  3. float curSpeed = speed * Input.GetAxis (
    "Vertical");  
  4. ontroller.SimpleMove(forward * curSpeed);  
2.function Move (motion : Vector3) : CollisionFlags
通過動力來移動控制器。動力只受限制於碰撞。它將沿著碰撞器滑動。這個函式不應用任何重力

如果只是單純控制玩家的移動,那麼用Character Controller足夠了。如果還涉及到視角的切換。Unity提供了相關的元件。在專案中引入Character Controller(Asset->Import Asset),就可以將角色控制器元件匯入我們的專案了。
  • 第一人稱控制器
經典的遊戲CS就是第一人稱視角的,攝像機就是我們的視角。人物的移動,導致視角的移動。(原始碼first.unity)

1.刪除預設的攝像機
2.新建一個地形Terrain
3.從角色控制器元件中引入 First Person Controller到專案中
4.拖動First Person Controller到合適的位置
我們就可以看到效果了,以第一人稱的視角移動,巡視整個場景。滑鼠控制整體視角,方向鍵或者wasd按鈕控制攝像機的移動。
  • 第三人稱控制器
很多角色扮演遊戲(wow,dota)常用到第三人稱視角。攝像機離我們的角色保持有一定距離,可以詳細看到我們所扮演角色的各種行為動作。(原始碼third.unity)
1.建立一個地形
2.引入3rd Person Controller元件到專案中
3.修改預設攝像機的Tag為MainCamera
4.選中3rd Person Controller元件,將其 Third Person Camera 設定為MainCamera
可以看到效果了,可以看到扮演的角色。方向鍵或者wasd按鍵可以控制角色的移動,同時可以發現整個視角也會跟著移動

效果圖


  • 核心程式碼解讀
第一人稱控制器指令碼FPSInputController.js
[javascript] view plain copy 在CODE上檢視程式碼片派生到我的程式碼片
  1. function Update () {  
  2.     //獲得鍵盤或者搖桿上的方向量(鍵盤預設是方向鍵和wasd鍵控制方向)
  3.     var directionVector = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));  
  4.     //有方向變化
  5.     if (directionVector != Vector3.zero) {  
  6.         //取得方向向量的長度
  7.         var directionLength = directionVector.magnitude;  
  8.         //normal 方向向量(向量/長度)
  9.         directionVector = directionVector / directionLength;  
  10.         //修正長度不大於1
  11.         directionLength = Mathf.Min(1, directionLength);  
  12.         //為了效果更明顯,長度平方擴大
  13.         directionLength = directionLength * directionLength;  
  14.         //用我們修正後的長度來修正方向向量
  15.         directionVector = directionVector * directionLength;  
  16.     }  
  17.     // 設定移動的方向
  18.     motor.inputMoveDirection = transform.rotation * directionVector;  
  19.     //設定跳躍(預設鍵盤是空格鍵)
  20.     motor.inputJump = Input.GetButton("Jump");  
  21. }  

第三人稱角色控制器ThirdPersonController.js

[javascript] view plain copy 在CODE上檢視程式碼片派生到我的程式碼片
  1. function Update() {  
  2.     if (!isControllable)  
  3.     {  
  4.         // 清除所有的輸入,如果不處於控制
  5.         Input.ResetInputAxes();  
  6.     }  
  7.     //按了跳躍鍵
  8.     if (Input.GetButtonDown ("Jump"))  
  9.     {  
  10.         //設定按下跳躍鍵的時間
  11.         lastJumpButtonTime = Time.time;  
  12.     }  
  13.     //控制角色的方向
  14.     UpdateSmoothedMovementDirection();  
  15.     //處理重力
  16.     ApplyGravity ();  
  17.     // 處理跳躍邏輯
  18.     ApplyJumping ();  
  19.     //計算實際的動作(移動方向和重力方向的)
  20.     var movement = moveDirection * moveSpeed + Vector3 (0, verticalSpeed, 0) + inAirVelocity;  
  21.     movement *= Time.deltaTime;  
  22.     // 移動角色
  23.     var controller : CharacterController = GetComponent(CharacterController);  
  24.     collisionFlags = controller.Move(movement);  
  25.     // 動畫處理
  26.     if(_animation) {  
  27.         if(_characterState == CharacterState.Jumping) //跳躍
  28.         {  
  29.             if(!jumpingReachedApex) {//沒到達最高點,繼續向上
  30.                 _animation[jumpPoseAnimation.name].speed = jumpAnimationSpeed;  
  31.                 _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever;  
  32.                 _animation.CrossFade(jumpPoseAnimation.name);  
  33.             } else {//到了最高點,速度方向改變
  34.                 _animation[jumpPoseAnimation.name].speed = -landAnimationSpeed;  
  35.                 _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever;  
  36.                 _animation.CrossFade(jumpPoseAnimation.name);                 
  37.             }  
  38.         }   
  39.         else
  40.         {  
  41.             if(controller.velocity.sqrMagnitude < 0.1) {//沒有方向移動
  42.                 _animation.CrossFade(idleAnimation.name);//空閒狀態
  43.             }  
  44.             else
  45.             {  
  46.                 if(_characterState == CharacterState.Running) {//奔跑
  47.                     _animation[runAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0, runMaxAnimationSpeed);  
  48.                     _animation.CrossFade(runAnimation.name);      
  49.                 }  
  50.                 elseif(_characterState == CharacterState.Trotting) {//疾走
  51.                     _animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0, trotMaxAnimationSpeed);  
  52.                     _animation.CrossFade(walkAnimation.name);     
  53.                 }  
  54.                 elseif(_characterState == CharacterState.Walking) {//普通走動
  55.                     _animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0, walkMaxAnimationSpeed);  
  56.                     _animation.CrossFade(walkAnimation.name);     
  57.                 }  
  58.             }  
  59.         }  
  60.     }  
  61.     //在地上
  62.     if (IsGrounded())  
  63.     {  
  64.         //旋轉方向
  65.         transform.rotation = Quaternion.LookRotation(moveDirection);  
  66.     }     
  67.     else
  68.     {  
  69.         //在空中忽略y軸旋轉
  70.         var xzMove = movement;  
  71.         xzMove.y = 0;  
  72.         if (xzMove.sqrMagnitude > 0.001)  
  73.         {  
  74.             transform.rotation = Quaternion.LookRotation(xzMove);  
  75.         }  
  76.     }     
  77.     // 跳躍狀態,剛好到達地面
  78.     if (IsGrounded())  
  79.     {  
  80.         //記錄到達地面的時間
  81.         lastGroundedTime = Time.time;  
  82.         //空中的速度設定為0
  83.         inAirVelocity = Vector3.zero;  
  84.         //更改相關狀態
  85.         if (jumping)  
  86.         {  
  87.             jumping = false;  
  88.             SendMessage("DidLand", SendMessageOptions.DontRequireReceiver);  
  89.         }  
  90.     }  
  91. }  
第三人控制器攝像機指令碼ThirdPersonCamera.js [javascript] view plain copy 在CODE上檢視程式碼片派生到我的程式碼片
  1. function Apply (dummyTarget : Transform, dummyCenter : Vector3)  
  2. {  
  3.     // 沒有目標
  4.     if (!controller)  
  5.         return;  
  6.     //目標中心和頂點
  7.     var targetCenter = _target.position + centerOffset;  
  8.     var targetHead = _target.position + headOffset;  
  9.     //計算目標旋轉角度和當前角度
  10.     var originalTargetAngle = _target.eulerAngles.y;  
  11.     var currentAngle = cameraTransform.eulerAngles.y;  
  12.     // 調整目標的真實角度
  13.     var targetAngle = originalTargetAngle;   
  14.     //按了Fire2(alt)攝像機的方向改變會加快
  15.     if (Input.GetButton("Fire2"))  
  16.         snap = true;  
  17.     if (snap)  
  18.     {  
  19.         // 靠近角色了,重置sna