微信小游戏笔记

微信小游戏笔记(flappy bird)

微信小游戏必要的部分为game.js和game.json,该小游戏的实现为直接在game.js中编写,由于还没有进行模块化逻辑性可能并不流畅。可在之后有时间进行模块化使结构更加清晰。

画布与全局变量的定义

const canvas = wx.createCanvas()
const ctx = canvas.getContext(‘2d’)
var score = 0
var speed = 0
const screenWidth = window.innerWidth
const screenHeight = window.innerHeight
对于接下来的小游戏的实现主要方法就是在画布上对图像的绘制擦除与重新绘制,需在画布上进行,而score为游戏的得分记录,speed为随着分数上升游戏的相应速度变化。

计分栏

function renderGameScore(ctx, score) {
ctx.fillStyle = “#1aad19”
ctx.font = “20px Arial”

ctx.fillText(
score,
10,
30
)
}
该函数为在屏幕的左上角一块区域为积分区域,并可通过ctx.fillStyle和 ctx.font修改相应字体的颜色和字体

生成随机数

function randomNum(min, max) {
switch (arguments.length) {
case 1:
return Math.floor(Math.random() * minNum + 1);
break;
case 2:
return Math.floor(Math.random() * (max - min + 1) + min);
break;
default:
return 0;
break;
}
}
要实现flappy bird那么障碍物的高度那必然不能是固定的所以需要一个函数来随机生成障碍物的高度,通过 randomNum(min, max)函数可生成一个在min与max直接的随机数在之后作为障碍物的高度

随机数的检查

var x1 = 0;
function fn(min, max) {

//准备一个空数组用于返回
var result;
//创建一个随机数
var num = randomNum(min, max);
//对随机数检查 ,是否重复
result = num;
x1 = result;
// return result;

console.log(result);

}
fn(0, 200);//生成一个0~200的随机数
result在之后的函数中也会使用通过一个全局变量将其传出,当然也可以通过其他方法,这里所用的方法有些麻烦了

背景的绘制

const context = canvas.getContext(‘2d’)// 创建一个 2d context
const context1 = canvas.getContext(‘2d’)
const bg = wx.createImage()
bg.src = ‘images/background.jpg’

function setup() {

bg.onload = function () {
context.drawImage(bg, 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);

console.log(0);
}
}
setup()
在这里又建立了两个2d context,其实只需要一个就足够了,这里用两个只是当时为了更容易区分出不同图片与障碍物,在绘制时更加清晰。

障碍物的绘制与移动

var y2;
var x2;
context.fillStyle = ‘#1aad19’ // 矩形颜色
context1.fillStyle = ‘#1aad19’
context.fillRect(canvas.width, 0, 50, x1); // 矩形左上角顶点为(canvas.width, 0),右下角顶点为(50, x1)
context1.fillRect(canvas.width, x1 + 120, 50, canvas.height - (x1 + 120))
function drawRect(x, y) {
x2=x;
y2=y;
if (speed < 4) {
context.clearRect(x + 1 + speed + 0.41, y, 50, x1)
context.drawImage(bg, x + 1 + speed + 0.41, y, 50, x1, x + 1 + speed + 0.41, y, 50, x1);
context1.clearRect(x + 1 + speed + 0.41, x1 + 120, 50, canvas.height - (x1 + 120))
context.drawImage(bg, x + 1 + speed + 0.41, x1 + 120, 50, canvas.height - (x1 + 120), x + 1 + speed + 0.41, x1 + 120, 50, canvas.height - (x1 + 120));
}
else {
context.clearRect(x + 1 + speed, y, 50, x1)
context.drawImage(bg, x + 1 + speed, y, 50, x1, x + 1 + speed, y, 50, x1)
context1.clearRect(x + 1 + speed, x1 + 120, 50, canvas.height - (x1 + 120))
context1.drawImage(bg, x + 1 + speed, x1 + 120, 50, canvas.height - (x1 + 120), x + 1 + speed, x1 + 120, 50, canvas.height - (x1 + 120))
}
context.fillRect(x, y, 50, x1)
context1.fillRect(x, x1 + 120, 50, canvas.height - (x1 + 120))
}

编写相应函数对对障碍物进行绘制,绘制相应矩形,由于要实现矩形的移动,所以每次绘制出现的障碍物时需对之前出现的障碍物进行clear,但在对障碍物进行clear之后会发现背景相应的部分也会消失,所以需要对背景相应的部分进行重新绘制。
在最开始时曾想过直接对整个背景进行重新绘制,但是正式实验时发现如果是对全部背景进行绘制由于是每16ms会进行对障碍物与背景的重新绘制会导致出现闪屏的现象,而对局部背景进行重新绘制就可以避免这一现象出现。

对bird进行绘制

const image = wx.createImage()
let imgX = canvas.width / 3
let imgY = canvas.height / 2 - 26
image.onload = function () {
context.drawImage(image, imgX, imgY)
}
image.src = ‘images/bird.png’
就是对操纵的bird进行绘制起始位置为大约三分之一屏宽二分之一屏高位置
bird图片需使用无背景的图片,可用Photoshop等对其进行提取并重新设置图片大小,我们这个大小为33×26。
微信小游戏笔记

使小游戏能正常运行

let rectX = canvas.width
const rectY = 0

