Phaserjs V2的state狀態解析及技巧

用phaserjs開發了好多游戲了,但是對phaser還是了解不深,只知道怎么去用,今天就特意花點時間研究下phaser的狀態管理到底是怎么回事。

首先,new Phaser.Game,以下是Phaser.Game的部分源碼:

Phaser.Game = function (width, height, renderer, parent, state, transparent, antialias, physicsConfig) {/*** @property {number} id - Phaser Game ID* @readonly*/this.id = Phaser.GAMES.push(this) - 1;...........................(省略的代碼)//  Parse the configuration object (if any)if (arguments.length === 1 && typeof arguments[0] === 'object'){this.parseConfig(arguments[0]);}else{this.config = { enableDebug: true };if (typeof width !== 'undefined'){this._width = width;}if (typeof height !== 'undefined'){this._height = height;}if (typeof renderer !== 'undefined'){this.renderType = renderer;}if (typeof parent !== 'undefined'){this.parent = parent;}if (typeof transparent !== 'undefined'){this.transparent = transparent;}if (typeof antialias !== 'undefined'){this.antialias = antialias;}this.rnd = new Phaser.RandomDataGenerator([(Date.now() * Math.random()).toString()]);this.state = new Phaser.StateManager(this, state);}this.device.whenReady(this.boot, this);return this;};

先看this.device.whenReady(this.boot, this);這段代碼,源碼的意思是設備準備就緒或者dom文檔準備就緒后就執行boot,說白了就是DOMContentLoaded這個事件或者window的load事件的回調,一切準備就緒,執行boot,boot源碼如下:

boot: function () {if (this.isBooted){return;}this.onPause = new Phaser.Signal();this.onResume = new Phaser.Signal();this.onBlur = new Phaser.Signal();this.onFocus = new Phaser.Signal();this.isBooted = true;PIXI.game = this;this.math = Phaser.Math;this.scale = new Phaser.ScaleManager(this, this._width, this._height);this.stage = new Phaser.Stage(this);this.setUpRenderer();this.world = new Phaser.World(this);this.add = new Phaser.GameObjectFactory(this);this.make = new Phaser.GameObjectCreator(this);this.cache = new Phaser.Cache(this);this.load = new Phaser.Loader(this);this.time = new Phaser.Time(this);this.tweens = new Phaser.TweenManager(this);this.input = new Phaser.Input(this);this.sound = new Phaser.SoundManager(this);this.physics = new Phaser.Physics(this, this.physicsConfig);this.particles = new Phaser.Particles(this);this.create = new Phaser.Create(this);this.plugins = new Phaser.PluginManager(this);this.net = new Phaser.Net(this);this.time.boot();this.stage.boot();this.world.boot();this.scale.boot();this.input.boot();this.sound.boot();this.state.boot();if (this.config['enableDebug']){this.debug = new Phaser.Utils.Debug(this);this.debug.boot();}else{this.debug = { preUpdate: function () {}, update: function () {}, reset: function () {}, isDisabled: true };}this.showDebugHeader();this.isRunning = true;if (this.config && this.config['forceSetTimeOut']){this.raf = new Phaser.RequestAnimationFrame(this, this.config['forceSetTimeOut']);}else{this.raf = new Phaser.RequestAnimationFrame(this, false);}this._kickstart = true;if (window['focus']){if (!window['PhaserGlobal'] || (window['PhaserGlobal'] && !window['PhaserGlobal'].stopFocus)){window.focus();}}if (this.config['disableStart']){return;}if (this.cache.isReady){this.raf.start();}else{this.cache.onReady.addOnce(function () {this.raf.start();}, this);}}

很有序的初始化一些事件回調和方法,其中world,stage等等都有boot初始化方法,整個Phaser里Phaser.Stage只在這里實例化一次,僅此一次,游戲的舞臺就只有這一個stage,stage繼承PIXI.DisplayObjectContainer,到這里就都清楚了。

Phaser.World也僅此一次被實例化,它繼承自Phaser.Group,Phaser.Group也繼承自PIXI.DisplayObjectContainer,但是實例化它的時候,默認是把它添加到Phaser.World里的,

if (parent === undefined){parent = game.world;}

所以Group都是在World里,除非顯示指定stage為其parent,實際開發幾乎沒這個必要。

Phaser.GameObjectFactory類封裝了Phaser的組件,如image,sprite等,顯示組件基本都是通過game.add直接被添加到World里(bitmapData除外這里不作研究):
image: function (x, y, key, frame, group) {if (group === undefined) { group = this.world; }return group.add(new Phaser.Image(this.game, x, y, key, frame));},

接下來看下this.state = new Phaser.StateManager(this, state);這段代碼,Phaser.StateManager也是僅被實例化一次,主要用來管理游戲state的,構造函數有兩個參數game和state,game就是我們的游戲對象,stage是默認的

boot: function () {this.game.onPause.add(this.pause, this);this.game.onResume.add(this.resume, this);if (this._pendingState !== null && typeof this._pendingState !== 'string'){this.add('default', this._pendingState, true);}},

默認state的key為'default',通過game.state.add添加state的源碼:

add: function (key, state, autoStart) {if (autoStart === undefined) { autoStart = false; }var newState;if (state instanceof Phaser.State){newState = state;}else if (typeof state === 'object'){newState = state;newState.game = this.game;}else if (typeof state === 'function'){newState = new state(this.game);}this.states[key] = newState;if (autoStart){if (this.game.isBooted){this.start(key);}else{this._pendingState = key;}}return newState;},

就是一個包含init,preload,create等的object或function,或者是Phaser.State類,這個類就是封裝一個state包含的所有方法,所有方法沒有任何實現。

game.state.start源碼:

start: function (key, clearWorld, clearCache) {if (clearWorld === undefined) { clearWorld = true; }if (clearCache === undefined) { clearCache = false; }if (this.checkState(key)){//  Place the state in the queue. It will be started the next time the game loop begins.this._pendingState = key;this._clearWorld = clearWorld;this._clearCache = clearCache;if (arguments.length > 3){this._args = Array.prototype.splice.call(arguments, 3);}}},

就是檢查下是否是一個State,沒什么啊,其實真正的start是在preUpadte里,

preUpdate: function () {if (this._pendingState && this.game.isBooted){var previousStateKey = this.current;//  Already got a state running?this.clearCurrentState();this.setCurrentState(this._pendingState);this.onStateChange.dispatch(this.current, previousStateKey);if (this.current !== this._pendingState){return;}else{this._pendingState = null;}//  If StateManager.start has been called from the init of a State that ALSO has a preload, then//  onPreloadCallback will be set, but must be ignoredif (this.onPreloadCallback){this.game.load.reset(true);this.onPreloadCallback.call(this.callbackContext, this.game);//  Is the loader empty?if (this.game.load.totalQueuedFiles() === 0 && this.game.load.totalQueuedPacks() === 0){this.loadComplete();}else{//  Start the loader going as we have something in the queuethis.game.load.start();}}else{//  No init? Then there was nothing to load eitherthis.loadComplete();}}},

start的時候,this._pendingState設置了當前的state,preUpdate方法先清除上一個state,再設置當前state,

setCurrentState里調用了link方法同時初始化一些事件監聽,clearCurrentState方法調用了unlink方法同時移除一些事件監聽,link方法如下:
link: function (key) {var state = this.states[key];state.game = this.game;state.add = this.game.add;state.make = this.game.make;state.camera = this.game.camera;state.cache = this.game.cache;state.input = this.game.input;state.load = this.game.load;state.math = this.game.math;state.sound = this.game.sound;state.scale = this.game.scale;state.state = this;state.stage = this.game.stage;state.time = this.game.time;state.tweens = this.game.tweens;state.world = this.game.world;state.particles = this.game.particles;state.rnd = this.game.rnd;state.physics = this.game.physics;state.key = key;},

由此可見每個狀態都有game所擁有的幾乎所有屬性,所以每個state都相當于一個單獨的game,包括init,preload,create等等。

setCurrentState:

setCurrentState: function (key) {var state = this.states[key];this.callbackContext = state;this.link(key);//  Used when the state is set as being the current active statethis.onInitCallback = state['init'] || this.dummy;this.onPreloadCallback = state['preload'] || null;this.onLoadRenderCallback = state['loadRender'] || null;this.onLoadUpdateCallback = state['loadUpdate'] || null;this.onCreateCallback = state['create'] || null;this.onUpdateCallback = state['update'] || null;this.onPreRenderCallback = state['preRender'] || null;this.onRenderCallback = state['render'] || null;this.onResizeCallback = state['resize'] || null;this.onPausedCallback = state['paused'] || null;this.onResumedCallback = state['resumed'] || null;this.onPauseUpdateCallback = state['pauseUpdate'] || null;//  Used when the state is no longer the current active statethis.onShutDownCallback = state['shutdown'] || this.dummy;//  Reset the physics system, but not on the first state startif (this.current !== ''){this.game.physics.reset();}this.current = key;this._created = false;//  At this point key and pendingState should equal each otherthis.onInitCallback.apply(this.callbackContext, this._args);//  If they no longer do then the init callback hit StateManager.startif (key === this._pendingState){this._args = [];}this.game._kickstart = true;},

每個state在start的時候都會重新執行init,preload,create,update等方法一遍,this.onInitCallback.apply的時候還把參數傳進來了,所以如果想start?state的時候傳參數,請定義個init方法,接受初始化傳過來的data,這種模式猶如class的contructor一樣使得

state之間相互獨立,又可以相互傳值,形成一條state網狀鏈式結構,由于clearCurrentState默認clearWorld =?true,所以在切換state的時候會先game.world.shutdown();相當于移除所有舞臺元素,同時提供了shutdown方法用于關閉state時做的處理。

整個phaser的state流程是----》

初始化Phaser.Game可設置默認state ==》game.state.add(key,state);添加state,==》start state:game.state.start(key1) ==>?移除key1,game.state.start(key2) ==》如此循環,整個過程所有state共享game同時共享其所有方法和屬性。

Phaser的初衷也是以最快的速度完成一個游戲,的確這種相互獨立e又可以相互連接的state真是可以為開發節省很多很多時間。

設計思路:一個游戲先preload(一般之前會加個boot)=》menuState = 》gameState1=》gameState2=》gameState3等等=》overState? 獨立模塊或場景都可添加state,UI界面最好是繼承Group,不要做state,注意由于state切換的時候會destroy?world,所以單例或共享View界面最好在start之前全部先移除,否則會出現destroy摧毀當前的單例view的child等所有 導致單例undefined?錯誤。

轉載于:https://www.cnblogs.com/wangzisheng/p/9051839.html

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

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

相關文章

JAVA_出神入化學習路線大綱

注:參考GitHub上的項目(toBeTopJavaer)總結出來 也是自己的目標。 基礎篇:https://www.cnblogs.com/blogzcc/p/10899066.html 進階篇:https://www.cnblogs.com/blogzcc/p/10899841.html 高級篇:https://www…

Ubuntu安裝并使用sogou輸入法

1.下載搜狗輸入法的安裝包 下載地址為:http://pinyin.sogou.com/linux/ ,如下圖,要選擇與自己系統位數一致的安裝包,我的系統是64位,所以我下載64位的安裝包 2.按鍵CtrAltT打開終端,輸入以下命令切換到下載文件夾: [ht…

面試題之web

1. django和flask框架的區別? django:大而全的全的框架,重武器;內置很多組件:ORM、admin、Form、ModelForm、中間件、信號、緩存、csrf等 flask: 微型框架、可擴展強,如果開發簡單程序使用flask比較快速&am…

python 常用鏡像

pip鏡像https://pypi.tuna.tsinghua.edu.cn/simplehttps://pypi.douban.io.com/simple pip install python-qt -i https://pypi.tuna.tsinghua.edu.cn/simple清華開源軟件鏡像:(anaconda)https://mirrors.tuna.tsinghua.edu.cn/https://mirro…

flutter 幾秒前, 幾分鐘前, 幾小時前, 幾天前...

Show me the code!!! class RelativeDateFormat {static final num ONE_MINUTE 60000;static final num ONE_HOUR 3600000;static final num ONE_DAY 86400000;static final num ONE_WEEK 604800000;static final String ONE_SECOND_AGO "秒前";static final St…

CMake 使用筆記

記錄 CMake 相關知識。 Prelude:讀文檔一定要有耐心! 問題一 CLion: CMakeLists.txt 中 set(CMAKE_CXX_FLAGS -Wall) 不起作用 Solution: 改用 target_compile_options(main PUBLIC -Wall) Reference:target_compile_optionsGCC: Options to …

Docker 完全指南

Docker 最初 dotCloud 公司內部的一個業余項目Docker 基于 Go 語言Docker 項目的目標是實現輕量級的操作系統虛擬化解決方案Docker 的基礎是 Linux 容器(LXC)等技術Docker 容器的啟動可以在秒級實現,這相比傳統的虛擬機方式要快得多Docker 對…

NOIP 2016【蚯蚓】

好吧,我承認我是個智障…… 這道題一眼看上去就是個堆,然而實際上有單調性。 注意到,如果 \(q 0\) 的話,將蚯蚓的左右兩邊分開丟進兩個隊列中,則兩個隊列都是單調不增的,因為每次取出的蚯蚓長度單調不增。…

Ajax異步(客戶端測試)

客戶端測試:GET方法實現Ajax異步 var request new XMLHttpRequest(); request.open("GET","sever.php?number" document.getElementById("keyword").value); request.send(); request.onreadystatechange function(){ if(request.…

VS 添加文件添加文件成鏈接

轉載于:https://www.cnblogs.com/wsxkit/p/10907585.html

設計模式——3.觀察者模式

觀察者模式(Observer) 觀察者模式(Observer)簡介: 定義一個一對多的依賴關系,讓多個觀察者對象監聽某個主題對象,當主題對象的狀態發生改變時,主題對象則通知所有的觀察者對象&#…

Android 長按照片保存 工具類

2019獨角獸企業重金招聘Python工程師標準>>> public class ImgUtils {public static void saveImageToGallery(Context context, Bitmap bmp) {final String[] items new String[] { "保存圖片"};//圖片轉成Bitmap數組final Bitmap[] bitmap new Bitmap…

反爬機制

一.通過headers反爬蟲: Basic Auth這是一種古老的、不安全的用戶驗證方式,一般會有用戶授權的限制,會在headers的Autheration字段里要求加入用戶名密碼(明文),如果驗證失敗則請求就會失敗,現在這種認證方式正在被淘汰。…

knockout + easyui = koeasyui

在做后臺管理系統的同學們,是否有用easyui的經歷。雖然現在都是vue、ng、react的時代。但easyui(也就是jquery為基礎)還是占有一席之地的。因為他對后端開發者太友好了,太熟悉不過了。要讓一個后端開發者來理解vue或者是react的VN…

輕量社交APP系統ThinkSNS 簡 權威發布 限時惠購

2019獨角獸企業重金招聘Python工程師標準>>> 伴隨國內外創業風潮、AI、區塊鏈等互聯網軟件科技領域的高速發展,2019年,ThinkSNS軟件品牌迎來十周年后的新紀元。作為下一個階段的產品元年,官方于2019年5月正式發售輕量核心社交APP系…

linux下安裝oracle sqlplus以及imp、exp工具

一、下載oracle 11g sqlplus軟件 linux 64位操作系統,oracle安裝包地址 http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html oracle-instantclient11.2-sqlplus-11.2.0.3.0-1.x86_64.rpm  oracle-instantclient11.2-basic-11.2.0.4.0-1.x86_6…

在operator =中要處理“自我賦值”

防止自我賦值很有必要 Widget w; w w; a[i] a[j]; //a[i]和a[j]實際上指向同一個元素 *pi *pj; //pi和pj實際上指向同一個元素 自我賦值的危害: Widget { private:Test *p; }; Widget &Widget::operator(const Widget &w) {delete p;p new int (*w.p);r…

新添加磁盤分區后,找不到新分區

問題:在Vcent中擴容磁盤容量,登錄虛擬機fdisk /dev/sda分區后,找不到新分區。 lsblk或者 df -TH fdisk /dev/sda p 嘗試解決辦法: cd /sys/class/scsi_host/ ls echo "- - -" > /sys/class/scsi_host/host0/scan (中…

Linux一些指令

備忘。。 ~/.bashrc 環境變量文件 xshell5 與本機文件傳輸 rz接受 sz filename 傳輸 watch -n 2 nvidia-smi 監視gpu 狀態wget 下載單個文件wget http://images.cocodataset.org/zips/train2014.zip給.sh文件添加x執行權限 比如以hello.sh文件為例,chmod ux hello…

C# 通過反射獲取方法/類上的自定義特性

1.所有自定義屬性都必須繼承System.Attribute 2.自定義屬性的類名稱必須為 XXXXAttribute 即是已Attribute結尾 自定義屬性QuickWebApi [AttributeUsage(AttributeTargets.Method, Inherited false, AllowMultiple true)]public class QuickWebApiAttribute: Attribute{publ…