本文來自網易雲社區
作者:王鴿
不知你是否還記得當年風靡一時的2048這個游戲,一個簡單而又不簡單的游戲,總會讓你在空閑時間玩上一會兒。
在這篇文章里,我們將使用開源的H5框架——Phaser來重現這個游戲。這里你可以了解到游戲內的狀態管理、Sprite元件對象等,以及如何使用Preload、Create等方法。
H5游戲框架眾多,為何選擇它?
由於近幾年H5的火熱,H5游戲框架如雨后春筍般出現,甚至有很多定位不是游戲開發的框架都被歸到這個范疇中。那么為什么選擇Phaser?以下是我選擇它的原因:
支持原生JS。
可以方便地在Canvas和WebGL之間切換。
定位明確,專注H5游戲開發。
完善的文檔及示例。
持續更新,目前Phaser 3正在開發。

2048游戲的最終呈現效果如下

開發准備
首先訪問Phaser官網http://www.phaser.io,下載JavaScript版本的Phaser,並搭建好項目結構
項目文件結構如下:

在index.html中引入相關js文件,定義一個div作為phaser生成canvas的父容器
<!DOCTYPE html>
<head>
<meta charset="UTF-8" />
<title>2048</title>
<script src="js/phaser.min.js"></script>
<script src="js/Menu.js"></script>
<script src="js/Game.js"></script>
<script src="js/index.js"></script>
<style>
body {
margin: 0;
padding: 0;
}
canvas {
margin: 0 auto;
}
.game {
position: absolute;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id="game" >"game"></div>
</body>
游戲是如何進行的
在html文件中我們已經引入了Phaser庫,這使我們擁有了一個名為Phaser的全局對象,通過這個對象,我們可以訪問Phaser庫中哪些用於構建游戲的方法和函數。
現在我們使用Phaser對象來創建一個游戲實例,這個對象用來代表整個游戲,我們會為他添加不同的狀態。
index.js,在其中創建游戲實例,注冊各個游戲狀態以及啟動游戲。
//實例化游戲對象,參數為寬、高、渲染方式,父容器
window.game = new Phaser.Game(240, 400, Phaser.CANVAS, 'game');
//添加狀態,參數為狀態應用的Key值,狀態所包含的對象
game.state.add('Menu', Menu);
game.state.add('Game', Game);
//狀態切換 開始游戲
game.state.start('Menu');
Phaser中的“狀態(state)”管理使游戲的場景切換變得非常容易,此處的“狀態”可以看理解為不同的游戲界面,2048這個游戲比較簡單,只需要首頁和游戲內兩個界面即可。
主頁狀態,由menu.js處理,用於加載游戲資源並顯示游戲開始界面,點擊開始按鈕后切換到游戲狀態並且開始游戲。
游戲狀態,由game.js處理,用於顯示游戲界面、控制游戲邏輯,游戲結束后顯示分數面板
接下來初始化菜單狀態對象(Menu),在Menu.js中定義一個新對象Menu並為它添加函數。狀態啟動時,首先會調用對象內的preload函數,通常加載游戲所需資源會在這一步進行;加載完成后,調用create函數,初始化游戲界面以及邏輯對象等等。
var Menu = {
preload: function () {
//加載圖像,參數為創建元件時所使用的Key值,文件路徑
game.load.image('background', 'assets/bg.png');
game.load.image('btnStart', 'assets/btn-start.png');
game.load.image('btnRestart', 'assets/btn-restart.png');
game.load.image('logo', 'assets/logo.png');
game.load.image('btnTryagain', 'assets/btn-tryagain.png');
},
create: function () {
//創建重復元件,可以重復圖片 一般用於重復紋理的底圖等
game.add.tileSprite(0, 0, game.width, game.height, 'background');
//創建圖片,此處是游戲logo,參數為x,y,加載圖片是所保存的Key值
var logo = game.add.image(0, 0, 'logo');
logo.reset((game.width - logo.width) / 2, (game.height - logo.height) / 2 - 50);
//開始按鈕用來啟動游戲
var startBtn = game.add.sprite(0, 0, 'btnStart');
startBtn.reset((game.width - startBtn.width) / 2, (game.height - startBtn.height) / 2 + 100);
//開啟元件點擊監聽,並添加監聽事件
startBtn.inputEnabled = true;
startBtn.events.onInputDown.add(this.startGame);
},
startGame: function () {
//轉換狀態至游戲界面
game.state.start('Game');
}
};
至此,啟動界面已經完成了,開啟本地web服務器后,在瀏覽器中打開index.html,就可以看到游戲的啟動界面了。

接着在Game.js開始處理游戲的界面以及邏輯
var Game = {
create: function () {
//添加背景
game.add.tileSprite(0, 0, game.width, game.height, 'background');
//變量用於保存游戲分數
this.score = 0;
this.best = 0;
//文字樣式,font:字體字號等 fill:顏色
var titleStyle = { font: "bold 12px Arial", fill: "#4DB3B3", boundsAlignH: "center" };
var scoreStyle = { font: "bold 20px Arial", fill: "#FFFFFF", boundsAlignH: "center" };
var scoreSprite = game.add.sprite(10, 10);
//使用graphics繪制圖形作為界面UI
var scoreGraphics = game.add.graphics(0, 0);
scoreGraphics.lineStyle(5, 0xA1C5C5);
scoreGraphics.beginFill(0x308C8C);
//繪制一個帶圓角的矩形
scoreGraphics.drawRoundedRect(0, 0, 70, 50, 10);
scoreGraphics.endFill();
//把圖形添加到父容器上,便於整體調整位置等
scoreSprite.addChild(scoreGraphics);
//添加文字 參數為x,y,文字內容,文字樣式
var scoreTitle = game.add.text(0, 5, "SCORE", titleStyle);
scoreTitle.setTextBounds(0, 0, 70, 50);
//把文字添加到父容器上,便於整體調整位置等
scoreSprite.addChild(scoreTitle);
this.scoreText = game.add.text(0, 20, this.score, scoreStyle);
this.scoreText.setTextBounds(0, 0, 70, 50);
scoreSprite.addChild(this.scoreText);
......
//添加鍵盤方向件的監聽以及監聽事件
var up = this.game.input.keyboard.addKey(Phaser.Keyboard.UP);
up.onDown.add(function () {...});
var down = this.game.input.keyboard.addKey(Phaser.Keyboard.DOWN);
down.onDown.add(function () {...});
var left = this.game.input.keyboard.addKey(Phaser.Keyboard.LEFT);
left.onDown.add(function () {...});
var right = this.game.input.keyboard.addKey(Phaser.Keyboard.RIGHT);
right.onDown.add(function () {...});
......
//獲取手勢滑動的X軸差值和Y軸差值 用於計算滑動方向
var deltaX = this.game.input.activePointer.position.x - this.game.input.activePointer.positionDown.x;
var deltaY = this.game.input.activePointer.position.y - this.game.input.activePointer.positionDown.y;
......
2048這個游戲的規則非常簡單,開發的思路也非常明確,維護一個4*4的數組,每次觸發移動事件時遍歷數組,進行方向上的疊加判斷,然后在數組中尋找空格,隨機生成新的數字,如果沒有則游戲結束。相關的一些開發思路以及算法優化在此也就不詳述了,大家可以自行查閱。
資料推薦
雖然這個游戲非常簡單,但通過這個項目,可以了解到Phaser的多個方面。如果對此感興趣,可以再深入接觸以下資料:
網易雲免費體驗館,0成本體驗20+款雲產品!
更多網易研發、產品、運營經驗分享請訪問網易雲社區。
相關文章:
【推薦】 #3.14 Piday#我的圓周率日
【推薦】 網易雲數據庫架構設計實踐
