整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          2019年7款超棒免費開源的HTML5游戲引擎

          2019年7款超棒免費開源的HTML5游戲引擎

          你畫像素畫原創教程

          HTML5(以下簡稱H5)干掉了Flash,H5游戲占領了瀏覽器。如果你想開發H5游戲,選擇一款好用的開源H5引擎非常有必要。

          GDevelop

          GDevelop是一款2D H5游戲引擎,專為初學者和專業開發者設計。強大的事件系統,可以在不了解編程語言的情況下開發H5跨平臺游戲。詳細的官方教程幫助你快速上手。



          下載地址:https://gdevelop-app.com/download/

          Phaser

          Phaser是一款2DH5游戲引擎,開發環境類似Flash。由開源開發者社區提供支持。它可以創建基于手機和桌面瀏覽器的游戲。有兩個主要版本,即Phaser CE和Phaser 3. Phaser CE是舊版本,Phaser 3是最新的穩定版本。



          下載地址:https://github.com/photonstorm/phaser

          PixiJS

          PixiJS是一種2D WebGL渲染器。當開發者專注于游戲開發時,引擎會自動解決設備兼容性。如果想要創建跨平臺的游戲和應用,它是不錯的選擇。



          下載地址:https://github.com/pixijs/pixi.js

          Babylon.js

          Babylon.js是一款3D H5游戲引擎。利用WebGL API渲染游戲。它還有一個在線沙盒,允許測試引擎API。毫無疑問,它是最好的開源HTML5和JavaScript游戲引擎之一。



          下載地址:https://github.com/BabylonJS/Babylon.js

          Crafty JS

          Crafty JS是最好的開源H5游戲引擎之一。它的主要功能包括事件綁定,組件和實體,不需要自定義繪圖或DOM操作。它還擁有一個競爭激烈的高素質開源開發者社區,他們隨時可以提供幫助。



          下載地址:https://github.com/craftyjs/Crafty

          melonJS

          melonJS是一款H5游戲輕量級引擎。這個JS庫的好處是沒有任何依賴性,只需要一個能夠支持H5的Web瀏覽器。主要功能是跨平臺,支持加速度和設備運動,補間效果,對象池,基本動畫管理,鼠標和觸摸設備支持等。



          下載地址:https://github.com/melonjs/melonJS

          PlayCanvas WebGL

          PlayCanvas是開源3D H5游戲引擎,可以創建一些非常漂亮的3D游戲和交互式動畫。使用它的公司有Facebook,三星,迪士尼,Miniclip,Mozilla,King,ARM,Zynga等。



          下載地址:https://github.com/playcanvas/engine

          完。

          oqups

          Moqups是一款免費的HTML5在線應用,可創建線框圖、實體模型和UI概念。該程序使用起來非常簡單,并且有內置的模板可以直接使用(模板包括單選按鈕、鏈接、圖像占位符、文本框以及滑塊等)。

          Stitches

          Stitches是一個HTML5 sprite sheet生成器。用戶只需要經過簡單的拖拽圖片文件到空白處,然后點擊“Generate”就可以生成一個圖像圖標和樣式表了。

          HTML5 Maker

          HTML5 Maker是一個在線的動畫制作工具/服務,可通過HTML, HTML5, CSS和JavaScript創建動畫和交互式內容。

          Initializr

          Initializr是一款HTML5模板生成器,幫助你快速啟動基于HTML5模板的新項目。總之,Initializr 是制作 HTML5 網站最好的入門輔助開發工具,你可以使用提供的特色模板快速生成網站,也可以自定義,Initializr 會為你生成代碼簡潔的可定制的網頁模板。

          Sprite Box

          Sprite Box是一款WYSIWYG工具,可幫組Web開發人員輕松、快速地創建CSS類和ID。它是基于使用背景位置屬性原則來調整插入到網頁塊元素中的精靈小圖像。這款工具是使用 JQuery,HTMl5 和 CSS3 組合來運轉的,而且是一款完全免費的工具。

          Liveweave

          Liveweave在HTML4/HTML5、CSS2/CSS3中含有內置的自動完成上下文特性,讓你工作起來更加輕松。你只需輸入HTML5和CSS3 標簽/元素即可,就是這么簡單。

          Literally Canvas

          Literally Canvas是一款開源的HTML5部件,可以被集成到任何頁面。它配備了一套簡單的工具,包括繪圖、擦除、顏色選擇器、撤銷、恢復、平移以及縮放。該工具利用jQuery+和Underscore.js創建而來,利用API定義背景色、工具以及尺寸。

          HTML5 Demos

          HTML5 Demos能夠讓你立即知道Firefox是否支持HTML5 Canvas,Safari能否運行HTML5 聊天客戶端。

          HTML5 Visual Cheat Sheet

          HTML5 Visual Cheat Sheet是專為Web設計師和開發者設計的一款速查表。這份速查表包含了HTML tag列表以及支持HTML4.01/5版本的相關屬性。

          Switch to HTML5

          Switch to HTML5是一款高效的模板生成器。如果你開始一個新的項目,記住一定要訪問該網站。各種各樣的HTML5網站模板將會呈現在你的眼前。

          Online SVG to HTML5 Canvas Tool

          這款工具可以將SVG轉換成HTML5 Canvas JavaScript函數。它幾乎可以運行在任何主機上,幫助用戶去嘗試使用Canvas,可以導出大量的矢量藝術包(Illustrator,Inkscape)。

          HTML5 Test

          利用HTML5 test可以測試你的瀏覽器支持即將推出HTML5 標準和相關規范的得分情況。盡管該規范還沒有最終敲定,但是所有主流瀏覽器廠商都在為未來做好準備。

          你可以查看瀏覽器支持HTML5 哪些部分并與其他瀏覽器進行對比。

          Patternizer

          Patternizer是用來創建條紋圖案的生成器。

          Lime JS

          LimeJS 是一個 JavaScript 游戲開發框架,允許開發者創建基于 HTML5 的游戲,支持主流瀏覽器包括iOS。

          HTML5 Reset

          HTML5 Reset是(HTML,CSS等)一套設計組件,旨在幫助用戶節省大量的時間,創建更加高效的項目。

          HTML5 Tracker

          HTML5 Tracker能夠用于跟蹤HTML5相關的最新修訂信息。

          Cross browser HTML5 forms

          表單是一個網站非常重要的一部分。 HTML5的特性日歷,色彩板,滑動部件,客戶端驗證等這些都是非常強大的工具,但現實的情況就是,大多數的瀏覽器不支持所有的功能。這是一個很大的問題,剛好Cross browser HTML5能夠幫您如何輕松創建一個跨瀏覽器的表單。

          學lufylegend.js之日,我用lufylegend.js開發了第一個HTML5小游戲——拼圖游戲,還寫了篇博文來炫耀一下:HTML5小游戲《智力大拼圖》發布,挑戰你的思維風暴。不過當時初學游戲開發,經驗淺薄,所以沒有好好專研游戲里的算法和代碼的缺陷,導致游戲出現了很多bug,甚至拼圖打亂后很可能無法復原。最近經常有朋友問起這個游戲,希望我能把代碼里的bug改一下方便初學者學習,順便我也打算測試一下自己寫這種小游戲的速度,所以就抽出了一些時間將這個游戲從頭到尾重新寫了一遍,計算了一下用時,從準備、修改素材到最后完成游戲,一共用了大約2h的時間。

          以下是游戲地址:

          由于頭條禁止在文章頁面加入鏈接,大家私信我“拼圖”即可獲取下載地址。

          這是我的游戲記錄,歡迎各位挑戰:

          接下來就來講講如何開發完成這款游戲的。(按“編年體”)

          準備階段

          準備lufylegend游戲引擎,大家可以去官方網站下載:

          由于頭條禁止在文章頁面加入鏈接,大家私信我“拼圖”即可獲取下載地址。

          引擎文檔地址:

          由于頭條禁止在文章頁面加入鏈接,大家私信我“拼圖”即可獲取下載地址。

          可以說,如果沒有強大的lufylegend引擎,這種html5小游戲用原生canvas制作,少說要一天呢。

          0~30min

          準備素材(10min) + 修改素材(20min)。由于在下實在手殘,不善于P圖,修改圖片用了大約20min,囧……

          30~50min

          開發開始界面。游戲不能沒有開始界面所以我們首先實現這部分代碼。在此之前是index.html里的代碼,代碼如下:

          <!DOCTYPE html>

          <html>

          <head>

          <title>Puzzle</title>

          <meta charset="utf-8">

          <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">

          <script type="text/javascript" src="./lib/lufylegend-1.10.1.simple.min.js"></script>

          <script type="text/javascript" src="./js/Main.js"></script>

          </head>

          <body style="margin: 0px; font-size: 0px; background: #F2F2F2;">

          <div id="mygame"></div>

          </body>

          </html>

          主要是引入一些js文件,不多說。然后準備一個Main.js文件,在這個文件里添加初始化界面和加載資源的代碼:

          /** 初始化游戲 */

          LInit(60, "mygame", 390, 580, main);

          var imgBmpd;

          /** 游戲層 */

          var stageLayer, gameLayer, overLayer;

          /** 拼圖塊列表 */

          var blockList;

          /** 是否游戲結束 */

          var isGameOver;

          /** 用時 */

          var startTime, time, timeTxt;

          /** 步數 */

          var steps, stepsTxt;

          function main () {

          /** 全屏設置 */

          if (LGlobal.mobile) {

          LGlobal.stageScale=LStageScaleMode.SHOW_ALL;

          }

          LGlobal.screen(LGlobal.FULL_SCREEN);

          /** 添加加載提示 */

          var loadingHint=new LTextField();

          loadingHint.text="資源加載中……";

          loadingHint.size=20;

          loadingHint.x=(LGlobal.width - loadingHint.getWidth()) / 2;

          loadingHint.y=(LGlobal.height - loadingHint.getHeight()) / 2;

          addChild(loadingHint);

          /** 加載圖片 */

          LLoadManage.load(

          [

          {path : "./js/Block.js"},

          {name : "img", path : "./images/img.jpg"}

          ],

          null,

          function (result) {

          /** 移除加載提示 */

          loadingHint.remove();

          /** 保存位圖數據,方便后續使用 */

          imgBmpd=new LBitmapData(result["img"]);

          gameInit();

          }

          );

          }

          function gameInit (e) {

          /** 初始化舞臺層 */

          stageLayer=new LSprite();

          stageLayer.graphics.drawRect(0, "", [0, 0, LGlobal.width, LGlobal.height], true, "#EFEFEF");

          addChild(stageLayer);

          /** 初始化游戲層 */

          gameLayer=new LSprite();

          stageLayer.addChild(gameLayer);

          /** 初始化最上層 */

          overLayer=new LSprite();

          stageLayer.addChild(overLayer);

          /** 添加開始界面 */

          addBeginningUI();

          }

          以上代碼有詳細注釋,大家可以對照引擎文檔和注釋進行閱讀。有些全局變量會在以后的代碼中使用,大家可以先忽略。接下來是addBeginningUI函數里的代碼,用于實現開始界面:

          function addBeginningUI () {

          var beginningLayer=new LSprite();

          beginningLayer.graphics.drawRect(0, "", [0, 0, LGlobal.width, LGlobal.height], true, "#EDEDED");

          stageLayer.addChild(beginningLayer);

          /** 游戲標題 */

          var title=new LTextField();

          title.text="拼圖游戲";

          title.size=50;

          title.weight="bold";

          title.x=(LGlobal.width - title.getWidth()) / 2;

          title.y=160;

          title.color="#FFFFFF";

          title.lineWidth=5;

          title.lineColor="#000000";

          title.stroke=true;

          beginningLayer.addChild(title);

          /** 開始游戲提示 */

          var hint=new LTextField();

          hint.text="- 點擊屏幕開始游戲 -";

          hint.size=25;

          hint.x=(LGlobal.width - hint.getWidth()) / 2;

          hint.y=370;

          beginningLayer.addChild(hint);

          /** 開始游戲 */

          beginningLayer.addEventListener(LMouseEvent.MOUSE_UP, function () {

          beginningLayer.remove();

          startGame();

          });

          }

          到此,運行代碼,得到我們的開始界面:

          看到這個畫面,其實我自己都想吐槽一下實在是太“樸素”了,囧……

          不過我這次圖個制作速度,所以還望各位看官海量。

          50~90min

          這40分鐘的時間,是最關鍵時期,期間我們要完成整個游戲的主體部分。首先,我們需要用代碼來實現以下過程:

          初始化游戲界面數據(如游戲時間、所用步數)和顯示一些UI部件(如圖樣)

          |

          -> 獲取隨機的拼圖塊位置

          |

          -> 顯示打亂后的拼圖塊

          我們將這些步驟做成一個個的函數方便我們統一調用:

          function startGame () {

          isGameOver=false;

          /** 初始化時間和步數 */

          startTime=(new Date()).getTime();

          time=0;

          steps=0;

          /** 初始化拼圖塊列表 */

          initBlockList();

          /** 打亂拼圖 */

          getRandomBlockList();

          /** 顯示拼圖 */

          showBlock();

          /** 顯示縮略圖 */

          showThumbnail();

          /** 顯示時間 */

          addTimeTxt();

          /** 顯示步數 */

          addStepsTxt();

          stageLayer.addEventListener(LEvent.ENTER_FRAME, onFrame);

          }

          函數一開始,我們把isGameOver變量設定為false代表游戲未結束,在后期的代碼里,我們會看到這個變量的作用。接著我們初始化了用于表示時間和步數的time和steps這兩個全局變量,另外初始化變量startTime的值用于后面計算游戲時間。

          接下來,我們就要開始初始化拼圖塊了。見initBlockList里的代碼:

          function initBlockList () {

          blockList=new Array();

          for (var i=0; i < 9; i++) {

          /** 根據序號計算拼圖塊圖片顯示位置 */

          var y=(i / 3) >>> 0, x=i % 3;

          blockList.push(new Block(i, x, y));

          }

          }

          這里我們使用了一個Block類,這個類用于顯示拼圖塊和儲存拼圖塊的數據,并提供了一些方法來操控拼圖塊,下面是其構造器的代碼:

          function Block (index, x, y) {

          LExtends(this, LSprite, []);

          var bmpd=imgBmpd.clone();

          bmpd.setProperties(x * 130, y * 130, 130, 130);

          this.bmp=new LBitmap(bmpd);

          this.addChild(this.bmp);

          var border=new LShape();

          border.graphics.drawRect(3, "#CCCCCC", [0, 0, 130, 130]);

          this.addChild(border);

          this.index=index;

          this.addEventListener(LMouseEvent.MOUSE_UP, this.onClick);

          }

          Block類繼承自LSprite,屬于一個顯示對象,所以我們在這個類中添加了一個位圖對象用于顯示拼圖塊對應的圖片。除此之外,我們還為拼圖塊添加了一個邊框,在顯示時用于隔開周圍的拼圖塊。Block類有一個index屬性,代表拼圖塊在拼圖塊列表blockList中的正確位置。最后,我們為此類添加了一個鼠標按下事件,用于處理鼠標按下后移動圖塊操作。

          接下來我們還要介紹這個類的一個方法setLocation:

          Block.prototype.setLocation=function (x, y) {

          this.locationX=x;

          this.locationY=y;

          this.x=x * 130;

          this.y=y * 130;

          };

          這個方法用于設置拼圖塊對象的顯示位置以及保存拼圖塊的“數組位置”。什么是“數組位置”呢?各位看官可以通過下面的圖片加以了解:

          可以看到,“數組位置”就類似于二維數組中的元素下標。儲存這個位置的作用在于可以很方便地從blockList中獲取到附近的其他拼圖塊。這個方法在我們顯示拼圖時有調用到,在顯示拼圖之前,我們得先打亂拼圖,見如下代碼:

          function getRandomBlockList () {

          /** 隨機打亂拼圖 */

          blockList.sort(function () {

          return 0.5 - Math.random();

          });

          /** 計算逆序和 */

          var reverseAmount=0;

          for (var i=0, l=blockList.length; i < l; i++) {

          var currentBlock=blockList[i];

          for (var j=i + 1; j < l; j++) {

          var comparedBlock=blockList[j];

          if (comparedBlock.index < currentBlock.index) {

          reverseAmount++;

          }

          }

          }

          /** 檢測打亂后是否可還原 */

          if (reverseAmount % 2 !=0) {

          /** 不合格,重新打亂 */

          getRandomBlockList();

          }

          }

          打亂拼圖部分直接用數組的sort方法進行隨機打亂:

          blockList.sort(function () {

          return 0.5 - Math.random();

          });

          其實打亂算法有很多種,我這里采用最粗暴的方法,也就是隨機打亂。這種算法簡單是簡單,壞在可能出現無法復原的現象。針對這個問題,就有配套的檢測打亂后是否可還原的算法,具體的算法理論我借用lufy大神的評論:

          此類游戲能否還原關鍵是看它打亂后的逆序次數之和是否為偶數

          假設你打亂后的數組中的每一個小圖塊為obj0,obj1,obj2,…它們打亂之前的序號分別為obj0.num,obj1.num…

          接下來循環數組,如果前面元素的序號比此元素后某個元素的序號大,如obj0.num > obj1.num或者obj2.num > obj4.num就表示一個逆序

          當全部的逆序之和為奇數時表示不可還原,重新打亂即可,打亂后重新檢測,直到逆序之和為偶數為止

          舉個例子,如果有一個數組為[3, 4, 2, 1],那么里面3 2, 3 1, 2 4, 4 1, 2 1是逆序的,所以逆序數是5。

          上面我給出的getRandomBlockList里的代碼就是在實現打亂算法和檢測是否可還原算法。

          還有一種打亂方式,大家可以嘗試嘗試:和復原拼圖一樣,將空白塊一步一步地與周圍的拼圖隨機交換順序。這個打亂算法較上一種而言,不會出現無法復原的現象,而且可以根據打亂的步數設定游戲難度。

          在完成打亂拼圖塊后,如期而至的是顯示拼圖塊:

          function showBlock() {

          for (var i=0, l=blockList.length; i < l; i++) {

          var b=blockList[i];

          /** 根據序號計算拼圖塊位置 */

          var y=(i / 3) >>> 0, x=i % 3;

          b.setLocation(x, y);

          gameLayer.addChild(b);

          }

          }

          顯示了拼圖塊后,我們要做的就是添加操作拼圖塊的功能。于是需要拓展Block類,為其添加事件監聽器onClick方法:

          Block.prototype.onClick=function (e) {

          var self=e.currentTarget;

          if (isGameOver) {

          return;

          }

          var checkList=new Array();

          /** 判斷右側是否有方塊 */

          if (self.locationX > 0) {

          checkList.push(Block.getBlock(self.locationX - 1, self.locationY));

          }

          /** 判斷左側是否有方塊 */

          if (self.locationX < 2) {

          checkList.push(Block.getBlock(self.locationX + 1, self.locationY));

          }

          /** 判斷上方是否有方塊 */

          if (self.locationY > 0) {

          checkList.push(Block.getBlock(self.locationX, self.locationY - 1));

          }

          /** 判斷下方是否有方塊 */

          if (self.locationY < 2) {

          checkList.push(Block.getBlock(self.locationX, self.locationY + 1));

          }

          for (var i=0, l=checkList.length; i < l; i++) {

          var checkO=checkList[i];

          /** 判斷是否是空白拼圖塊 */

          if (checkO.index==8) {

          steps++;

          updateStepsTxt();

          Block.exchangePosition(self, checkO);

          break;

          }

          }

          };

          首先,我們在這里看到了isGameOver全局變量的作用,即在游戲結束后,阻斷點擊拼圖塊后的操作。

          在點擊了拼圖塊后,我們先獲取該拼圖塊周圍的拼圖塊,并將它們裝入checkList,再遍歷checkList,當判斷到周圍有空白拼圖塊后,即周圍有index屬性等于8的拼圖塊后,先更新操作步數,然后將這兩個拼圖塊交換位置。具體交換拼圖塊位置的方法詳見如下代碼:

          Block.exchangePosition=function (b1, b2) {

          var b1x=b1.locationX, b1y=b1.locationY,

          b2x=b2.locationX, b2y=b2.locationY,

          b1Index=b1y * 3 + b1x,

          b2Index=b2y * 3 + b2x;

          /** 在地圖塊數組中交換兩者位置 */

          blockList.splice(b1Index, 1, b2);

          blockList.splice(b2Index, 1, b1);

          /** 交換兩者顯示位置 */

          b1.setLocation(b2x, b2y);

          b2.setLocation(b1x, b1y);

          /** 判斷游戲是否結束 */

          Block.isGameOver();

          };

          還有就是Block.getBlock靜態方法,用于獲取給定的“數組位置”下的拼圖塊:

          Block.getBlock=function (x, y) {

          return blockList[y * 3 + x];

          };

          在Block.exchangePosition中,我們通過Block.isGameOver判斷玩家是否已將拼圖復原:

          Block.isGameOver=function () {

          var reductionAmount=0, l=blockList.length;

          /** 計算還原度 */

          for (var i=0; i < l; i++) {

          var b=blockList[i];

          if (b.index==i) {

          reductionAmount++;

          }

          }

          /** 計算是否完全還原 */

          if (reductionAmount==l) {

          /** 游戲結束 */

          gameOver();

          }

          };

          到這里,我們就實現了打亂和操作拼圖塊部分。

          90~120min

          最后30min用于細枝末節上的處理,如顯示拼圖縮略圖、顯示&更新時間和步數,以及添加游戲結束畫面,這些就交給如下冗長而簡單的代碼來完成吧:

          function showThumbnail() {

          var thumbnail=new LBitmap(imgBmpd);

          thumbnail.scaleX=130 / imgBmpd.width;

          thumbnail.scaleY=130 / imgBmpd.height;

          thumbnail.x=(LGlobal.width - 100) /2;

          thumbnail.y=410;

          overLayer.addChild(thumbnail);

          }

          function addTimeTxt () {

          timeTxt=new LTextField();

          timeTxt.stroke=true;

          timeTxt.lineWidth=3;

          timeTxt.lineColor="#54D9EF";

          timeTxt.color="#FFFFFF";

          timeTxt.size=18;

          timeTxt.x=20;

          timeTxt.y=450;

          overLayer.addChild(timeTxt);

          updateTimeTxt();

          }

          function updateTimeTxt () {

          timeTxt.text="時間:" + getTimeTxt(time);

          }

          function getTimeTxt () {

          var d=new Date(time);

          return d.getMinutes() + " : " + d.getSeconds();

          };

          function addStepsTxt () {

          stepsTxt=new LTextField();

          stepsTxt.stroke=true;

          stepsTxt.lineWidth=3;

          stepsTxt.lineColor="#54D9EF";

          stepsTxt.color="#FFFFFF";

          stepsTxt.size=18;

          stepsTxt.y=450;

          overLayer.addChild(stepsTxt);

          updateStepsTxt();

          }

          function updateStepsTxt () {

          stepsTxt.text="步數:" + steps;

          stepsTxt.x=LGlobal.width - stepsTxt.getWidth() - 20;

          }

          function onFrame () {

          if (isGameOver) {

          return;

          }

          /** 獲取當前時間 */

          var currentTime=(new Date()).getTime();

          /** 計算使用的時間并更新時間顯示 */

          time=currentTime - startTime;

          updateTimeTxt();

          }

          function gameOver () {

          isGameOver=true;

          var resultLayer=new LSprite();

          resultLayer.filters=[new LDropShadowFilter()];

          resultLayer.graphics.drawRoundRect(3, "#BBBBBB", [0, 0, 350, 350, 5], true,"#DDDDDD");

          resultLayer.x=(LGlobal.width - resultLayer.getWidth()) / 2;

          resultLayer.y=LGlobal.height / 2;

          resultLayer.alpha=0;

          overLayer.addChild(resultLayer);

          var title=new LTextField();

          title.text="游戲通關"

          title.weight="bold";

          title.stroke=true;

          title.lineWidth=3;

          title.lineColor="#555555";

          title.size=30;

          title.color="#FFFFFF";

          title.x=(resultLayer.getWidth() - title.getWidth()) / 2;

          title.y=30;

          resultLayer.addChild(title);

          var usedTimeTxt=new LTextField();

          usedTimeTxt.text="游戲用時:" + getTimeTxt(time);

          usedTimeTxt.size=20;

          usedTimeTxt.stroke=true;

          usedTimeTxt.lineWidth=2;

          usedTimeTxt.lineColor="#555555";

          usedTimeTxt.color="#FFFFFF";

          usedTimeTxt.x=(resultLayer.getWidth() - usedTimeTxt.getWidth()) / 2;

          usedTimeTxt.y=130;

          resultLayer.addChild(usedTimeTxt);

          var usedStepsTxt=new LTextField();

          usedStepsTxt.text="所用步數:" + steps;

          usedStepsTxt.size=20;

          usedStepsTxt.stroke=true;

          usedStepsTxt.lineWidth=2;

          usedStepsTxt.lineColor="#555555";

          usedStepsTxt.color="#FFFFFF";

          usedStepsTxt.x=usedTimeTxt.x;

          usedStepsTxt.y=180;

          resultLayer.addChild(usedStepsTxt);

          var hintTxt=new LTextField();

          hintTxt.text="- 點擊屏幕重新開始 -";

          hintTxt.size=23;

          hintTxt.stroke=true;

          hintTxt.lineWidth=2;

          hintTxt.lineColor="#888888";

          hintTxt.color="#FFFFFF";

          hintTxt.x=(resultLayer.getWidth() - hintTxt.getWidth()) / 2;

          hintTxt.y=260;

          resultLayer.addChild(hintTxt);

          LTweenLite.to(resultLayer, 0.5, {

          alpha : 0.7,

          y : (LGlobal.height - resultLayer.getHeight()) / 2,

          onComplete : function () {

          /** 點擊界面重新開始游戲 */

          stageLayer.addEventListener(LMouseEvent.MOUSE_UP, function () {

          gameLayer.removeAllChild();

          overLayer.removeAllChild();

          stageLayer.removeAllEventListener();

          startGame();

          });

          }

          });

          }

          Ok,2h下來,整個游戲就搞定咯~不得不表揚一下lufylegend這個游戲引擎,實在是可以大幅提升開發效率。

          源代碼下載

          最后奉上源代碼:

          由于頭條禁止在文章頁面加入鏈接,大家私信我“拼圖”即可獲取下載地址。

          致謝與反思

          這篇博文在最初寫成的時候,我沒有對逆序算法進行深入研究,再加上我的測試不仔細,我沒有發現算法的錯誤之處。因此,在博文發布后,不少讀者發現游戲無解現象并將此問題反饋給了我,經過網友熱心幫助,我才找到了問題所在,并更正了算法。在此對這些熱心的網友表示真心的感謝,也為我學習不深入,以及誤導了不少讀者而感到十分內疚自責。

          如果大家對本文有任何意見或不解,歡迎留言~


          主站蜘蛛池模板: 精品福利视频一区二区三区| 正在播放国产一区| 国产吧一区在线视频| 国产日韩精品视频一区二区三区 | 国产一区二区草草影院| 国产精品免费大片一区二区| 国产精品美女一区二区三区| 91在线视频一区| 波多野结衣免费一区视频| 国产福利在线观看一区二区| 国产乱人伦精品一区二区 | 色噜噜狠狠一区二区三区| 奇米精品一区二区三区在| 免费人妻精品一区二区三区| 国产伦精品一区二区三区不卡| 农村乱人伦一区二区| 亚洲午夜福利AV一区二区无码| 国产成人高清视频一区二区| 国产一区二区在线观看视频| 国产成人精品一区二区A片带套| 国产99久久精品一区二区| 无码人妻一区二区三区一| 精品无码人妻一区二区免费蜜桃| 亚洲AV福利天堂一区二区三| 国产免费一区二区三区不卡| 波多野结衣AV无码久久一区| 中日韩一区二区三区| 国产综合无码一区二区辣椒| 国产一区二区视频在线播放| 中文无码精品一区二区三区| 亚洲一区二区三区香蕉| 另类免费视频一区二区在线观看| 久久久久国产一区二区| 国产乱码精品一区二区三区中文| 国产成人精品一区二区三区无码| 一本AV高清一区二区三区| 日本一区精品久久久久影院| 在线视频一区二区三区| 男人的天堂av亚洲一区2区| 日本香蕉一区二区三区| 亚洲欧洲一区二区三区|