利用原生js實(shí)現(xiàn)html5小游戲之打磚塊(附源碼)
前言
PS:本次項(xiàng)目中使用了大量 es6 語(yǔ)法,故對(duì)于 es6 語(yǔ)法不太熟悉的小伙伴最好能先了解一些基本的原理再繼續(xù)閱讀。
首先,先說明一下做這個(gè)系列的目的:其實(shí)主要源于博主希望熟練使用 canvas 的相關(guān) api ,同時(shí)對(duì)小游戲的實(shí)現(xiàn)邏輯比較感興趣,所以希望通過這一系列的小游戲來(lái)提升自身編程能力;關(guān)于 es6 語(yǔ)法,個(gè)人認(rèn)為以后 es6 語(yǔ)法會(huì)越來(lái)越普及,所以算是提前熟悉語(yǔ)法使用技巧。小游戲的實(shí)現(xiàn)邏輯上可能并不完善,也許會(huì)有一些 bug ,但是畢竟只是為了提升編程能力與技巧,希望大家不要太較真
作為第一次分享,我選擇打磚塊這個(gè)邏輯不算太復(fù)雜的小游戲。同時(shí),為了接近真實(shí)游戲效果,在游戲中也添加了關(guān)卡,磚塊血量,以及物理碰撞模型的簡(jiǎn)略實(shí)現(xiàn)。其實(shí)關(guān)注游戲?qū)崿F(xiàn)邏輯就好了
線上演示地址:http://demo.jb51.net/js/2018/h5-game-blockBreaker
github地址:https://github.com/yangyunhe369/h5-game-blockBreaker
本地下載地址:http://xiazai.jb51.net/201801/yuanma/h5-game-blockBreaker(jb51.net).rar
ps:github地址和本地下載有代碼演示,以及源碼可供參考,線上演示地址可供預(yù)覽
先上一個(gè)游戲完成后的截圖

