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


    首先,我们来看下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这个目录,就可以直接预览到效果了

  • 相关阅读:
    Jmeter_实现操作postgresql数据库
    测试人员如何使用Git部署测试环境
    GitLab简单使用
    ssh: Could not resolve hostname git.*****-inc.com : Temporary failure in name resolution fatal: The remote end hung up unexpectedly
    本地Linux服务器上配置Git
    SeleniumIDE_初识
    自动化测试_测试模型
    Top命令详解02
    【Linux性能调优一】观大局:系统平均负载load average
    【自动化专题】借助firefox插件定位web元素小技巧
  • 原文地址:https://www.cnblogs.com/tianxiangbing/p/wx-jy.html
Copyright © 2020-2023  润新知