zoukankan      html  css  js  c++  java
  • 如何快速开发一个微信小游戏--实例《打气球》

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

  • 相关阅读:
    POJ 3468 A Simple Problem with Integers
    BZOJ 4430 Guessing Camels
    POJ 2309 BST
    POJ 1990 MooFest
    cf 822B Crossword solving
    cf B. Black Square
    cf 828 A. Restaurant Tables
    Codefroces 822C Hacker, pack your bags!
    [HDU 2255] 奔小康赚大钱
    [BZOJ 1735] Muddy Fields
  • 原文地址:https://www.cnblogs.com/tianxiangbing/p/wx-jy.html
Copyright © 2011-2022 走看看