QQ技术群:5678537,70210212,77813547 个人网站:http://www.lovewebgames.com 邮箱:55342775@qq.com

如何快速开发一个微信小游戏--实例《打气球》

首先,我们来看下h5游戏和微信小游戏之间的区别:

1.我认为最大的一点区别在于,微信小游戏全是基于单个canvas的结构,而h5的游戏,我们可以使用多层的canvas对游戏进行分类,比如我之前有开发一个《大头吃小头》的h5游戏,如下图,演示地址:http://www.lovewebgames.com

 

在这里,我们就对它进行了三层结构的划分,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下整个项目,然后用微信调试工具导入dev这个目录,就可以直接预览到效果了

posted @ 2019-10-08 17:23  田想兵  阅读(2877)  评论(0编辑  收藏  举报
联系QQ:55342775,QQ技术群:5678537,70210212,77813547 个人网站:http://www.lovewebgames.com 邮箱:55342775@qq.com