首先,我们来看下h5游戏和微信小游戏之间的区别:
1.我认为最大的一点区别在于,微信小游戏全是基于单个canvas的结构,而h5的游戏,我们可以使用多层的canvas对游戏进行分类,比如我之前有开发一个《大头吃小头》的h5游戏
在这里,我们就对它进行了三层结构的划分,1层为主游戏层,主要处理游戏内的各精灵的活动,1层为控制器层(或操作层),主要处理事件或摇杠的操作,第3层就是显示层了,主要展示一些文字如得分、生命值等信息。这样划分的好处是显而意见的,可以充分利用每层的独立渲染,减少性能的开销。然而在微信小游戏中,只有一个canvas是显示的,再创建的canvas都是不可见的。
2.第二点不同在于,无法使用dom元素,dom虽然在动画的性能上比canvas差很多,但它也有很多的优点,比如他可以结合css样式快速的呈现很好的展示效果,包括事件的处理也大不同,例如在《大头吃小头》这款游戏中,控制杠就是用html元素展示的,包括游戏里的一些按钮,它们并不是在每帧都需要重绘的,更多的可能是位置的变化。而在微信小游戏的开发中,我们完全不能使用除canvas外的html元素,游戏里的任何变化,只能通过每帧的清屏重绘来完成。
3.第三点不同在于api不同,基本上原来在浏览器端的api都不能用,包括事件的绑定也不一样,这也就是别人说的,小程序的开发,并不会给你前端的开发加成,因为是两套完全不同的api玩法,所以我们需要adapter,官方有提供一个简单的weapp-adapter,来综合小游戏和h5之间的差异,在下面的内容里,我将抛弃它,完全使用api来操作,既然是两套不同的玩法,我认为没必要统一。
上面说到adapter,是不是意味着我们要写很多的基础代码呢,当然要写,不过我已经把这些基础的代码写成了一个库,名字叫wx-jy,它的作用与adapter又有着不同,主要是为了我们减少对游戏的转承启合而开发代码,多的不说了,源码在github上有,包括h5版的jy和微信版的wx-jy
下面我们来看一下,今天我们要带大家完成的小游戏《打气球》,这款游戏很适合做入门教程,首先他包含有小游戏的所有过程,然后他逻辑简单,不会看不懂。说到游戏的过程,我把它分成六大状态:
前面三个状态loading、title、descript为游戏准备阶段,runing就是游戏的核心运行状态了,也许你会问了,为啥要分这么细,游戏不就是开始和结束吗?呃,那是你觉得,我要我觉得。
说了这么多了,我们还是没开始写《打气球》的一行代码,不要紧,老弟,磨材不误砍刀工,其实打气球的代码不超过十行,我们总不能拿那十行代码讲一天吧?好了,开始正式的撸码吧!
第一步,我们要创建一个游戏的舞台,我们所有的游戏小伙伴们都将在这个舞台上起舞。
import {
JY,
STATE,
Stage,
Title,
Descript,
Sprite,
lib
} from 'wx-jy';
const canvas = wx.createCanvas();
const [height, width] = [canvas.height, canvas.width]
//创建舞台
let stage = new Stage(canvas, width, height, '#FFFFFF');
前两行引用wx-jy的相关依赖,你可以把这个文件单独下载下来引用。下面就是new Stage了,有了舞台后,我们就需要把一些要素放进去了,比如标题和介绍
let title = new Title('打气球', stage);
title.create = (resolve) => {
lib.write(stage, '一起来打气球')
resolve();
}
let descript = new Descript(stage)
descript.create = async (resolve) => {
lib.draw(stage, 'images/descript.jpg', 0, 0, stage.width, stage.height)
// await lib.waitMoment(3000);
//添加开始按钮的Sprite
let btn = new Sprite(stage, 'images/btn-start.png', 100, 40, (width - 100) / 2, height - 40 - 40);
btn.draw();
wx.onTouchStart((e) => {
btn.touchHits(e,()=>{
wx.offTouchStart();
resolve()
})
});
}
在descript这里的代码为什么会多一点,主要是要展示一个按钮,然后绑定点击的事件,所有步聚的方法都使用异步函数的方式编写,这样只需要resolve()调用就会自动走到下一步了。
接下来就是声明一个气球的精灵类了,这个精灵,有两个属性方法,一个是上升的速度,一个是更新位置的方法。
//气球类
class Ball extends Sprite {
speed: number = 1;//速度
//更新位置
update() {
this.y -= this.speed;
if (this.y+this.height < 0) {
this.visible = false;
}
}
}
做完这些,我们就可以写我们的主体函数类了,它继承于JY,对过程进行扩展。
class Game extends JY {
frame: number = 0;//帧数
ballList: Ball[] = [];//所有球的集合
newGame() {
this.stage.style = "green";
this.setState(STATE.running);
//事件绑定
wx.onTouchStart(e => {
let { clientX, clientY } = e;
console.log(clientX, clientY)
this.ballList.forEach((ball,index) => {
//触碰回收球并播放声音
ball.touchHits(e,()=>{
this.ballList.splice(index,1);
lib.play('audio/boom.mp3');
})
});
});
}
async running() {
this.frame++;
//先清空场景
this.stage.clear();
this.createSprite();
this.ballList.forEach((ball,index) => {
ball.update();
ball.draw();
//回收球
if(!ball.visible){
this.ballList.splice(index,1);
}
});
}
//创建角色
createSprite() {
//100帧创建一个角色
if (this.frame % 100 == 0) {
let x = lib.random(0, stage.width - 30);
let w = 40;
let h = 340 / 120 * w;
let ball = new Ball(this.stage, 'images/ball.png', w, h, x, this.stage.height);
// ball.touchHits(this.touch)
this.ballList.push(ball);
}
}
async gameOver() {
stage.clear();
lib.write(stage, '游戏结束!');
await lib.waitMoment(3000);
this.setState(STATE.descript);
}
}
这里我们重写了newGame、runing和gameover这三个生命周期,目的是个性化内容,所有的游戏可能真正的区别也只是游戏开始、运行和结束三个状态是不一样的了。
最后,我们实例化这个类,然后启动它,还有资源文件的加载。
let mygame = new Game(stage, title, descript);
mygame.resources = [
'images/ball.png',
'images/btn-start.png',
'images/descript.jpg',
'audio/boom.mp3'
];
mygame.setup()
就这样,一款好看又好玩的《打气球》就基本完成了,所有需要我们编写的代码不过100行,中间你还可以添加生命数和分值来增强游戏的可玩性。
你也可以从github中clone下整个项目,然后用微信调试工具导入example这个目录,就可以直接预览到效果了https://github.com/tianxiangb...