用23種設計模式打造一個cocos creator的游戲框架----(十二)狀態模式

1、模式標準

模式名稱:狀態模式

模式分類:行為型

模式意圖:允許一個對象在其內部狀態改變時改變它的行為。對象看起來似乎修改了它的類。

結構圖:

適用于:

1、一個對象的行為決定于它的狀態,并且它必須在運行時刻根據狀態改變它的行為。

2、一個操作中含有龐大的多分支的條件語句,且這些分支依賴丁該對象的狀態。這個狀態常用一個或多個枚舉常量表示。通常,有多個操作包含這一相同的條件結構。State模式將每一個條件分支放入一個獨立的類中。這使得開發者可以根據對象自身的情況將對象的狀態作為一個對象,這一對象可以不依賴于其他對象獨立變化。

主要成員:

  • 上下文(Context):它定義了客戶端感興趣的接口,并且維護一個指向當前狀態的實例變量。
  • 狀態抽象(State):這是一個接口或者抽象類,它定義了每個狀態必須實現的方法。
  • 具體狀態(Concrete States):它們是實現狀態接口的類,每個類對應一種狀態,且包含了該狀態下的行為實現。

2、分析與設計??

在一般的游戲開發中狀態值通常是一個枚舉值,但在狀態模式中,狀態值是一個通過實現了 IUnitState?接口的對象表示的。這種方法的優點是它更加靈活和強大,因為這個狀態值不僅僅是一個值,它還是一組行為的集合(即方法實現)。這允許您在不同的狀態之間切換行為,而不是僅僅改變一個表示狀態的值。

在游戲中的單位一般有以下幾種狀態:站立,移動,攻擊,釋放技能中,眩暈中,死亡。比較常見的是單位正在釋放一個技能,這個時候一個飛錘飛過來,將他擊暈了,他停止了技能的釋放。

接下來我們修改一下我們的意圖

意圖:允許一個對象(單位)在其內部狀態改變時(由其狀態對象來)改變它的行為。對象看起來似乎修改了它的類(實際是狀態對象干的)。

3、開始打造

