Unity3D遊戲開發從零單排(六)
阿新 • • 發佈:2019-02-16
提要
今天要實現的是一個簡單人物控制器。包括用w,a,s,d來控制人物上下左右跑動,滑鼠左擊發出連招,都是基於老的lagacy的動畫。雖然unity3d自帶有charactorcontroller,但是並不是很好用,所以人物控制相關的全部自己來實現。先上效果圖:
場景搭建
首先下載這個package,裡面包含了人物的動作還有地面的模型。將人物和地面都拖進場景中。這裡的模型預設的動畫模式是lagacy,不用修改。模型有點偏小,改變模型的scale值為10.最好不要改原始檔的scale的scale factor,可能會出現骨骼錯位的問題。
接下來給攝像機新增一個天空盒元件,新增一個unity自帶的天空盒就好。
對於人物還要新增幾個component:
新增Rigdbody來控制人物,選擇IsKinematic,這樣角色就不會被外力影響。加了CapsuleCollider讓角色 不掉下去。HeroController用來控制角色的運動和打鬥,下面會說。
角色行走
思路很簡單,通過wasd獲得行走的方向,然後對應控制角色的位移就可以了,不過在變向的時候要注意角色的平滑轉身。
首先定義 一個 列舉變數,為角色可能的狀態。
public enum ActionState { Attack_1, Attack_2, Attack_3_1, Attack_3_2, Attack_3_3, Attack_4, Fire, Jump, Run, Idle } private ActionState actionState = ActionState.Idle;
Animate函式來根據角色的狀態播放對應的動畫
void Animate() { float delayTime = -0.1f; switch (actionState) { case ActionState.Attack_3_1: delayTime = -0.1f; playerAnimation.CrossFade("Attack3-1", 0.15f); currentAnimationClip = playerAnimation["Attack3-1"].clip; break; case ActionState.Attack_3_2: delayTime = -0.1f; playerAnimation.CrossFade("Attack3-2", 0.15f); currentAnimationClip = playerAnimation["Attack3-2"].clip; break; case ActionState.Attack_3_3: delayTime = -0.1f; playerAnimation.CrossFade("Attack3-3", 0.15f); currentAnimationClip = playerAnimation["Attack3-3"].clip; break; case ActionState.Attack_4: delayTime = -0.1f; playerAnimation.CrossFade("Attack4", 0.15f); currentAnimationClip = playerAnimation["Attack4"].clip; break; case ActionState.Idle: playerAnimation.CrossFade("Idle", 0.35f); currentAnimationClip = playerAnimation["Idle"].clip; break; case ActionState.Jump: playerAnimation.CrossFade("Jump", 0.15f); currentAnimationClip = playerAnimation["Jump"].clip; break; case ActionState.Run: playerAnimation.CrossFade("Run", 0.15f); currentAnimationClip = playerAnimation["Run"].clip; break; case ActionState.Fire: playerAnimation.CrossFade("Fire", 0.15f); currentAnimationClip = playerAnimation["Fire"].clip; break; default: break; } //Switch to default if an animation is almost over if (playerAnimation[currentAnimationClip.name].time > (playerAnimation[currentAnimationClip.name].length + delayTime)){ actionState = ActionState.Idle; currentAnimationClip = playerAnimation["Idle"].clip; } }
在update函式中新增對應的邏輯函式:
// Update is called once per frame
void Update () {
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
MovementManagement (h, v);
Animate ();
}
MovementManagement函式就是根據輸入處理角色行走的
void MovementManagement(float horizontal, float vertical)
{
if(horizontal != 0f || vertical != 0f)
{
Rotating(horizontal, vertical);
actionState = ActionState.Run;
moveDirection = new Vector3(horizontal, 0.0f, vertical);
rigidbody.MovePosition(rigidbody.position + speed * moveDirection * Time.deltaTime);
}
}
平滑轉身函式(參考Unity官網的toturial)
void Rotating(float horizontal, float vertival)
{
Vector3 targetDirection = new Vector3 (horizontal, 0f, vertival);
// Create a rotation based on this new vector assuming that up is the global y axis.
Quaternion targetRotation = Quaternion.LookRotation(targetDirection, Vector3.up);
// Create a rotation that is an increment closer to the target rotation from the player's rotation.
Quaternion newRotation = Quaternion.Lerp(rigidbody.rotation, targetRotation, turnSmoothing * Time.deltaTime);
// Change the players rotation to this new rotation.
rigidbody.MoveRotation(newRotation);
}
由於這裡是簡單的平地,所以處理起來比較簡單。當需要控制角色在複雜的地形上行走的時候,比如山川丘陵,就需要角色在Y方變化了。這個時候只需要勾選角色的rigidbody component的 use gravity,然後限制rigidbody的x,z方向的移動了,x,z方向的移動要完全靠指令碼來處理。
角色連擊
首先來思考一下邏輯。角色初始值狀態是Idle,此時按下攻擊,發連招的第一招,如果玩家繼續按的話就進入第二招,依次類推,如果中途停下的話,就還是回到Idle狀態。這是最簡單的單線連招的邏輯,沒有考慮打斷,多連等情況,程式碼實現如下:
void AttackLogic()
{
if (Input.GetButtonDown ("Fire1"))
{
if(actionState != ActionState.Attack_3_1 && actionState != ActionState.Attack_3_2
&& actionState != ActionState.Attack_3_3&& actionState != ActionState.Attack_4)
{
Debug.Log ("Fire");
actionState = ActionState.Attack_3_1;
}
else if(actionState == ActionState.Attack_3_1 && playerAnimation[currentAnimationClip.name].time > 1.0f)
{
actionState = ActionState.Attack_3_2;
}
else if(actionState == ActionState.Attack_3_2 && playerAnimation[currentAnimationClip.name].time > 1.0f)
{
actionState = ActionState.Attack_3_3;
}
else if(actionState == ActionState.Attack_3_3 && playerAnimation[currentAnimationClip.name].time > 1.0f)
{
actionState = ActionState.Attack_4;
}
/*else if(actionState == ActionState.Attack_3 && playerAnimation[currentAnimationClip.name].time > 2.0f)
{
actionState = ActionState.Idle;
}*/
}
else if(Input.GetButtonDown ("Jump"))
{
actionState = ActionState.Jump;
}
else if(Input.GetButtonDown ("Fire2"))
{
actionState = ActionState.Fire;
//if (currentSkill==null)
}
}
執行一下,就可以實現最開始的那個效果了。
參考
Unity3d toturial - Stealth