說起狀態模式游戲開發者們第一個想到的一定是AI的有限狀態機FSMs,狀態模式確實是實現有限狀態機的一種方法。之後還會講狀態機的進階分層狀態機(hierarchical state machines),和pushdown自動機(pushdown automata), 本文就拿人物控制的有限狀態機來講講狀態機模式,本文例子其實是狀態模式和觀察者模式的組合,通過獲取玩家按鍵消息來改變狀態。
if (Input.GetKey(KeyCode.D)) { …設置方向向右.. if (Input.GetKey(KeyCode.LeftShift)) { ..移動..播放跑步動畫.. } else { ..移動..播放走路動畫.. } } else if (Input.GetKey(KeyCode.A)) { …設置方向向左.. if (Input.GetKey(KeyCode.LeftShift)) { ..移動..播放跑步動畫.. } else { ..移動..播放走路動畫.. } }
bool isJump = false; if (Input.GetKeyDown(KeyCode.W)) { isJump = true; } if (Input.GetKey(KeyCode.D)) { …設置方向向右.. if (Input.GetKey(KeyCode.LeftShift)) { if(!isJump) ..移動..播放跑步動畫.. else ..移動..播放跳躍動畫.. } else { if(!isJump) ..移動..播放走路動畫.. else ..移動..播放跳躍動畫.. } } else if (Input.GetKey(KeyCode.A)) { …設置方向向左.. if(!isJump) ..移動..播放跑步動畫.. else ..移動..播放跳躍動畫.. } else { if(!isJump) ..移動..播放走路動畫.. else ..移動..播放跳躍動畫.. } }
bool isCrouch = false; if (Input.GetKeyDown(KeyCode.S)) { isCrouch = true; } bool isJump = false; if (Input.GetKeyDown(KeyCode.W)&&! isCrouch) { isJump = true; } if (Input.GetKey(KeyCode.D)) { …設置方向向右.. if (Input.GetKey(KeyCode.LeftShift)) { if(!isJump&&! isCrouch) ..移動..播放跑步動畫.. else if(!isCrouch) ..移動..播放跳躍動畫.. else ..移動..播放蹲走動畫.. } else { if(!isJump&&! isCrouch) ..移動..播放跑步動畫.. else if(!isCrouch) ..移動..播放跳躍動畫.. else ..移動..播放蹲走動畫.. } } else if (Input.GetKey(KeyCode.A)) { …設置方向向左.. if(!isJump&&! isCrouch) ..移動..播放跑步動畫.. else if(!isCrouch) ..移動..播放跳躍動畫.. else ..移動..播放蹲走動畫.. } else { if(!isJump&&! isCrouch) ..移動..播放跑步動畫.. else if(!isCrouch) ..移動..播放跳躍動畫.. else ..移動..播放蹲走動畫.. } }
阿蘭圖靈提出的圖靈機就是一種狀態機,就是指一個抽象的機器,它有一條無限長的紙帶TAPE,紙帶分成了一個一個的小方格,每個方格有不同的顏色。有一個讀寫頭HEAD在紙帶上移來移去。機器頭有 一組內部狀態,還有一些固定的程序。在每個時刻,機器頭都要從當前紙帶上讀入一個方格信息,然後結合自己的內部狀態查找程序表,根據程序輸出信息到紙帶方格上,並轉換自己的內部狀態,然後進行移動。
public enum CharacterState { Idling = 0, Walking = 1, Jumping = 2, acting= 3, defending= 4, } public CharacterState heroState = CharacterState. Idling;
void handleInput() { switch(heroState) { case CharacterState. Idling: …播放空閒動畫.. if…Input.GetKey –A,D. this. heroState = CharacterState. Walking; else if…Input.GetKey –w. this. heroState = CharacterState. Jumping; else if…Input.GetKey –J. this. heroState = CharacterState. acting; else if…Input.GetKey –I. this. heroState = CharacterState. defending; break; case CharacterState. Walking: if…Input.GetKey –A,D. …CharacterController移動操作.. else…Input.GetKeyUp – A,D… this. heroState = CharacterState. Idling; break; case CharacterState. Jumping: if(Input.GetKeyUp(KeyCode.W)) …CharacterController移動操作.. if(CharacterController.isGrounded) { this. heroState = CharacterState. Idling; } break; case CharacterState. acting: …播放攻擊動畫. chargeTime += Time.timeScale / Time.deltaTime; if(chargeTime>maxTime) { this. heroState = CharacterState. Idling; chargeTime = 0; } break; case CharacterState. defending: …播放防御動畫. if(Input.GetKeyUp(KeyCode.I)) this. heroState = CharacterState. Idling; break; } }
using UnityEngine; using System.Collections; using System; public class InputEventArgs : EventArgs { public string input; public string addition1; public string addition2; public InputEventArgs(string _input, string _addition1, string _addition2) { this.input = _input; this.addition1 = _addition1; this.addition2 = _addition2; } }
public delegate void InputEventHandler(object sender, InputEventArgs e); public event InputEventHandler InputTran; InputEventArgs inputArgs = new InputEventArgs(,,); State heroStateActVer; void Start() { personCtrl = this.GetComponent(); heroStateActVer = new IdleStateActVer(this.gameObject); InputTran += new InputEventHandler(heroStateActVer.handleInput); } void Input_events(InputEventArgs e) { if (e != null) { InputTran(this, e); } } void Update() { if (Input.anyKeyDown) { foreach (char c in Input.inputString) { if (c != null) { inputArgs.input = c.ToString(); Input_events(inputArgs); } } } heroStateActVer.UpDate(); }
public void handleInput(object sender, InputEventArgs e) { input = e.input; switch (input) { case j://攻擊 …轉為攻擊狀態.. break; case i://防御 …轉為防御狀態… break; } }
using UnityEngine; using System.Collections; public class State { protected static string input; protected GameObject Person; protected Hero Person_ctrl; protected float chargeTime; protected float MaxTime; public State(GameObject _Person) { this.Person = _Person; this.Person_ctrl = _Person.GetComponent(); } public virtual void handleInput(object sender, InputEventArgs e) { } public virtual void UpDate() { } public virtual void UpDate() { } public virtual void Start() { } }
using UnityEngine; using System.Collections; public class ActState : State { public ActState(GameObject _Person) : base(_Person) { } public override void Start() { this.chargeTime = 0.0f; this.MaxTime =..攻擊動畫時間.. ..播放攻擊動畫.. } public override void handleInput(object sender, InputEventArgs e) { input = e.input; switch (input) { case j://連擊 if (chargeTime > MaxTime - 0.1f) { Person_ctrl.GetActState(1).Start(); } break; case i: //轉換為防御狀態 if (chargeTime > MaxTime - 0.1f) { Person_ctrl.SetActState(2); Person_ctrl.GetNowActState().Start(); } break; } } public override void UpDate() { if (chargeTime < MaxTime) chargeTime += Time.timeScale / Time.deltaTime; else { this.chargeTime = 0.0f; Person_ctrl.SetActState(0); Person_ctrl.GetNowActState().Start(); } } }
using UnityEngine; using System.Collections; public class AllState { public static State actState = new ActState(); public static State jumpState = new JumpState(); ……. }
private State[] hero_act_state = new State[3]; hero_act_state[0] = new IdleStateActVer(this.gameObject); hero_act_state[1] = new ActState(this.gameObject); hero_act_state[2] = new DefenseState(this.gameObject);
部分代碼已共享至github
命令模式:游戲開發設計模式之命令模式(unity3d 示例實現)
對象池模式:游戲開發設計模式之對象池模式(unity3d 示例實現)
原型模式:游戲開發設計模式之原型模式 & unity3d JSON的使用(unity3d 示例實現)博主近期渲染:最近用unity5弄的一些渲染