export enum UnitStateType {Standing,Moving,Attacking,CastSkilling,Stuning,Die
}
export interface IUnitState {enterState(unitItem: IUnitItem): void//stand(): void; // 站立move(): void; // 移動attack(): void; // 攻擊castSkill(): void; // 釋放技能stun(): void; // 擊暈die(): void; // 死亡// getType(): UnitStateType
}
// 狀態基類,包含一個指向Unit的引用
export abstract class BaseState implements IUnitState {protected unitItem: IUnitItem;enterState(unitItem: IUnitItem) {this.unitItem = unitItem;}// 獲取狀態的type值abstract getType(): UnitStateType;// 狀態abstract stand(): void;abstract move(): void;abstract attack(): void;abstract castSkill(): void;abstract stun(): void;abstract die(): void;}

// 站立狀態
export class StandingState extends BaseState {getType(): UnitStateType {return UnitStateType.Standing;}stand() {console.log(this.unitItem, "單位已經進入站立狀態");}move() {console.log(this.unitItem, "單位準備進入移動狀態");this.unitItem.setState(new MovingState());}attack(): void {console.log(this.unitItem, "單位準備進入攻擊狀態");this.unitItem.setState(new AttackingState());}castSkill(): void {console.log(this.unitItem, "單位準備進入釋放技能狀態");this.unitItem.setState(new CastSkillingState());}stun(): void {console.log(this.unitItem, "單位準備進入擊暈狀態");this.unitItem.setState(new StuningState());}die() {console.log("單位準備進入死亡狀態");this.unitItem.setState(new DeadState());}}// 移動狀態
export class MovingState extends BaseState {getType(): UnitStateType {return UnitStateType.Moving;}stand() {console.log(this.unitItem, "單位準備進入站立狀態");this.unitItem.setState(new StandingState());}move() {console.log(this.unitItem, "單位已經進入移動狀態");}attack(): void {console.log(this.unitItem, "單位準備進入攻擊狀態");this.unitItem.setState(new AttackingState());}castSkill(): void {console.log(this.unitItem, "單位準備進入釋放技能狀態");this.unitItem.setState(new CastSkillingState());}stun(): void {console.log(this.unitItem, "單位準備進入擊暈狀態");this.unitItem.setState(new StuningState());}die() {console.log(this.unitItem, "單位準備進入死亡狀態");this.unitItem.setState(new DeadState());}}// 攻擊狀態
export class AttackingState extends BaseState {getType(): UnitStateType {return UnitStateType.Attacking;}enterState(unitItem: IUnitItem) {super.enterState(unitItem);this.doAction();}doAction() {// 執行攻擊this.unitItem.role.attack(); // 攻擊// 如果攻擊順利完成,進行清理并返回到正常狀態// 例如,設置一個延時來模擬攻擊動作的時間let attackDuration = 1000setTimeout(() => {if (this.unitItem.getCurrentState().getType() == UnitStateType.Attacking) {console.log('單位已從攻擊狀態到站立狀態')this.unitItem.getCurrentState().stand()}}, attackDuration);}stand() {console.log(this.unitItem, "單位準備進入站立狀態");this.unitItem.setState(new StandingState());}move() {console.log(this.unitItem, "單位準備進入移動狀態");this.unitItem.setState(new MovingState());}attack(): void {console.log(this.unitItem, "單位已經進入攻擊狀態");}castSkill(): void {console.log(this.unitItem, "單位準備進入釋放技能狀態");this.unitItem.setState(new CastSkillingState());}stun(): void {console.log(this.unitItem, "單位準備進入擊暈狀態");this.unitItem.setState(new StuningState());}die() {console.log(this.unitItem, "單位準備進入死亡狀態");this.unitItem.setState(new DeadState());}}// 釋放技能狀態
export class CastSkillingState extends BaseState {getType(): UnitStateType {return UnitStateType.CastSkilling;}enterState(unitItem: IUnitItem) {super.enterState(unitItem);this.doAction();}doAction() {// 執行攻擊// this.unitItem.role.attack(); // 攻擊// 如果攻擊順利完成,進行清理并返回到正常狀態// 例如,設置一個延時來模擬攻擊動作的時間let attackDuration = 1000setTimeout(() => {if (this.unitItem.getCurrentState().getType() == UnitStateType.CastSkilling) {console.log('單位已從技能釋放狀態到站立狀態')this.unitItem.getCurrentState().stand()}}, attackDuration);}stand() {console.log(this.unitItem, "單位準備進入站立狀態");this.unitItem.setState(new StandingState());}move() {console.log(this.unitItem, "單位準備進入移動狀態");this.unitItem.setState(new MovingState());}attack(): void {console.log(this.unitItem, "單位準備進入攻擊狀態");this.unitItem.setState(new AttackingState());}castSkill(): void {console.log(this.unitItem, "單位已經進入釋放技能狀態");}stun(): void {console.log(this.unitItem, "單位準備進入擊暈狀態");this.unitItem.setState(new StuningState());}die() {console.log(this.unitItem, "單位準備進入死亡狀態");this.unitItem.setState(new DeadState());}}// 擊暈狀態
export class StuningState extends BaseState {getType(): UnitStateType {return UnitStateType.Stuning;}enterState(unitItem: IUnitItem) {super.enterState(unitItem);this.stopCurrentAction();}stand() {console.log(this.unitItem, "單位準備進入站立狀態");this.unitItem.setState(new StandingState());}move() {console.log(this.unitItem, "單位準備進入移動狀態");this.unitItem.setState(new MovingState());}attack(): void {console.log(this.unitItem, "單位準備進入攻擊狀態");this.unitItem.setState(new AttackingState());}castSkill(): void {console.log(this.unitItem, "單位準備進入釋放技能狀態");this.unitItem.setState(new CastSkillingState());}stun(): void {console.log(this.unitItem, "單位已經進入擊暈狀態");}die() {console.log(this.unitItem, "單位準備進入死亡狀態");this.unitItem.setState(new DeadState());}stopCurrentAction() {console.log(this.unitItem, "單位所有動作停止,因為被擊暈");// 如果有正在進行的釋放技能的操作,這里將其中斷// 這可能包括清除技能計時器、動畫等}}
// 死亡狀態
export class DeadState extends BaseState {getType(): UnitStateType {return UnitStateType.Dead;}enterState(unitItem: IUnitItem) {super.enterState(unitItem);this.stopCurrentAction();}stand() {console.log(this.unitItem, "單位準備進入站立狀態");this.unitItem.setState(new StandingState());}move() {console.log(this.unitItem, "單位準備進入移動狀態");this.unitItem.setState(new MovingState());}attack(): void {console.log(this.unitItem, "單位準備進入攻擊狀態");this.unitItem.setState(new AttackingState());}castSkill(): void {console.log(this.unitItem, "單位準備進入釋放技能狀態");this.unitItem.setState(new CastSkillingState());}stun(): void {console.log(this.unitItem, "單位準備進入擊暈狀態");this.unitItem.setState(new StuningState());}die() {console.log(this.unitItem, "單位已經進入死亡狀態");}stopCurrentAction() {console.log(this.unitItem, "單位所有動作停止,因為已死亡");// 如果有正在進行的釋放技能的操作,這里將其中斷// 這可能包括清除技能計時器、動畫等}
}

接著是單位里的

export class UnitItem  extends Component implements IItem, IUnitItem {ad: number = 100;mp: number = 0;role: Fighter;private currentState: IUnitState = null;accept(visitor: IAttackVisitor) {visitor.visitUnitItem(this)}setRole(role: Fighter): void {this.role = role;}setState(state: IUnitState) {this.currentState = state;state.enterState(this);}getCurrentState(): IUnitState {if (this.currentState == null) {this.setState(new StandingState())}return this.currentState;}move() {this.getCurrentState().move()}idle() {this.getCurrentState().stand()}attack(unitItem: UnitItem<T>) {if (!this.canAttack()) {// 不能處理攻擊的邏輯,可能是顯示消息或者進入其他狀態return;}// 嘗試進入攻擊狀態this.getCurrentState().attack()let damage = this.adlet attackVisitor = new MonomerAttackVisitor(damage)unitItem.accept(attackVisitor)// 臨時 todo 刪除console.log('假裝本次攻擊帶有擊暈效果')unitItem.getCurrentState().stun()}skill() {if (!this.canSkill()) {// 不能處理攻擊的邏輯,可能是顯示消息或者進入其他狀態return;}// 嘗試進入攻擊狀態this.getCurrentState().castSkill()}die() {this.getCurrentState().die()}private canSkill(): boolean {// 檢查單位是否可以進行技能攻擊// 例如,單位是否處于暈眩狀態或者攻擊是否冷卻中if (this.mp < 100) {console.log('不能處理skill攻擊的邏輯,因為魔法值不足100')return false}if (this.getCurrentState().getType() == UnitStateType.CastSkilling) {console.log('不能處理skill攻擊的邏輯,因為已經處于技能釋放中')return false}if (this.getCurrentState().getType() == UnitStateType.Stuning) {console.log('不能處理skill攻擊的邏輯,因為已經被擊暈')return false}if (this.getCurrentState().getType() == UnitStateType.Dead) {console.log('不能處理skill攻擊的邏輯,因為已經死亡')return false}return true;}private canAttack(): boolean {// 檢查單位是否可以進行攻擊// 例如,單位是否處于暈眩狀態或者攻擊是否冷卻中if (this.getCurrentState().getType() == UnitStateType.Attacking) {console.log('不能處理攻擊的邏輯,因為已經處于攻擊中')return false}if (this.getCurrentState().getType() == UnitStateType.Stuning) {console.log('不能處理攻擊的邏輯,因為已經被擊暈')return false}if (this.getCurrentState().getType() == UnitStateType.Dead) {console.log('不能處理攻擊的邏輯,因為已經死亡')return false}return true;}
}

4、開始使用