var interval = setInterval(function test() {
ctx.clearRect(0, 0, 50, 50);
ctx.drawImage(bg, 0, 0, 50, 50, 0, 0, 50, 50);

renderGameScore(ctx, score)
rectX = rectX - 1 - speed
drawRect(rectX, rectY)
context.clearRect(imgX, imgY - 1, 33, 26);
context1.drawImage(bg, imgX, imgY - 1, 33, 26, imgX, imgY - 1, 33, 26);
context.drawImage(image, imgX, imgY++);

let touchX = imgX;
let touchY = imgY;
if ((touchX >= rectX && touchX <= rectX + 50 && touchY <= x1) || (touchX + 33 >= rectX && touchX + 33 <= rectX + 50 && touchY <= x1) || (touchX >= rectX && touchX <= rectX + 50 && touchY + 26 >= x1 + 120) || (touchX + 33 >= rectX && touchX + 33 <= rectX + 50 && touchY + 26 >= x1 + 120)) { // bird与矩形发生碰撞
clearInterval(interval);
wx.showModal({
title: ‘它死了’,
content: ‘重新开始’,
showCancel: false,//是否显示取消按钮
success: function (res) {
if (res.cancel) {
//点击取消,默认隐藏弹框
} else {
context.clearRect(imgX-50, 0, imgX+50, canvas.height)
context.drawImage(bg, imgX-50, 0, imgX + 50, canvas.height, imgX-50, 0, imgX + 50, canvas.height);
context.clearRect(imgX, imgY - 1, 33, 26);
context1.drawImage(bg, imgX, imgY - 1, 33, 26, imgX, imgY - 1, 33, 26);
console.log(5);
speed = 0;
score=0;
renderGameScore(ctx, score);
rectX = canvas.width
imgX = canvas.width / 3
imgY = canvas.height / 2 - 26
context.drawImage(image, imgX, imgY++);
interval = setInterval(test, 16);
}
}

})
}

if (imgY + 26 >= canvas.height||imgY<=0) {
clearInterval(interval); //停止循环进行
wx.showModal({
title: ‘它死了’,
content: ‘重新开始’,
showCancel: false,//是否显示取消按钮
success: function (res) {
if (res.cancel) {
//点击取消,默认隐藏弹框
} else {
context.clearRect(0, 0, canvas.width, canvas.height)
context.drawImage(bg, 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height);
context.clearRect(imgX, imgY - 1, 33, 26);
context1.drawImage(bg, imgX, imgY - 1, 33, 26, imgX, imgY - 1, 33, 26);
console.log(5);
speed = 0;
score = 0;
renderGameScore(ctx, score);
rectX = canvas.width
imgX = canvas.width / 3
imgY = canvas.height / 2 - 26
context.drawImage(image, imgX, imgY++);
interval = setInterval(test, 16);
}
}

})
}

if (rectX <= -50) {
speed = speed + 0.4;
if (speed > 4) { speed = 4 }
score = score + 1;
console.log(score);
renderGameScore(ctx, score);
context.clearRect(rectX, rectY, 1, x1);
context1.clearRect(rectX, x1 + 33, 1, canvas.height - (x1 + 33));
fn(0, 200);
rectX = canvas.width
}
}, 16)
该部分为该小游戏的主体部分,通过计数器setInterval函数每过16ms循环执行该函数,每次清除之前的障碍物后重新绘制相应部分背景并使障碍物的起始x-1再重新绘制通过循环实现障碍物随时间移动,要说的是背景与障碍物的绘制顺序要弄清楚,因为画布绘制之后的图像会覆盖之前的所以不要使障碍物被背景覆盖。
在障碍物来到屏幕的最左边时需要对其进行回收,使障碍物回到屏幕的最右边重新开始运动,并对分数和难度(障碍物速度每次加speed)进行更新,若不进行回收可能会出一些问题。
还需对bird与障碍物的碰撞进行判定当角色与障碍物进行碰撞或者与屏幕最下方最上方进行碰撞时,会出现弹框提示游戏结束,这里很重要一点是由于我们是通过计时器循环实现障碍物与角色的运动的,在跳出弹框之前一定要先调用函数clearInterval(interval)来实现停止循环,否则由于每16ms进行一次循环,它会一直判定发生碰撞,也就会使弹框变成俄罗斯套娃,无限弹框会让你什么都无法操作,所以停止循环十分重要。
在发生碰撞之后,由于要点击确定后重新开始,所以要对一些变量,比如bird的位置、score、speed已经障碍物的初始位置进行初始化,使游戏能够重新开始。
由于我们之前在定义计时器函数时函数名为test,在之前调用停止循环后只需调用 interval = setInterval(test, 16)即可实现计时器的重新开始计算,游戏也就重新开始了。

点击事件

wx.onTouchStart(function () {
context.clearRect(imgX, imgY, 33, 26);
context1.drawImage(bg, imgX, imgY, 33, 26, imgX, imgY, 33, 26);
imgY = imgY - 30

context.drawImage(image, imgX, imgY);
})

调用了wx.onTouchStart函数,当每次发生点击屏幕事件时就会调用该函数,该函数实现的是每次点击就会使bird向上飞30px,从而实现bird的上升。

微信小游戏笔记
至此flappy bird小游戏就基本实现了。