微信小遊戲開發之三:實現小遊戲的簡易引擎
阿新 • • 發佈:2019-01-10
一、建立引擎目錄
在主目錄下建立名為'lib'的資料夾,存放引擎程式碼
二、建立所有遊戲元素的基類:Node
在'lib'資料夾下建立'node.js'檔案;
一個元素,需要座標去定義位置,長寬來定義範圍,還需要能夠切換顯示狀態,新增子元素和獲取父元素等等
程式碼如下:
export default class Node { constructor(x = 0, y = 0, width = 0, height = 0) { // 在父元素中的座標 this.x = x this.y = y // 父元素在世界座標系中的座標 this.absX = 0 this.absY = 0 // 錨點 this.anchorPointX = 0.5 this.anchorPointY = 0.5 // 寬和高 this.width = width this.height = height // 子元素 this.children = [] // 是否顯示 this.visible = true } /** * 將當前元素繪製到螢幕中 * @ctx canvas_context */ draw(ctx) { if (this.visible) { this.children.forEach((child) => { child.draw(ctx) }) } // node本身不進行繪製,需要讓子類自行繪製 } /** * 增加一個子元素 * @child 子元素 */ addChild(child) { child.parent = this child.absX += this.x child.y += this.y this.children.push(child) console.log("node.addChild") } /** * 獲得計算錨點後的全域性座標 */ getFixedPosition() { let absPos = this.getAbsPosition() return { x: absPos.x - this.anchorPointX * this.width, y: absPos.y - this.anchorPointY * this.height } } /** * 設定錨點,值範圍在(0, 1) */ setAnchorPoint(x, y) { if (x < 0) x = 0 if (y < 0) y = 0 if (x > 1) x = 1 if (y > 1) y = 1 this.anchorPointX = x this.anchorPointY = y } /** * 快速設定寬和高 */ setContentSize(width, height) { this.width = width this.height = height } /** * 快速設定座標,並修改子元素的絕對座標 */ setPosition(x, y) { this.x = x this.y = y this.setChildrenAbsPosition(this.getAbsPosition()) } setPositionX(x) { this.x = x this.setChildrenAbsPosition(this.getAbsPosition()) } setPositionY(y) { this.y = y this.setChildrenAbsPosition(this.getAbsPosition()) } /** * 獲得未計算錨點的全域性座標 */ getAbsPosition() { return { x: this.x + this.absX, y: this.y + this.absY } } /** * 修改所有子元素的座標 */ setChildrenAbsPosition(absPos) { this.children.forEach((child) => { child.setAbsPosition(absPos) }) } setAbsPosition(absPos) { this.absX = absPos.x this.absY = absPos.y this.setChildrenAbsPosition(absPos) } }
三、實現Label類
在'lib'資料夾下新建'label.js'檔案 由於計算文字寬度,必須要獲得canvas的context, 所以在'lib'資料夾下新建'warehouse'類作為資料倉庫,儲存遊戲中需要用到的常量let ctx function WareHouse() { this.getCtx = function () { if (!ctx) { ctx = canvas.getContext('2d') } return ctx } } export default (new WareHouse())
‘lib/label.js’
import Node from './node.js' import WareHouse from './warehouse.js' export default class Lable extends Node { constructor(text = '', x = 0, y = 0, fontSize = "20px", fontFamily = "Courier New") { super(x, y) this.fontSize = fontSize this.fontFamily = fontFamily this.text = text } draw(ctx) { super.draw(ctx) if (this.visible) { ctx.font = this.fontSize + " " + this.fontFamily let fixedPos = this.getFixedPosition() ctx.fillText(this.text, fixedPos.x, fixedPos.y) } } /** * Label的寬度需要通過canvas進行測量,所以要特殊處理 */ getFixedPosition() { let ctx = WareHouse.getCtx() this.width = ctx.measureText(this.text).width return super.getFixedPosition() } setFontSize(fontsize) { this.fontSize = fontSize } setFontFamily(fontFamily) { this.fontFamily = fontFamily } }
四、實現Sprite類
在'lib'資料夾下新建'sprite.js'檔案import Node from './node'
export default class Sprite extends Node {
constructor(imgSrc = '', width = 0, height = 0, x = 0, y = 0) {
super(x, y, width, height)
this.img = new Image()
this.img.src = imgSrc
}
draw(ctx) {
let absPos = this.getFixedPosition()
if (this.visible) {
ctx.drawImage(
this.img,
absPos.x,
absPos.y,
this.width,
this.height
)
}
super.draw(ctx)
}
setImage(imgSrc){
this.img.src = imgSrc
}
}
五、檢視效果
在'main.js'中編輯如下程式碼:import './js/libs/weapp-adapter'
import './js/libs/symbol'
import Sprite from './lib/sprite.js'
import Label from './lib/label.js'
import WareHouse from './lib/warehouse.js'
// 獲取canvas上下文
let ctx = WareHouse.getCtx()
//新建一個Sprite和一個Label
let helloSprite = new Sprite("hello.png")
let helloLable = new Label("hello world")
let worldLable = new Label("world", 0, 50)
helloSprite.addChild(helloLable)
helloLable.addChild(worldLable)
helloSprite.setPosition(150, 50)
helloSprite.setContentSize(50, 50)
helloSprite.setAnchorPoint(0.5,0.5)
helloLable.setAnchorPoint(0.5, 0.5)
// 模擬遊戲迴圈
window.requestAnimationFrame(loop, canvas)
// update中渲染元素
function update() {
//helloSprite.setPositionY(helloSprite.y + 0.1)
helloSprite.draw(ctx)
}
function loop() {
// 清空顯示區域
ctx.clearRect(0, 0, canvas.width, canvas.height)
// 渲染元素
update()
// 持續迴圈呼叫自身
window.requestAnimationFrame(loop, canvas)
}
可以看到如下效果:
未完待續...