        let unitItem001 = xhgame.itemFactory.createUnitItem('kuloubing', UnitType.UnitSpine)let unitItem002 = xhgame.itemFactory.createUnitItem('kuloubing', UnitType.UnitSpine)unitItem001.idle()unitItem002.idle()unitItem002.skill()unitItem002.mp = 100;unitItem002.skill()unitItem001.setRole(new Cavalry(new Sword()));console.log('unitItem001(騎兵)準備使用【劍】對unitItem002發起了攻擊')unitItem001.attack(unitItem002)unitItem001.setRole(new Cavalry(new Bow()));console.log('unitItem001(騎兵)準備使用【弓】對unitItem002發起了攻擊')unitItem001.attack(unitItem002)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/211957.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/211957.shtml
英文地址,請注明出處:http://en.pswp.cn/news/211957.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【C語言】字符串函數strcpystrcatstrcmpstrstr的使?和模擬實現

&#x1f308;write in front :&#x1f50d;個人主頁 &#xff1a; 啊森要自信的主頁 ??真正相信奇跡的家伙&#xff0c;本身和奇跡一樣了不起啊&#xff01; 歡迎大家關注&#x1f50d;點贊&#x1f44d;收藏??留言&#x1f4dd;>希望看完我的文章對你有小小的幫助&am…

OCSP檢查數字證書狀態詳解

文章目錄 1. OCSP 的基本原理2. OCSP 的工作流程3. OCSP 的優勢和不足4. OCSP Stapling5. OCSP 配置 OCSP&#xff08;Online Certificate Status Protocol&#xff09;是一種用于檢查數字證書狀態的協議。它提供了一種實時查詢證書狀態的方式&#xff0c;以確定證書是否被吊銷…

prototype、__proto__、constructor、原型、原型鏈

結論&#xff1a; __proto__和constructor屬性是對象所獨有的&#xff1b; prototype屬性是函數所獨有的&#xff0c;由于函數也是一種對象&#xff0c;所以函數也擁有__proto__和constructor屬性&#xff1b;__proto__屬性的作用就是當訪問一個對象的屬性時&#xff0c;如果該…

C++ 多態性(Polymorphism)和 虛函數(Virtual Functions)

在 C 中&#xff0c;多態性&#xff08;Polymorphism&#xff09;是面向對象編程的一個重要概念&#xff0c;它允許通過基類指針或引用來調用派生類對象的特定方法。虛函數&#xff08;Virtual Functions&#xff09;是實現多態性的一種機制&#xff0c;通過在基類中聲明虛函數…

InputStream和OutputStream速通

InputStream和OutputStream 輸入流&#xff08;InputStream&#xff09;&#xff1a; InputStream是抽象類&#xff0c;用于從各種數據源&#xff08;如文件、網絡連接、內存等&#xff09;讀取字節流。常見的子類包括FileInputStream、ByteArrayInputStream和SocketInputStrea…

電源小白入門學習1——電源系統架構和相關指標

電源小白入門學習1——電源系統架構和相關指標 電源系統架構電源系統的指標及測量方法電源的效率電源的靜態電流輸出電壓調整率紋波測量的注意事項動態負載測試 在開始本期內容之氣&#xff0c;我先簡單介紹一下我們電源小白學習系列內容&#xff1a;首先我是一個嵌入式小白&am…

【InsCode】新的代碼管理工具inscode教程它和Git以及SVN的區別

InsCode 實踐分享 InsCodeGitSVN類型代碼管理工具分布式版本控制系統集中式版本控制系統分支管理支持強大的分支管理功能&#xff0c;包括創建、合并和刪除分支支持分支管理&#xff0c;操作簡單快捷支持分支管理&#xff0c;但操作相對復雜代碼托管提供代碼托管功能&#xff…

在VSCode中運行Python腳本文件時如何傳參

以下實驗所處的操作系統環境說明&#xff1a; OS版本MacOSMonterey 12.1VSCodeOctober 2023 (version 1.84.2) 一、背景 在 VSCode 中寫好 Python 腳本后&#xff0c;如果要運行起來&#xff0c;可以怎么做呢&#xff1f; 一般有以下幾種方式&#xff1a; 1、直接在 VSCode…

sentinel整合nacos配置中心持久化

在網上找了很多的資料&#xff0c;發現sentinel整合nacos持久化的博文和視頻大多數都只有改造限流部分的教程&#xff0c;并且都需要修改前端&#xff0c;略顯麻煩&#xff0c;至于剩下的熔斷、熱點流控、授權的更是沒有相關的改造教程&#xff0c;最后在知乎的看到一篇文章后讓…

百科詞條可以刪除嗎?如何刪除自己的百度百科?

近日&#xff0c;小馬識途營銷顧問接到不少客戶刪除自己百科詞條的咨詢&#xff0c;有不少人自己并沒有去建立百科詞條&#xff0c;但是網上已經有了&#xff0c;有的信息不正確&#xff0c;甚至有的信息是負能量的&#xff0c;對當事人自己造成一定的困擾&#xff0c;所以尋求…

pytorch學習4-簡易卷積實現

系列文章目錄 pytorch學習1-數據加載以及Tensorboard可視化工具pytorch學習2-Transforms主要方法使用pytorch學習3-torchvisin和Dataloader的使用pytorch學習4-簡易卷積實現pytorch學習5-最大池化層的使用pytorch學習6-非線性變換&#xff08;ReLU和sigmoid&#xff09;pytorc…

【鴻蒙學習網絡】

鴻蒙技術學習相關學習資料 官方文檔&#xff1a;華為官方提供了鴻蒙開發者文檔&#xff0c;包括開發指南、API參考和示例代碼等。您可以訪問華為開發者中心網站&#xff08;https://developer.harmonyos.com/&#xff09;獲取最新的官方文檔和教程。在 線 課 程 &#xff1a; …

PbootCMS 前臺RCE漏洞復現

0x01 產品簡介 PbootCMS是全新內核且永久開源免費的PHP企業網站開發建設管理系統,是一套高效、簡潔、 強悍的可免費商用的PHP CMS源碼,能夠滿足各類企業網站開發建設的需要 0x02 漏洞概述 PbootCMS v<=3.1.6版本中存在模板注入,攻擊者可構造特定的鏈接利用該漏洞,執行…

線程及實現方式

一、線程 線程是一個基本的CPU執行單元&#xff0c;也是程序執行流的最小單位。引入線程之后&#xff0c;不僅是進程之間可以并發&#xff0c;進程內的各線程之間也可以并發&#xff0c;從而進一步提升了系統的并發度&#xff0c;使得一個進程內也可以并發處理各種任務&#x…

c語言的內存函數

memcpy函數 1.調用形式void*memcpy(void*p1,void*p2,int n)&#xff0c;表示從第二個位置復制n個字節到第一個位置&#xff0c;而指針類型為void的原因是他可以復制整型字符型甚至指針結構體類型的數據 2.在遇到\0的時候不會停下來&#xff0c;因為函數執行拷貝靠字節數&…

【Hive】——安裝部署

1 MetaData&#xff08;元數據&#xff09; 2 MetaStore &#xff08;元數據服務&#xff09; 3 MetaStore配置方式 3.1 內嵌模式 3.2 本地模式 3.3 遠程模式 4 安裝前準備 <!-- 整合hive --><property><name>hadoop.proxyuser.root.hosts</name><v…

Java+Swing: 主界面組件布局 整理9

說明&#xff1a;這篇博客是在上一篇的基礎上的&#xff0c;因為上一篇已經將界面的框架搭好了&#xff0c;這篇主要是將里面的組件完善。 分為三個部分&#xff0c;北邊的組件、中間的組件、南邊的組件 // 放置北邊的組件layoutNorth(contentPane);// 放置中間的 Jtablelayou…

Tair(3):Tair入門demo

新建一個maven項目 1 導入依賴 <dependency><groupId>com.taobao.tair</groupId><artifactId>tair-client</artifactId><version>2.3.5</version></dependency><dependency><groupId>com.alibaba</groupId>…

計算日期到天數轉換

根據輸入的日期&#xff0c;計算是這一年的第幾天。 保證年份為4位數且日期合法。 輸入描述&#xff1a;輸入一行&#xff0c;空格分割&#xff0c;分別是年&#xff0c;月&#xff0c;日 輸出描述&#xff1a;輸出是這一年的第幾天 輸入&#xff1a;2012 12 31 輸出&#xff…

Python計時器

制作一個簡單的Python計時器 在本教程中&#xff0c;我們將學習如何使用Python制作一個基礎的計時器。這個計時器將能夠開始計時、暫停、繼續和重置時間。 設計思路 為了建立一個計時器&#xff0c;我們需要定義一個能夠跟蹤時間的變量&#xff0c;并且定期更新顯示的時間。…