(小游戏)详解消方块:微信小程序开发

13 篇文章 0 订阅
12 篇文章 0 订阅

大家好!我又来了。今天我又写了一个超级无聊的小游戏

在无聊的道路上,渐行渐远。还记得儿时我们喜欢玩的这个游戏吗?

由于我申请的小程序不是小游戏,所以无法体验;

于是我又写成H5页面:http://www.yating.online/brick.html

喜欢就给我点个星吧:https://github.com/Chenyating/easyGame

一、简单介绍:

简单的介绍一下我的小游戏:

通过红色小块的反弹,吃掉白色小块,长条需接住反弹回来的红色小块;

操作说明:

1、点击界面的空白处;

游戏规则:

1、红色小块开始从白色长条出发,周而复始随机撞击小白块

2、红色小块回到底部时,必须在白色长条上

结束条件:

红色小块落地;(吃完小白块需要猴年马月

 

二、技术难点

  • 小程序的canvas的使用;
  • 本次开发的是小程序;

通过开发的过程,该游戏最大的难点如下:

1、小红运动的方式角度

2、小长条运动的方法:

 

三、实现步骤:

接下来我开始详细说明这个游戏设计过程,实现的逻辑;

红色小块简称:小红(red)

白色长条简称:小长(slider),

小白块简称:小白;

以下为我设置的变量:

  data: {
        // 画布配置
        canvasWidth: 310,
        canvasHeight: 500,
        canvasCenterX: 0,
        // 整块画布
        context: null,
        // 滑块配置
        sliderX: 125,
        sliderY: 490,
        sliderWidth: 100, //滑块宽度
        sliderHeight: 10, //滑块高度
        sliderCenter: null, //滑块中心
        sliderSpeed: 1, //滑块速度
        // 滑块移动到的位置
        mouseX: null,
        position: 1, //1为右,-1为左
        redraw: null, //滑块移动的循环作用
        // 砖头们的设置
        blocksContext: null,
        blocks: null,
        blocksWidth: 9,
        // 小红砖
        redBlock: null,
        redX: 150,
        redY: 480,
        redK: -1,
        redB: null,
        redM: 1,
        rered: null,
        redSpeed: 5,
        // 分值记录
        fail: 0,
        score: 0
    },

一、绘制

1、小长的绘制:

    // 绘制滑块
    drawSlider(x) {
        var bu = this.data.context
        bu.setFillStyle('#ffffff');
        bu.fillRect(x, this.data.sliderY, this.data.sliderWidth, this.data.sliderHeight);
        bu.draw();
    },

需要获取鼠标点击的位置,鼠标点击的位置相对于滑块中心点的方位,这里position为在x轴上移动的距离;

 //获取鼠标X的位置
    sliderDot(e) {
        this.setData({
            mouseX: e.detail.x - (this.data.sliderWidth / 2)
        })
        // 判断鼠标点击的滑块的位置相对于滑块的方向
        if (this.data.mouseX >= this.data.sliderCenter) {
            // 右边
            this.setData({
                position: 1
            })
            this.moveSlider(this.data.sliderX, this.data.position)
        } else {
            // 左边
            this.setData({
                position: -1
            })
            this.moveSlider(this.data.sliderX, this.data.position)
        }
    },

接着我们开始写,小长在底部移动的方法;

1、移动过程中,如果小长碰壁了,那么小长就停止移动,即使小长的中心没有到达鼠标点;

2、小长没有碰壁,则它朝指定位置移动,直到到达该指定位置;

    // 重新绘制滑块
    moveSlider(sliderX, x) {
        var that = this;
        // 移动循环
        clearTimeout(this.data.redraw);
        // 清除原来
        // var bu = this.data.context;
        // bu.clearRect(sliderX, this.data.sliderY, this.data.sliderWidth, this.data.sliderHeight)
        // 同步更新数据
        this.setData({
            sliderX: sliderX + x
        })
        // 重绘
        this.drawSlider(sliderX + x);
        // 条件判断:每次移动的时候先判断是否碰到墙壁
        this.setData({
            sliderCenter: that.data.sliderX + 20
        })
        if (this.data.sliderX >= (this.data.canvasWidth - this.data.sliderWidth) || this.data.sliderX <= 0) {
            // 如果碰到壁就停止
            clearTimeout(this.data.redraw);
            return;
        } else {
            // 判断一下滑块是否到鼠标点击的位置
            if (this.data.sliderCenter == this.data.mouseX) {
                // 如果到达鼠标位置,就结束;
                clearTimeout(this.data.redraw);
                return;
            } else {
                //否则就继续移动
                this.data.redraw = setTimeout(() => {
                    this.moveSlider(sliderX + x, x);
                }, this.data.sliderSpeed);
                return;

            }

        }
    },

 

2、绘制小白块

我用一个数组存放小白块的上色情况

    // 初始化砖头们的值,
    blocksArray() {
        var that = this;
        for (var i = 0; i < (that.data.canvasWidth / 10); i++) {
            for (var j = 0; j < (that.data.canvasHeight / 10); j++) {
                let blocks0 = 'blocks[' + i + '][' + j + '][0]'; //横坐标
                let blocks1 = 'blocks[' + i + '][' + j + '][1]'; //纵坐标
                let blocks2 = 'blocks[' + i + '][' + j + '][2]'; //上色与否 0,1
                // 10行以内有颜色
                if (j < 30) {
                    var color = 1;
                } else {
                    // 否则无颜色
                    var color = 0;
                }
                that.setData({
                    [blocks0]: i * 10,
                    [blocks1]: j * 10,
                    [blocks2]: color
                })
            }
        }
    },

绘制小白块们

 // 已知砖头数组,绘制砖头
    drawBlocks() {
        var that = this;
        var context = that.data.blocksContext;
        // 绘制众多小方块
        context.setFillStyle('#ffffff');
        for (var i = 0; i < that.data.blocks.length; i++) {
            for (var j = 0; j < that.data.blocks[i].length; j++) {
                // 绘制方块
                if (that.data.blocks[i][j][2] == 1) {
                    context.fillRect(that.data.blocks[i][j][0], that.data.blocks[i][j][1], this.data.blocksWidth, this.data.blocksWidth)
                } else {
                    continue;
                }
            }
        }

3、绘制小红

    // 绘制小红
    drawRed(x, y) {
        var bu = this.data.redBlock
        bu.rect(x, y, this.data.blocksWidth, this.data.blocksWidth)
        bu.setFillStyle('red')
        bu.fill()
        bu.draw()
    },

二、小红的运动轨迹

1、计算小红的运动函数:y=kx+b

 getLine(k, m) {
        this.data.redB = this.data.redY - k * this.data.redX;
        // console.log("y=" + k + "*x+" + this.data.redB, m)
        this.moveRed(k, this.data.redB, m, this.data.redX, this.data.redY)
    },

小红的运动轨迹为一条直线,小红的移动便就是随着这条直线运动

2、写小红移动的方法

小红在每次移动的过程中,都要不断的判断校验小红自身的状态是否还属于游戏规则之内:

简单的我用一个流程图来说明小红移动过程中的校验流程:

 moveRed(k, b, m, x, y) {
        // 移动循环
        clearTimeout(this.data.rered);
        // 1、判断小红是否碰到左右壁;
        if ((x + m) == this.data.canvasWidth || (x + m) == -10) {
            // 左右反弹
            this.turnLeftRight(k, m);
            return;
        }
        // 2、判断小红是否碰到顶部;
        if ((x + m) * k + b == -10) {
            // if ((x + m) * k + b == -10 || (x + m) * k + b == 490) {
            this.turnUpDown(k, m);
            return;
        }
        // 3、判断小红在底部时
        if ((x + m) * k + b == 480) {
            // 判断小红是否在长条上
            if (this.data.redX >= this.data.sliderX - 10 && this.data.redX <= (this.data.sliderX + this.data.sliderWidth)) {
                // 3.1判断小红在长条上,要改变k和m的值;
                console.log("在长条上")
                this.changgeKM();
                console.log(this.data.redK, this.data.redM)
                return;
            } else {
                clearTimeout(this.data.rered);
                console.log("不在长条上")
                // 3.2、判断小红不在长条上;落地计算,游戏结束
                var nowfail = this.data.fail + 1;
                this.setData({
                    fail: nowfail
                })
                // this.turnUpDown(k, m);
                return;
            }
        }
        // // 判断小红大于490时候,结束;
        if ((x + m) * k + b > 480) {
            clearTimeout(this.data.rered)
            return;
        }
        // 4、判断小红是否碰到小白块;
        var i = parseInt((x + m) / 10);
        var j = parseInt(((x + m) * k + b) / 10);
        if (this.data.blocks[i][j][2] == 1) {
            // 判断一下头顶有没有小白
            this.data.blocks[i][j][2] = 0;
            // 分值计算
            var nowscore = this.data.score + 1;
            this.setData({
                score: nowscore
            })
            // 重绘小白
            this.drawBlocks();
            // 碰到小白随机反弹
            if (parseInt(Math.random() * 2) == 1) {
                this.turnLeftRight(k, m);
                return;
            } else {
                this.turnUpDown(k, m);
                return;
            }
        } else {
            //5、 绘制下一个小红;
            this.painNextRed(k, b, m, x, y);
        }

    },

3、左右反弹的函数:

如图可知,当小红碰壁时,会将会左右反弹;

若原来第一条直线的函数为:y=kx+b1;

那么反弹以后的第二条直线函数便设为:y=-kx+b2;

二者直线的斜率互为相反数;这样每次判断以后就需要再次重新计算小红的运动轨迹函数;

例如图一,原来每次是在x轴上每次移动m;后来反弹以后每次移动为-m,此时斜率为-k;

    turnLeftRight(k, m) {
        this.setData({
            redK: -k,
            redM: -m
        })
        // console.log("左右换方向!", this.data.redK, this.data.redM)
        // 反弹,获取反弹的直线函数,继续移动
        this.getLine(this.data.redK, this.data.redM)
    },

4、上反弹的函数

同理可得,当小红碰到顶壁的方法为

例如图一,原来每次是在x轴上每次移动m;后来反弹以后每次移动为m,但是此时斜率为-k;

  turnUpDown(k, m) {
        this.setData({
            redK: -k,
            redM: m
        })
        // console.log("下换方向!", this.data.redK, this.data.redM)
        // 反弹,获取反弹的直线函数,继续移动
        this.getLine(this.data.redK, this.data.redM)
    },

5、下反弹时的判断

下反弹时,就需要考虑,小红落地时,是否在小长的范围内;

  // 当小红到达底部490时:判断小红有没有被接住
            if ((x + m) * k + b == 480) {
                // 判断小红的X是否在小长长度之内
                // console.log("小红现在的位置是:",this.data.redX,"小长现在的位置是",this.data.sliderX)
                if (this.data.redX >= this.data.sliderX && this.data.redX <= (this.data.sliderX + this.data.sliderWidth)) {
                    this.turnUpDown(k, m);
                    return;
                }
                // 落地计算
                var nowfail = this.data.fail + 1;
                this.setData({
                    fail: nowfail
                })
                clearInterval(this.data.rered)
                return;
            }

6、根据小红落在小长的位置,进行不同角度的反弹

    changgeKM() {
        if (this.data.sliderX - 10 <= this.data.redX && this.data.redX <= this.data.sliderX + 20) {
            this.data.redK = 0.5;
            this.data.redM = -1;
            this.getLine(this.data.redK, this.data.redM)
            return;
        }
        if (this.data.sliderX + 20 <= this.data.redX && this.data.redX <= this.data.sliderX + 40) {
            this.data.redK = 1;
            this.data.redM = -1;
            this.getLine(this.data.redK, this.data.redM)
            return;
        }
        if (this.data.sliderX + 40 <= this.data.redX && this.data.redX <= this.data.sliderX + 50) {
            this.data.redK = 2;
            this.data.redM = -1;
            this.getLine(this.data.redK, this.data.redM)
            return;
        }
        if (this.data.sliderX + 50 <= this.data.redX && this.data.redX <= this.data.sliderX + 60) {
            this.data.redK = -2;
            this.data.redM = 1;
            this.getLine(this.data.redK, this.data.redM)
            return;
        }
        if (this.data.sliderX + 60 <= this.data.redX && this.data.redX <= this.data.sliderX + 80) {
            this.data.redK = -1;
            this.data.redM = 1;
            this.getLine(this.data.redK, this.data.redM)
            return;
        }
        if (this.data.sliderX + 80 <= this.data.redX && this.data.redX <= this.data.sliderX + 110) {
            this.data.redK = -0.5;
            this.data.redM = 1;
            this.getLine(this.data.redK, this.data.redM)
            return;
        }
        this.getLine(this.data.redK, this.data.redM)
        return;
    },

7、判断小红遇到小白的情况;

原来我考虑了。小红遇到小白出现的9种情况;其实不用这么麻烦;

(如图显示的是,小红遇到小白的9种消除的情况)

只要下一个小红的头顶上有一个小白,那么就将头顶上的小白给消除;

若头顶出现小白,则下一步小红随机左右,向下反弹;

 // 判断小红四周的情况
            if (this.data.blocks[i][j][2] == 1) {
                // 判断一下侧面有没有小白,有的话就左右反弹
                this.data.blocks[i][j][2] = 0;
                // 分值计算
                var nowscore = this.data.score + 1;
                this.setData({
                    score: nowscore
                })
                // 重绘小白
                this.drawBlocks();
                if (parseInt(Math.random() * 2) == 1) {
                    this.turnLeftRight(k, m);
                    return;
                }
                this.turnUpDown(k, m);
                return;
            }

基本上这个游戏的雏形就完成了。

 

接下去还有很多需要优化的工作,后面会继续更新;

感谢阅读~

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值