连连看游戏的规则总结如下:
● 两个选中的方块是相同的。
● 两个选中的方块之间连接线的折点不超过两个。(连接线由x轴和y轴的平行线组成)。
本篇开发连连看游戏,游戏效果如图1所示。
■ 图1 连连看运行界面
本游戏增加智能查找功能,当玩家自己无法找到时,可以右键单击画面,则会出现提示可以消去的两个方块(被加上红色边框线)。
01、程序设计的步骤
1. 设计点类Point
点类Point比较简单,主要存储方块所在棋盘坐标(x,y)。
//定义坐标点类 function Point(_x, _y) { this.x = _x; this.y = _y; }
2. 设计游戏主逻辑
整个游戏在Canvas对象中进行,在页面加载时调用create_map( )实现将图标图案随机放到地图中,地图map中记录的是图案的数字编号。最后调用print_map()按地图map中记录图案信息将图2中图标图案绘制在Canvas对象中,生成游戏开始的界面。同时绑定Canvas对象触屏开始事件,对玩家触屏操作做出反应。
var map = []; var Select_first = false; //是否已经选中第一块 var linePointStack = []; //存储连接的折点棋盘坐标 var Height = 12; var Width = 10; var p1, p2; //存储选中第一块,第二块方块对象坐标 /** * 生命周期函数--监听页面加载 */ onLoad: function(options) { //创建画布上下文 this.init(); //初始化地图, 将地图中所有方块区域位置置为空方块状态 this.create_map() ; //生成随机地图 this.print_map(); //输出map地图 this.ctx = wx.createCanvasContext('myCanvas') this.ctx.draw(); }, init: function() { //初始化地图, 将地图中所有方块区域位置置为空方块状态 for (var x = 0; x < Width; x++) { map[x] = new Array(); for (var y = 0; y < Height; y++) { map[x][y] = " "; //" "表示空的 } } },
3. 编写函数代码
print_map( )按地图map中记录图案信息将图2中图标图案显示在Canvas对象中,生成游戏开始的界面。
** *按地图map中记录图案信息将图标图案显示在Canvas对象中,生成游戏开始的界面。 */ print_map: function() { //输出map地图 let ctx = this.ctx for (var x = 0; x < Width; x++) for (var y = 0; y < Height; y++) if (map[x][y] != ' ') { var img1 = '/images/' + map[x][y] + ".jpg"; //ctx.drawImage('/images/4.jpg', 50 * i, 50, 50, 50) ctx.drawImage(img1, 25 * x, 25 * y, 25, 25); } },
用户在窗口中上单击时,由屏幕像素坐标(e.touches[0].x, e.touches[0].y)计算被单击方块的地图棋盘位置坐标(x,y)。判断是否是第一次选中方块,是则仅仅对选定方块加上红色示意框线。如果是第二次选中方块,则加上黑色示意框线,同时要判断是否图案相同且连通。假如连通则画选中方块之间连接线。
Canvas对象触屏事件则调用智能查找功能find2Block()。
Canvas对象触屏开始事件代码。
touchStart: function(e) { var x = Math.floor(e.touches[0].x / 25); var y = Math.floor(e.touches[0].y / 25); let ctx = this.ctx; var pair=false; //是否配对成功 this.print_map(); //输出map地图 console.log("clicked at" + x + "," + y); if (map[x][y] == " ") console.log("提示此处无方块"); else { if (Select_first == false) { p1 = new Point(x, y); //画选定(x1,y1)处的框线 ctx.setStrokeStyle("red"); ctx.strokeRect(x * 25, y * 25, 25, 25); Select_first = true; } else { p2 = new Point(x, y); //判断第二次单击的方块是否已被第一次单击选取,如果是则返回。 if ((p1.x == p2.x) && (p1.y == p2.y)) return; //画选定(x2,y2)处的框线 console.log('第二次单击的方块' + x + ', ' + y) ctx.strokeRect(x * 25, y * 25, 25, 25); if (this.IsSame(p1, p2) && this.IsLink(p1, p2)) { //判断是否连通 console.log('连通' + x + ', ' + y); Select_first = false; //画选中方块之间连接线 this.drawLinkLine(p1, p2); map[p1.x][p1.y] = ' '; //清空记录地图中第1个方块 map[p2.x][p2.y] = ' '; //清空记录地图中第2个方块 pair=true; //配对成功,定时0.5秒后刷新屏幕 linePointStack=[]; if(this.isWin()) { //游戏结束 console.log("游戏结束,你通关了!!"); } } else { //不能连通则取消选定的2个方块 Select_first = false; } } } ctx.draw(); if (pair) { //配对成功 this.print_map(); //重新输出map地图 //定时0.5秒后刷新屏幕 setTimeout(function () { ctx.draw(); }, 500); //过半秒 } },
IsSame(p1,p2)判断p1 ( x1, y1)与p2(x2, y2)处的方块图案是否相同。
IsSame: function(p1, p2) { if (map[p1.x][p1.y] == map[p2.x][p2.y]) { console.log("clicked at IsSame"); return true; } return false; },
以下是画方块之间连接线的方法。
drawLinkLine(p1,p2)绘制(p1,p2)所在2个方块之间的连接线。判断linePointStack数组长度,如果为0,则是直接连通。linePointStack数组长度为1,则是一折连通,linePointStack存储是一折连通的折点。linePointStack数组长度为2,则是2折连通,linePointStack存储是2折连通的两个折点。
drawLinkLine: function(p1, p2) { //画连接线 console.log("折点数" + linePointStack.length); if (linePointStack.length == 0) //直线联通 this.drawLine(p1, p2); if (linePointStack.length == 1) { //一折连通 var z = linePointStack.pop(); console.log("一折连通点z" + z.x + z.y); this.drawLine(p1, z); this.drawLine(p2, z); } if (linePointStack.length == 2) { //2折连通 var z1 = linePointStack.pop() //print("2折连通点z1",z1.x,z1.y) this.drawLine(p2, z1) var z2 = linePointStack.pop() //print("2折连通点z2",z2.x,z2.y) this.drawLine(z1, z2); this.drawLine(p1, z2); } },
drawLinkLine(p1,p2)绘制(p1,p2)之间的直线。
drawLine: function(p1, p2) { //绘制(p1, p2)之间的直线 let ctx = this.ctx; ctx.beginPath(); ctx.moveTo(p1.x * 25 + 12, p1.y * 25 + 12); ctx.lineTo(p2.x * 25 + 12, p2.y * 25 + 12); ctx.stroke(); },
IsWin()检测是否尚有非未被消除的方块,即地图map中元素值非空(" "),如果没有则已经赢得了游戏。
/** *#检测是否已经赢得了游戏 */ isWin: function() { //检测是否尚有非未被消除的方块 //(非BLANK_STATE状态) for (var y = 0; y < Height; y++) for (var x = 0; x < Width; x++) if (map[x][y] != " ") return false; return true; }
至此完成连连看游戏。