微信小程序——用canvas做个层叠消融游戏(一)

本篇为小程序的一学习笔记,以一小游戏‘层叠消融’为例子,对canvas组件进行展开学习。

开场白就没了,直奔主题。先来看看小程序在组件使用上,对canvas做了什么。

em……,首先,指定了作为唯一标识符的属性canvas-id,因为小程序搭了一套MV*框架,所以对于元素绑定这个,和用原生的js的方式不同。然后就是一系列的手势触发事件。其他的,其实在使用上也没做什么特别的处理嘛。既然如此,那就直接贴上对canvas进行元素绑定的代码吧。

<!-- canvas.wxml -->

<canvas canvas-id="testCanvas"></canvas>

<!-- canvas.js -->

Page({

    onReady: function(e) {

        // 使用wx.createContext获取绘图上下文 context

        var context = wx.createCanvasContext('testCanvas');

        context.setStrokeStyle('#00ff00');

        context.rect(0,0,200,200);

        context.draw();

    }

})


因为小程序的canvas元素默认宽高是不会覆盖全屏的,所以在初始化canvas之后要进行重新设置宽高。屏幕的宽高可以通过API:wx.getSystemInfo获得。


接下来就是画图了。‘层叠消融’这个游戏的主要效果就是图片叠加部分双数相消。具体效果如图:


上面的图形由三个基本图形(正方形)组成,用这三个基本图形拼出上面的目标图案,则算通关。

需求:多图形相叠双数相消。要实现这个效果,用传统的css是很麻烦的,这时canvas的灵活性就体现出来了。canvas对图片图形的处理是像素级的,其本身提供了一系列的图形遮盖策略。globalCompositeOperation这个属性设定了在画新图形时采用的遮盖策略,其值是一个标识12种遮盖方式的字符串。其中‘xor’方式正能实现我们双数相消的需求。

立即贴上主要的代码:

//绘制一个反相图案

let revert = function(path){

    this.context.beginPath();

    this.context.fillStyle="#000";

    this.context.globalCompositeOperation="xor";

    for(let i=0;i<path.length;i++){

        if(i==0){

            this.context.moveTo(path[i].x,path[i].y);

        }else{

            this.context.lineTo(path[i].x,path[i].y);

        }

    }

    this.context.fill();

    return this;

}


(小程序的onReady函数,这里具体的调用我打包了一下,具体打包细节我就不再这里细讲了)

onReady: function(){

    let canvasCtl = new this.canvasCtl();

    canvasCtl.init(this);

    let block1 = new util.block([{x:200,y:50},{x:100,y:150},{x:100,y:50}],canvasCtl);

    block1.initBlock();

    let block2 = new util.block([{x:150,y:70},{x:250,y:70},{x:250,y:200}],canvasCtl);

    block2.initBlock();

    let block3 = new util.block([{x:50,y:60},{x:110,y:60},{x:110,y:110},{x:50,y:110}],canvasCtl);

    block3.initBlock();

    this.blockList.push(block1);

    this.blockList.push(block2);

    this.blockList.push(block3);

},

效果图如下:


既然是小游戏,那就要会动是不是。需求:手指点上时,选中图片跟着移动。

这时,就要用上小程序给我们提供的手势触发了,用到的有这两个:


bindtouchstart用于判断手指选中那个图形,bindtouchmove用于图形移动。

对于判定选中图形这个问题,赶紧回忆起你的小学数学:沿着判定点向图形方向画一条射线,若相交点为单数,则判定点在图形中,否则,判定点在图形外。转换为代码模式如下:

block.prototype.checkPointInRegion = function(pt){

    let nCross = 0; // 定义变量,统计目标点向右画射线与多边形相交次数

    for (let i = 0; i < this.path.length; i++) { //遍历多边形每一个节点

        let p1 = this.path[i];

        let p2 = this.path[(i+1)%this.path.length];

        // p1是这个节点,p2是下一个节点,两点连线是多边形的一条边

        // 以下算法是用是先以y轴坐标来判断的

        if ( p1.y == p2.y )continue;//如果这条边是水平的,跳过

        if ( pt.y < ((p1.y= ((p1.y>p2.y)?p1.y:p2.y))continue;//如果目标点高于这个线段,跳过

        //那么下面的情况就是:如果过p1画水平线,过p2画水平线,目标点在这两条线中间

        let x = (pt.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;

        // 这段的几何意义是 过目标点,画一条水平线,x是这条线与多边形当前边的交点x坐标

        if ( x > pt.x ) nCross++; //如果交点在右边,统计加一。这等于从目标点向右发一条射线(ray),与多边形各边的相交(crossing)次数

    }

    if (nCross % 2 == 1) {

        return true; //如果是奇数,说明在多边形里

    } else {

        return false; //否则在多边形外 或 边上

    }

}

下面就是移动了,canvas的图形的移动很粗暴,那就是擦掉旧的重新画上新的。需要记录下多次bindtouchmove触发时手指的位移->计算出图形移动后的新定点坐标->在画布上擦掉旧图形->根据新坐标画上新图形。下面贴上主要代码:

searchBlock:function(e){ 

    if(this.movePath.length>10){ 

         this.movePath.shift(); 

     }

     this.movePath.push(e);

    for(let i = 0; i < this.blockList.length; i++){//让新选中的图形永远处于第一位

      if(this.blockList[i].checkPointInRegion({ x: e.touches[0].x , y:e.touches[0].y })){

        [this.blockList[0],this.blockList[i]] = [this.blockList[i],this.blockList[0]]

      };

    }

  }, 

 moveBlock:function(e){

    if(this.movePath.length>10){

      this.movePath.shift();

    }

    this.movePath.push(e);

    let oldPath = this.movePath[this.movePath.length-2]?this.movePath[this.movePath.length-2]:null;

    let newPath = e;

    this.blockList[0].move(oldPath.touches[0],newPath.touches[0]);

  },

block.prototype.move = function(oldPath,newPath){

    if(oldPath){

      var x = newPath.x - oldPath.x;

      var y = newPath.y - oldPath.y;

      this.changeLocation(x,y);

    }

}


效果图如下:


接下去就是通关判定、关卡设置、关卡选择……有点多,这些内容就留到下期吧。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355