青瓷引擎是一套開源免費(fèi)的JavaScript游戲引擎類庫,其基于開源免費(fèi)的Phaser游戲引擎,并提供了一套完全基于瀏覽器的跨平臺集成式HTML5游戲編輯器。
功能描述:
上手容易,學(xué)習(xí)成本低
引擎、編輯器、后臺均基于JavaScript數(shù)百個(gè)工程示例Demo及完整游戲教程助力用戶學(xué)習(xí)掌握。
開發(fā)效率高
重新定義了HTML5游戲的開發(fā)工作流,開發(fā)、調(diào)試盡在瀏覽器內(nèi)。不斷豐富的插件庫,讓游戲開發(fā)更加便捷、簡單。
一站式集成工具套件
開發(fā)和整合了游戲中用到的各種工具,強(qiáng)調(diào)了各工具之間的無縫融合,大大提升了開發(fā)效率。
傳播更廣
游戲無需瀏覽器安裝額外插件,適應(yīng)性更廣,更利于傳播。
開源免費(fèi) 便于擴(kuò)展
MIT開源協(xié)議,面向組件式編程,支持組件熱拔插,方便擴(kuò)展維護(hù)。核心庫及編輯器都是純JavaScript,便于用戶自行擴(kuò)展修改。
可視化編輯 所見即所得
先進(jìn)的UI界面布局規(guī)則,簡單幾步,無需編碼即可適配各種分辨率。強(qiáng)大的可視化編輯功能,拖拖拽拽便可以實(shí)現(xiàn)很多復(fù)雜的功能。
安裝說明:
Windows下安裝
首先安裝Node.js環(huán)境
如果您本機(jī)已經(jīng)安裝了Node.js,推薦您升級到最新版本,青瓷引擎支持的Node.js版本:
Node.js合并io.js之前任何 v0.12.x 的版本
Node.js合并io.js之后任何高于 v4.1 的版本
下載青瓷引擎
通過青瓷引擎官網(wǎng)下載免安裝包,并解壓
運(yùn)行青瓷引擎
雙擊start-win.bat運(yùn)行,青瓷引擎編輯器將自動在瀏覽器中打開:
也可在解壓目錄下,通過命令行啟動 node ./editorservice/StartService.js
青瓷引擎編輯器可運(yùn)行在任何支持HTML5的瀏覽器,但建議采用Google Chrome瀏覽器運(yùn)行性能最佳
瀏覽器的訪問地址為:http://localhost:port/project.html 其中port端口值見控制臺(默認(rèn)都為5002):
在瀏覽器中打開的界面如圖:
操作示例說明:
創(chuàng)建工程
指定工程文件夾名:HelloWorld。操作方法如下:
工程設(shè)置
設(shè)定編輯器布局為:豎屏。操作方法:選擇菜單“Layout/Portrait”
選擇菜單“Project/Settings...”,在Inspector面板中打開工程設(shè)置界面
設(shè)置值如下:
Project Name(工程名): HelloWorld
Game Name(游戲名):HelloWorld
Company(開發(fā)者姓名或公司名):qcplay
Identifier(游戲唯一標(biāo)識符,需要保證唯一):com.qici.helloworld
Version(當(dāng)前工程的版本號):0.9
其他字段使用默認(rèn)值
創(chuàng)建場景
創(chuàng)建一個(gè)空的場景,步驟如下:
選擇菜單“Project/New Scene”
場景中掛載個(gè)UIRoot對象(暫時(shí)可以理解為放界面元素的根節(jié)點(diǎn)就好了)
保存場景,場景名稱:HelloWorld,場景的文件路徑:Assets/state/HelloWorld.bin
設(shè)置為入口場景
將剛才創(chuàng)建的新場景HelloWorld加入到場景列表中。方法是打開Project Setting面板,將場景選中:
在場景列表中,第一個(gè)即為入口場景(系統(tǒng)會自動加載)
場景需要勾選后,才能被加載。否則發(fā)布時(shí)將視為無效場景
添加腳本
這里,我們使用代碼創(chuàng)建一個(gè)文本,并顯示:”Hello World!“。
在Project面板中,右擊”Script“創(chuàng)建一個(gè)js文件:Init.js
雙擊打開,編輯代碼如下:
var Init = qc.defineBehaviour('qc.helloworld.Init', qc.Behaviour, function() { }, { }); Init.prototype.awake = function() { // create a text var node = this.game.add.text(this.gameObject); node.text = 'Hello World!'; node.color = new qc.Color(0xffffff); };
將此代碼掛載到UIRoot節(jié)點(diǎn)(方法是直接拖拽到節(jié)點(diǎn)上),這樣此腳本就能被調(diào)度運(yùn)行。
代碼講解
首先,我們定義一個(gè)類:qc.helloworld.Init。qc.defineBehaviour接收4個(gè)參數(shù),這里可以先簡單了解下:
第一個(gè)參數(shù):類的名字為qc.helloworld.Init
第二個(gè)參數(shù):所有掛載到場景對象(本示例為UIRoot節(jié)點(diǎn))的腳本,都應(yīng)該繼承自:qc.Behaviour
第三個(gè)參數(shù):腳本對象的構(gòu)造函數(shù)
第四個(gè)參數(shù):可被序列化的對象字段及其類型描述
var Init = qc.defineBehaviour('qc.helloworld.Init', qc.Behaviour, function() { }, { });
然后,在Init對象的awake函數(shù)中,添加邏輯代碼以創(chuàng)建text。awake并不需要開發(fā)者自己去調(diào)度,當(dāng)UIRoot這個(gè)節(jié)點(diǎn)被反序列化后,系統(tǒng)自動調(diào)用腳本的awake方法
在awake方法中:
this.game:游戲?qū)嵗囊?/p>
this.game.add:對象創(chuàng)建工廠(可以用來創(chuàng)建文本、圖片、精靈等對象)
this.gameObject:本邏輯腳本掛載的目標(biāo)游戲?qū)ο螅ū緦?shí)例為UIRoot)
this.game.add.text(this.gameObject):在UIRoot節(jié)點(diǎn)下,創(chuàng)建一個(gè)Text對象
然后設(shè)置文本內(nèi)容為:'Hello World!'
最后設(shè)置文本顏色值為白色
運(yùn)行起來
保存當(dāng)前場景
點(diǎn)擊”運(yùn)行“按鈕,查看結(jié)果
讓文字居中
默認(rèn)情況下,文本的位置在屏幕左上角(0,0)。修改Init.js代碼,在awake中,添加如下代碼:
// 設(shè)置文本對象原點(diǎn)在中心 node.pivotX = 0.5; node.pivotY = 0.5; // 位置居中 node.x = this.gameObject.width/2; node.y = this.gameObject.height/2; // 文本水平對齊 node.alignH = qc.UIText.CENTER;
運(yùn)行之,現(xiàn)在文本居中顯示了。
換個(gè)方式:不要編碼
在之前的實(shí)現(xiàn)方式中,如果非編碼人員(如策劃人員、美術(shù)人員)想要調(diào)整顯示的文字、位置和樣式等,他們是沒有能力自行修改的。
因此我們換一種方式,直接在場景中可視化創(chuàng)建文字對象,并設(shè)置其內(nèi)容、文字大小等信息:
將Init.js從UIRoot對象中干掉,這樣此腳本將無法自動被調(diào)度了
在UIRoot下創(chuàng)建UIText節(jié)點(diǎn),并在Inspector面板中設(shè)置其內(nèi)容
運(yùn)行查看效果
是不是比手寫代碼快很多?
這一切如何發(fā)生的呢?
從傳統(tǒng)的編程方式來看,到這里會有一些疑問:程序執(zhí)行入口在哪?編輯器”偷偷摸摸“干了些啥?讓我們依次展開詳細(xì)解釋。
首先,將本工程發(fā)布出來
打開文件:StartGame.html,查看文件內(nèi)容。這里按順序摘取主要內(nèi)容依次解釋。
游戲配置
由編輯器根據(jù)Project Settings自動生成
qici.config = { projectName: 'HelloWorld', gameName: 'HelloWorld', companyName: 'qcplay', bundleIdentifier: 'com.qici.helloworld', gameInstance: 'qc_game', backgroundColor: 4671303, runInBackground: true, antialias: true, transparent: false, developerMode: false, renderer: 'Auto', loadingPrefab: '', scene: { "HelloWorld" : "Assets/state/HelloWorld.bin" }, entityScene : 'HelloWorld', loading: { loadingInterval: 200, brightingInterval: 10, blinkingCount: 5, blinkingInterval: 70, fadingInterval: 400 } };
導(dǎo)入引擎庫文件和用戶腳本文件
游戲一開始會出現(xiàn)吃豆子的加載動畫,這過程加載如下幾個(gè)代碼文件:
qici.scripts = [ './Assets/meta/globalUrlMap.js', 'http://engine.zuoyouxi.com/lib/0.97.06/phaser.min.js', 'http://engine.zuoyouxi.com/lib/0.97.06/webfontloader.js', 'http://engine.zuoyouxi.com/lib/0.97.06/qc-core.js', // External scripts for plugins // User scripts './js/game-scripts-mini-0.9.js' ];
加載這些js文件和播放進(jìn)度的動畫表現(xiàn),在qc-loading.js腳本中實(shí)現(xiàn):
<body onload="qici.init();"> <div id="gameDiv" style="position:relative;"></div> <script src='http://engine.zuoyouxi.com/lib/0.97.06/qc-loading.js'></script> </body>
游戲?qū)嵗跏蓟?br/>在編輯器目錄,打開lib/qc-loading-debug.js文件。加載js文件和進(jìn)度表現(xiàn)的邏輯忽略不看;
當(dāng)js文件加載完畢后,調(diào)用qici.loadGame方法:
qici.loadGame = function() { var game = window[qici.config.gameInstance] = new qc.Game({ width: '100%', height: '100%', parent: 'gameDiv', state: qici.splashState, editor: qici.config.editor === true, backgroundColor: new qc.Color(qici.config.backgroundColor), runInBackground: qici.config.runInBackground, antialias: qici.config.antialias, transparent: qici.config.transparent, debug: qici.config.developerMode === true, renderer: (function() { if (qici.config.renderer === 'WebGL') { return Phaser.WEBGL; } if (qici.config.renderer === 'Canvas'){ return Phaser.CANVAS; } return Phaser.AUTO; })() }); game.bundleIdentifier = qici.config.bundleIdentifier; game.log.important('**** [QICI Engine]Starting game: {0}', qici.config.gameName); };
游戲的初始化流程在這里實(shí)現(xiàn)了:實(shí)例化qc.Game,構(gòu)造函數(shù)接收一個(gè)object進(jìn)行配置。大部分配置屬性暫時(shí)不去理會,這里著重看下state(值為qici.splashState)
Splash State
這個(gè)其實(shí)是個(gè)空的內(nèi)置場景,此場景完成一些初始化信息(例如loading動畫等)。最重要的是:通過此場景載入入口場景(本例子為HelloWorld)。主流程如下:
qici.splashState = { init: function() { window[qici.config.gameInstance].fullScreen(); }, preload: function() { var game = window[qici.config.gameInstance]; if (qici.config.loadingPrefab) { game.assets.load('__loading_prefab__', qici.config.loadingPrefab); } var text = game.add.text(); text.text = 'Initializing, please wait ...'; text.setAnchor(new qc.Point(0, 0), new qc.Point(1, 1)); text.left = 0; text.right = 0; text.top = 0; text.bottom = 0; text.alignH = qc.UIText.CENTER; text.alignV = qc.UIText.MIDDLE; text.fontSize = 24; text.color = new qc.Color(0xffffff); text.strokeThickness = 2; text.stroke = new qc.Color(0x000000); game._initText_ = text; game.updateScale(true); }, create: function() { var game = window[qici.config.gameInstance]; game.state.entity = qici.config.entityScene; game.state.list = qici.config.scene; var node; if (qici.config.loadingPrefab) { var prefab = game.assets.find('__loading_prefab__'); if (prefab) { node = game.add.clone(prefab); node.ignoreDestroy = true; node.visible = false; } } if (game._initText_) { if (node) { game._initText_.destroyImmediately(); } delete game._initText_; } game.phaser.time.events.add(1, function() { game.state.load(game.state.entity, true); }); if (qici.config.frameRate) game.time.frameRate = qici.config.frameRate; } };
進(jìn)入主場景后,系統(tǒng)反序列化場景內(nèi)容并逐一構(gòu)建場景對象。構(gòu)建完畢后依次初始化場景節(jié)點(diǎn)(通過調(diào)用邏輯腳本的awake函數(shù))
初始化流程總結(jié)
這些初始化流程編輯器已經(jīng)自動幫你完成:
實(shí)例化qc.Game
Game啟動后,依次調(diào)用SplashState場景(空的內(nèi)置場景)的init、preload和create,并載入入口場景
下載、反序列化入口場景,將場景重新構(gòu)建后調(diào)用awake方法(掛載到對象的邏輯腳本才會調(diào)用)
更新日志:
場景統(tǒng)一使用:scene(原來部分使用了state)
修改截屏接口的包圍盒獲取方式,使用相對自己的坐標(biāo)而非世界坐標(biāo)
TileLayer增加接口:setTileIndex,支持動態(tài)修改地圖塊
增加2個(gè)加密/解密接口:qc.Des.encrypt和qc.Des.decrypt
Tween組件duration參數(shù)默認(rèn)為1(原來為0)
合并Arcade物理插件幀調(diào)度時(shí)機(jī)
圖片在canvas渲染模式下,當(dāng)寬高為0時(shí)不繪制
Node節(jié)點(diǎn)增加事件:onDeserialized(反序化完成事件)
qc.Color增加屬性:r、g、b
DOM節(jié)點(diǎn)增加alpha屬性
Canvas繪制時(shí),默認(rèn)開啟roundPixeds選項(xiàng)
替換編輯器首頁樣式
部分內(nèi)置文件夾限制刪除,如以下目錄:Assets/raw、Assets/scene等
開啟臟矩形時(shí),當(dāng)父節(jié)點(diǎn)被移除后,子節(jié)點(diǎn)所在范圍沒有更新
NodeMask組件在RenderTexture中繪制時(shí),位置更新不及時(shí)
在X5瀏覽上,DOM插入到隱藏節(jié)點(diǎn)位置繪制不對
Slider中的滑塊不是固定大小時(shí),追蹤點(diǎn)擊失效
Button在開啟NativeClick時(shí),父親節(jié)點(diǎn)隱藏后依然可以響應(yīng)點(diǎn)擊
圖集只有一張圖片時(shí),frameNames屬性錯(cuò)誤
輸入框被編輯時(shí),父親節(jié)點(diǎn)隱藏時(shí)依然可見
數(shù)組類型字段反序列化時(shí),存在多處引用
幀率限制在發(fā)布后不起效
富文本插件
粒子插件預(yù)覽版
動畫編輯器預(yù)覽版
Box2D物理插件預(yù)覽版
固定游戲大小功能(見ProjectSetting的fixedGameSize配置)