微信小遊戲
因爲工作需要,提前預研微信小遊戲的開發流程。做了如下一個簡單的demo項目,並且把實際項目中遇到的坑點都一一詳細列出,方便在今後的項目中可以進行查閱。
小遊戲填坑指南
-
微信小遊戲只允許在調試模式下使用
window
全局變量,在真機模式下使用window
會導致報錯。 -
如何在canvas繪製圖片
let image = wx.createImage()
image.src = './resources/background.png'
// 資源加載完成回調
image.onload = _ => {
this.ctx.drawImage(
image,
0, 0,
// 源圖片裁剪的寬高
image.width,
image.height,
0, 0,
// 屏幕投影寬高
image.width,
image.height
)
}
- 單例模式應用
export default class Director {
constructor () {
console.log('Director 構造器初始化')
}
static getInstance () {
if (!Director.instance) {
Director.instance = new Director()
}
return Director.instance
}
}
// other Class
import Director from './js/Director'
export default class Main {
constructor () {
// 獲取 Director 實例
this.director = Director.getInstance()
}
}
- 實現全局狀態管理器
export default class DataStore {
constructor () {
this.map = new Map()
}
static getInstance () {
if (!DataStore.instance) {
DataStore.instance = new DataStore()
}
return DataStore.instance
}
put (key, value) {
this.map.set(key, value)
return this // 保證鏈式調用
}
get (key) {
return this.map.get(key)
}
// 資源銷燬
destory () {
// for (let value of this.map.values()) {
// value = null
// }
}
}
super
之前不可以調用this
export default class Background extends Sprite {
constructor (image = null) {
// this 不可以調用
this.image = null
// this 不可以調用
super(image,
0, 0,
image.width,
image.height,
0, 0,
screenWidth,
screenHeight
)
}
}
- 子類中通過
super
,可以調用父類的方法
export default class Background extends Sprite {
draw () {
super.drawImage()
}
}
- 微信垃圾回收
wx.triggerGC()
- 播放音樂
// 播放背景音樂
createBackgroundMusic () {
const bgm = wx.createInnerAudioContext()
bgm.autoplay = true // 自動播放
bgm.loop = true // 循環播放
bgm.src = 'audio/bgm.mp3'
}
- 振動檢測
// 振動檢測
wx.vibrateShort({
success () {
console.log('success')
},
fail () {
console.log('fail')
},
complete () {
console.log('complete')
}
})
- 微信常用數據接口
// 獲取用戶授權信息
// https://developers.weixin.qq.com/miniprogram/dev/api/wx.getUserInfo.html
wx.getUserInfo(Object object)
// 用戶登錄
// https://developers.weixin.qq.com/miniprogram/dev/api/wx.login.html
wx.login(Object object)
- 搭建簡易的websocket服務
// 服務端ws
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
// 建立連接
wss.on('connection', function connection(ws) {
// 接受客戶端消息
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});
// 發送消息
ws.send('something');
});
// 客戶端ws
setConnect () {
console.log('setConnect')
wx.connectSocket({
url: 'ws://127.0.0.1:8080',
success () {
console.log('建立成功')
},
complete () {
console.log('建立完成')
}
})
}
- 在webSocket中發送消息
wx.onSocketOpen(_ => {
// 必須在onSocketOpen回調中發送
wx.sendSocketMessage({
data: '發送客戶端消息~~~~~~~~~~~',
success () {
console.log('發送成功')
},
complete () {
console.log('發送完成')
}
})
// 監聽服務端的消息
wx.onSocketMessage(res => {
console.log('這是接受服務端數據', res)
})
})
- 簡易碰撞檢測
// 碰撞檢測
checkCollision (point, range, image) {
const offset = {
top: -1,
bottom: -1,
left: -1,
right: -1
}
if (point.y < range.top + image.height / 2) {
// 超出上邊界
offset.top = parseFloat((range.top + image.height / 2 - point.y) / image.height)
} else if (point.y > range.bottom - image.height / 2) {
// 超出下邊界
offset.bottom = parseFloat((point.y - (range.bottom - image.height / 2)) / image.height)
}
if (point.x < range.left + image.width / 2) {
// 超出左邊界
offset.left = parseFloat((range.left + image.width / 2 - point.x) / image.width)
} else if (point.x > range.right - image.width / 2) {
// 超出右邊界
offset.right = parseFloat((point.x - (range.right - image.width / 2)) / image.width)
}
return offset
}
- 簡易邊界檢測
checkRange (point) {
let infos = {
valid: false,
pos: -1, // 點擊區域無效
point
}
const unitImage = this.dataStore.get('wrong')
if (point.y >= this.topRange.top &&
point.y <= this.topRange.bottom &&
point.x >= this.topRange.left &&
point.x <= this.topRange.right
) {
console.log('點擊了上邊界')
infos.pos = 0
infos.valid = true
infos.offset = this.checkCollision(point, this.topRange, unitImage)
} else if (point.y >= this.bottomRange.top &&
point.y <= this.bottomRange.bottom &&
point.x >= this.bottomRange.left &&
point.x <= this.bottomRange.right
) {
console.log('點擊了下邊界')
infos.pos = 1
infos.valid = true
infos.offset = this.checkCollision(point, this.bottomRange, unitImage)
}
return infos
}
- canvas 文字居中
// canvas 文字居中(動態計算文字長度)
const len = (this.score.toString().length - 1)
this.dataStore.ctx.font = `bold ${px(48)}px Arial`
this.dataStore.ctx.fillStyle = '#833823'
this.dataStore.ctx.fillText(
this.score,
px(pos.x - 10 * len), px(pos.y), 1000)
- Promise.all 應用
// 資源加載
this.image = wx.createImage()
this.progressbg = wx.createImage()
this.progressbar = wx.createImage()
this.image.src = 'resources/images/common/bg.png'
this.progressbg.src = 'resources/images/common/progress-bar.png'
this.progressbar.src = 'resources/images/common/progress.png'
this.loaded = false
const p1 = new Promise(resolve => {
this.image.onload = _ => {
resolve()
}
})
const p2 = new Promise(resolve => {
this.progressbg.onload = _ => {
resolve()
}
})
const p3 = new Promise(resolve => {
this.progressbar.onload = _ => {
resolve()
}
})
Promise.all([p1, p2, p3]).then(_ => {
console.log('loading頁加載完成')
this.loaded = true
})
- 繪製矩形
// 繪製矩形
ctx.fillStyle = 'rgba(255,255,255,0.9)'
const width = px(300)
const height = px(200)
ctx.fillRect(this.screenWidth / 2 - width / 2, this.screenHeight / 2 - height / 2, width, height)
ctx.fill()
- js 隨機數
Math.ceil(); //向上取整。
Math.floor(); //向下取整。
Math.round(); //四捨五入。
Math.random(); //0.0 ~ 1.0 之間的一個僞隨機數