游戲工程目錄如下
. ├─ index.html // 首頁(yè)html │ ├─ css // css樣式資源文件 ├─ images // 圖片資源文件 └─ js ├─ common.js // 公共js方法 ├─ game.js // 游戲主要運(yùn)行邏輯 └─ scene.js // 游戲場(chǎng)景相關(guān)類
游戲?qū)崿F(xiàn)邏輯
這里對(duì)游戲中需要繪制的擋板、小球、磚塊、計(jì)分板都進(jìn)行了實(shí)例化,并將游戲主要運(yùn)行邏輯單獨(dú)進(jìn)行實(shí)例化
擋板 Paddle
class Paddle {
constructor (_main) {
let p = {
x: _main.paddle_x, // x 軸坐標(biāo)
y: _main.paddle_y, // y 軸坐標(biāo)
w: 102, // 圖片寬度
h: 22, // 圖片高度
speed: 10, // x軸移動(dòng)速度
ballSpeedMax: 8, // 小球反彈速度最大值
image: imageFromPath(allImg.paddle), // 引入圖片對(duì)象
isLeftMove: true, // 能否左移
isRightMove: true, // 能否右移
}
Object.assign(this, p)
}
// 向左移動(dòng)
moveLeft () {
...
}
// 向右移動(dòng)
moveRight () {
...
}
// 小球、擋板碰撞檢測(cè)
collide (ball) {
...
}
// 計(jì)算小球、擋板碰撞后x軸速度值
collideRange (ball) {
...
}
}
擋板類:主要會(huì)定義其坐標(biāo)位置、圖片大小、x 軸位移速度、對(duì)小球反彈速度的控制等,再根據(jù)不同按鍵響應(yīng) moveLeft 和 moveRight 移動(dòng)事件,collide 方法檢測(cè)小球與擋板是否碰撞,并返回布爾值
小球 Ball
class Ball {
constructor (_main) {
let b = {
x: _main.ball_x, // x 軸坐標(biāo)
y: _main.ball_y, // y 軸坐標(biāo)
w: 18, // 圖片寬度
h: 18, // 圖片高度
speedX: 1, // x 軸速度
speedY: 5, // y 軸速度
image: imageFromPath(allImg.ball), // 圖片對(duì)象
fired: false, // 是否運(yùn)動(dòng),默認(rèn)靜止不動(dòng)
}
Object.assign(this, b)
}
move (game) {
...
}
}
小球類:其大部分屬性與擋板類似,主要通過 move 方法控制小球運(yùn)動(dòng)軌跡
磚塊 Block
class Block {
constructor (x, y, life = 1) {
let bk = {
x: x, // x 軸坐標(biāo)
y: y, // y 軸坐標(biāo)
w: 50, // 圖片寬度
h: 20, // 圖片高度
image: life == 1 ? imageFromPath(allImg.block1) : imageFromPath(allImg.block2), // 圖片對(duì)象
life: life, // 生命值
alive: true, // 是否存活
}
Object.assign(this, bk)
}
// 消除磚塊
kill () {
...
}
// 小球、磚塊碰撞檢測(cè)
collide (ball) {
...
}
// 計(jì)算小球、磚塊碰撞后x軸速度方向
collideBlockHorn (ball) {
...
}
}
磚塊類:會(huì)有兩個(gè)屬性不同,分別是 life 和 是否存活。然后,在小球和磚塊撞擊時(shí),調(diào)用 kill 方法扣除當(dāng)前磚塊血量,當(dāng)血量為0時(shí),清除磚塊。collide 方法檢測(cè)小球與磚塊是否碰撞,并返回布爾值
計(jì)分板 Score
class Score {
constructor (_main) {
let s = {
x: _main.score_x, // x 軸坐標(biāo)
y: _main.score_y, // y 軸坐標(biāo)
text: '分?jǐn)?shù):', // 文本分?jǐn)?shù)
textLv: '關(guān)卡:', // 關(guān)卡文本
score: 200, // 每個(gè)磚塊對(duì)應(yīng)分?jǐn)?shù)
allScore: 0, // 總分
blockList: _main.blockList, // 磚塊對(duì)象集合
blockListLen: _main.blockList.length, // 磚塊總數(shù)量
lv: _main.LV, // 當(dāng)前關(guān)卡
}
Object.assign(this, s)
}
// 計(jì)算總分
computeScore () {
...
}
}
分?jǐn)?shù)類:會(huì)記錄當(dāng)前分?jǐn)?shù)、關(guān)卡數(shù),其中 computeScore 方法會(huì)在小球碰撞磚塊且磚塊血量為0時(shí)調(diào)用,并累加總分
場(chǎng)景 Scene
class Scene {
constructor (lv) {
let s = {
lv: lv, // 游戲難度級(jí)別
canvas: document.getElementById("canvas"), // canvas 對(duì)象
blockList: [], // 磚塊坐標(biāo)集合
}
Object.assign(this, s)
}
// 實(shí)例化所有磚塊對(duì)象
initBlockList () {
...
}
// 創(chuàng)建磚塊坐標(biāo)二維數(shù)組,并生成不同關(guān)卡
creatBlockList () {
...
}
}
場(chǎng)景類:主要是根據(jù)游戲難度級(jí)別,繪制不同關(guān)卡及磚塊集合(目前只生成了三個(gè)關(guān)卡)。其中 creatBlockList 方法先生成所有磚塊的二維坐標(biāo)數(shù)組,再調(diào)用 initBlockList 方法進(jìn)行所有磚塊的實(shí)例化
游戲主邏輯 Game
class Game {
constructor (fps = 60) {
let g = {
actions: {}, // 記錄按鍵動(dòng)作
keydowns: {}, // 記錄按鍵 keycode
state: 1, // 游戲狀態(tài)值,初始默認(rèn)為1
state_START: 1, // 開始游戲
state_RUNNING: 2, // 游戲開始運(yùn)行
state_STOP: 3, // 暫停游戲
state_GAMEOVER: 4, // 游戲結(jié)束
state_UPDATE: 5, // 游戲通關(guān)
canvas: document.getElementById("canvas"), // canvas 元素
context: document.getElementById("canvas").getContext("2d"), // canvas 畫布
timer: null, // 輪詢定時(shí)器
fps: fps, // 動(dòng)畫幀數(shù),默認(rèn)60
}
Object.assign(this, g)
}
...
}
游戲核心類:這里包括游戲主要運(yùn)行邏輯,包括但不限于以下幾點(diǎn)
- 繪制游戲整個(gè)場(chǎng)景
- 調(diào)用定時(shí)器逐幀繪制動(dòng)畫
- 游戲通關(guān)及游戲結(jié)束判定
- 綁定按鈕事件
- 邊界檢測(cè)處理函數(shù)
- 碰撞檢測(cè)處理函數(shù)
入口函數(shù) _main
let _main = {
LV: 1, // 初始關(guān)卡
MAXLV: 3, // 最終關(guān)卡
scene: null, // 場(chǎng)景對(duì)象
blockList: null, // 所有磚塊對(duì)象集合
ball: null, // 小球?qū)ο?
paddle: null, // 擋板對(duì)象
score: null, // 計(jì)分板對(duì)象
ball_x: 491, // 小球默認(rèn) x 軸坐標(biāo)
ball_y: 432, // 小球默認(rèn) y 軸坐標(biāo)
paddle_x: 449, // 擋板默認(rèn) x 軸坐標(biāo)
paddle_y: 450, // 擋板默認(rèn) y 軸坐標(biāo)
score_x: 10, // 計(jì)分板默認(rèn) x 軸坐標(biāo)
score_y: 30, // 計(jì)分板默認(rèn) y 軸坐標(biāo)
fps: 60, // 游戲運(yùn)行幀數(shù)
game: null, // 游戲主要邏輯對(duì)象
start: function () {
let self = this
/**
* 生成場(chǎng)景(根據(jù)游戲難度級(jí)別不同,生成不同關(guān)卡)
*/
self.scene = new Scene(self.LV)
// 實(shí)例化所有磚塊對(duì)象集合
self.blockList = self.scene.initBlockList()
/**
* 小球
*/
self.ball = new Ball(self)
/**
* 擋板
*/
self.paddle = new Paddle(self)
/**
* 計(jì)分板
*/
self.score = new Score(self)
/**
* 游戲主要邏輯
*/
self.game = new Game(self.fps)
/**
* 游戲初始化
*/
self.game.init(self)
}
}
入口函數(shù):實(shí)現(xiàn)了游戲中需要的所有類的實(shí)例化,并進(jìn)行游戲的初始化
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
javascript 禁止復(fù)制網(wǎng)頁(yè)
常見的一些禁止復(fù)制網(wǎng)頁(yè)的代碼,但破解方法也不見容易,這里就不說了,可以看本站以前發(fā)布的文章。2009-06-06
layer設(shè)置maxWidth及maxHeight解決方案
這篇文章主要介紹了layer設(shè)置maxWidth及maxHeight解決方案,非常不錯(cuò),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-07-07
HTML+CSS+JS實(shí)現(xiàn)的簡(jiǎn)單應(yīng)用小案例分享
這篇文章主要為大家分享四個(gè)用HTML+CSS+JS實(shí)現(xiàn)的簡(jiǎn)單應(yīng)用小案例,有:猜數(shù)字、表白墻、切換日夜間模式和待辦事項(xiàng),需要的可以參考一下2022-02-02
如何通過遞歸方法實(shí)現(xiàn)用json-diff渲染json字符串對(duì)比結(jié)果
JsonDiff是一個(gè)高性能json差異發(fā)現(xiàn)工具,它幾乎可以發(fā)現(xiàn)任何JSON結(jié)構(gòu)的差異,并且將錯(cuò)誤信息反饋給用戶,下面這篇文章主要給大家介紹了關(guān)于如何通過遞歸方法實(shí)現(xiàn)用json-diff渲染json字符串對(duì)比結(jié)果的相關(guān)資料,需要的朋友可以參考下2022-12-12
連續(xù)操作HTMLElement對(duì)象圖文解決方法
Object.prototype.***不能用作在HTMLElement對(duì)象上,如本后面的抓圖所示。2008-03-03

