1. 程式人生 > >Unity手遊之路角色控制器

Unity手遊之路角色控制器

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

  • Charactor Controller(角色控制器)
"角色控制器允許你在受制於碰撞的情況下很容易的進行運動,而不用處理剛體。角色控制器不受力的影響,僅僅當你呼叫Move函式時才運動。然後它將執行運動,但是受制於碰撞。"(---from unity3d官方文件)  我們通常在人物模型上加上這個元件後,就可以控制模型的移動了。要注意的一點是。加了角色控制器後,他就不受重力影響。所以要自己在move函式中處理重力的情況。即我們要自己出來y軸方向上的速度變化。
  • 兩個重要的函式
1.function SimpleMove (speed : Vector3) : bool
以一定的速度移動。將忽略Y軸上的速度。單位是m/s。重力被自動應用。建議每幀只調用一次Move或者SimpleMove。返回值是是否著地。
例子
CharacterController controller= GetComponent<CharacterController>();
Vector3 forward= transform.TransformDirection(Vector3.forward);
float curSpeed = speed * Input.GetAxis ("Vertical");
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
function Update () {
	//獲得鍵盤或者搖桿上的方向量(鍵盤預設是方向鍵和wasd鍵控制方向)
	var directionVector = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
	
    //有方向變化
	if (directionVector != Vector3.zero) {
        //取得方向向量的長度
	    var directionLength = directionVector.magnitude;
        //normal 方向向量(向量/長度)
		directionVector = directionVector / directionLength;
		
        //修正長度不大於1
		directionLength = Mathf.Min(1, directionLength);
		
        //為了效果更明顯,長度平方擴大
		directionLength = directionLength * directionLength;
		
        //用我們修正後的長度來修正方向向量
		directionVector = directionVector * directionLength;
	}
	
	// 設定移動的方向
	motor.inputMoveDirection = transform.rotation * directionVector;
    //設定跳躍(預設鍵盤是空格鍵)
	motor.inputJump = Input.GetButton("Jump");
}

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

function Update() {
    if (!isControllable)
    {
        // 清除所有的輸入,如果不處於控制
        Input.ResetInputAxes();
    }
    //按了跳躍鍵
    if (Input.GetButtonDown ("Jump"))
    {
        //設定按下跳躍鍵的時間
        lastJumpButtonTime = Time.time;
    }
    //控制角色的方向
    UpdateSmoothedMovementDirection();
    //處理重力
    ApplyGravity ();
    // 處理跳躍邏輯
    ApplyJumping ();
    //計算實際的動作(移動方向和重力方向的)
    var movement = moveDirection * moveSpeed + Vector3 (0, verticalSpeed, 0) + inAirVelocity;
    movement *= Time.deltaTime;
    // 移動角色
    var controller : CharacterController = GetComponent(CharacterController);
    collisionFlags = controller.Move(movement);
    // 動畫處理
    if(_animation) {
        if(_characterState == CharacterState.Jumping) //跳躍
        {
            if(!jumpingReachedApex) {//沒到達最高點,繼續向上
                _animation[jumpPoseAnimation.name].speed = jumpAnimationSpeed;
                _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever;
                _animation.CrossFade(jumpPoseAnimation.name);
            } else {//到了最高點,速度方向改變
                _animation[jumpPoseAnimation.name].speed = -landAnimationSpeed;
                _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever;
                _animation.CrossFade(jumpPoseAnimation.name);				
            }
        } 
        else 
        {
            if(controller.velocity.sqrMagnitude < 0.1) {//沒有方向移動
                _animation.CrossFade(idleAnimation.name);//空閒狀態
            }
            else 
            {
                if(_characterState == CharacterState.Running) {//奔跑
                    _animation[runAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0, runMaxAnimationSpeed);
                    _animation.CrossFade(runAnimation.name);	
                }
                else if(_characterState == CharacterState.Trotting) {//疾走
                    _animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0, trotMaxAnimationSpeed);
                    _animation.CrossFade(walkAnimation.name);	
                }
                else if(_characterState == CharacterState.Walking) {//普通走動
                    _animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0, walkMaxAnimationSpeed);
                    _animation.CrossFade(walkAnimation.name);	
                }
				
            }
        }
    }
    //在地上
    if (IsGrounded())
    {
        //旋轉方向
        transform.rotation = Quaternion.LookRotation(moveDirection);
			
    }	
    else
    {
        //在空中忽略y軸旋轉
        var xzMove = movement;
        xzMove.y = 0;
        if (xzMove.sqrMagnitude > 0.001)
        {
            transform.rotation = Quaternion.LookRotation(xzMove);
        }
    }	
    // 跳躍狀態,剛好到達地面
    if (IsGrounded())
    {
        //記錄到達地面的時間
        lastGroundedTime = Time.time;
        //空中的速度設定為0
        inAirVelocity = Vector3.zero;
        //更改相關狀態
        if (jumping)
        {
            jumping = false;
            SendMessage("DidLand", SendMessageOptions.DontRequireReceiver);
        }
    }
}
第三人控制器攝像機指令碼ThirdPersonCamera.js
function Apply (dummyTarget : Transform, dummyCenter : Vector3)
{
	// 沒有目標
	if (!controller)
		return;
	//目標中心和頂點
	var targetCenter = _target.position + centerOffset;
	var targetHead = _target.position + headOffset;
    //計算目標旋轉角度和當前角度
	var originalTargetAngle = _target.eulerAngles.y;
	var currentAngle = cameraTransform.eulerAngles.y;
	// 調整目標的真實角度
	var targetAngle = originalTargetAngle; 
    //按了Fire2(alt)攝像機的方向改變會加快
	if (Input.GetButton("Fire2"))
		snap = true;
	
	if (snap)
	{
		// 靠近角色了,重置snap 
		if (AngleDistance (currentAngle, originalTargetAngle) < 3.0)
			snap = false;
		//計算當前角度
		currentAngle = Mathf.SmoothDampAngle(currentAngle, targetAngle, angleVelocity, snapSmoothLag, snapMaxSpeed);
	}
	// Normal 攝像機動作
	else
	{
        //延遲一點時間
		if (controller.GetLockCameraTimer () < lockCameraTimeout)
		{
			targetAngle = currentAngle;
		}
		// 向後走的時候鎖住攝像機
		if (AngleDistance (currentAngle, targetAngle) > 160 && controller.IsMovingBackwards ())
			targetAngle += 180;//旋轉180
        //插值改變相機角度
		currentAngle = Mathf.SmoothDampAngle(currentAngle, targetAngle, angleVelocity, angularSmoothLag, angularMaxSpeed);
	}
    //當跳躍時
	// When jumping don't move camera upwards but only down!
	if (controller.IsJumping ())
	{
		// 計算目標的高度
		var newTargetHeight = targetCenter.y + height;
		if (newTargetHeight < targetHeight || newTargetHeight - targetHeight > 5)
			targetHeight = targetCenter.y + height;
	}
	// 走動時,改變高度
	else
	{
		targetHeight = targetCenter.y + height;
	}
	// 計算當前高度
	var currentHeight = cameraTransform.position.y;
	currentHeight = Mathf.SmoothDamp (currentHeight, targetHeight, heightVelocity, heightSmoothLag);
	// 按角度旋轉、
	var currentRotation = Quaternion.Euler (0, currentAngle, 0);
    //更新相機位置
	cameraTransform.position = targetCenter;
	cameraTransform.position += currentRotation * Vector3.back * distance;
	// 設定相機的高度
	cameraTransform.position.y = currentHeight;
	//攝像機一直朝向目標
	SetUpRotation(targetCenter, targetHead);
}
  • 總結

角色控制,可以方便的控制遊戲的視角。在很多遊戲中,可以直接使用該元件,減少我們的重複開發工作

  • 原始碼

http://pan.baidu.com/s/1BwArJ

  • 參考文件
http://unity3d.com/learn