
“连连看”是源自台湾的桌面小游戏,自从流入大陆以来风靡一时,也吸引众多程序员开发出多种版本的“连连看”。“连连看”考验的是各位的眼力,在有限的时间内,只要把所有能连接的相同图案,两个一对地找出来,每找出一对,它们就会自动消失,只要把所有的图案全部消完即可获得胜利。所谓能够连接,指得是:无论横向或者纵向,从一个图案到另一个图案之间的连线不能超过两个弯,其中,连线不能从尚未消去的图案上经过。
连连看游戏的规则总结如下:
● 两个选中的方块是相同的。
● 两个选中的方块之间连接线的折点不超过两个。(连接线由x轴和y轴的平行线组成)。
本篇开发连连看游戏,游戏效果如图1所示。

■ 图1 连连看运行界面
本游戏增加智能查找功能,当玩家自己无法找到时,可以右键单击画面,则会出现提示可以消去的两个方块(被加上红色边框线)。
点类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] = " "; //" "表示空的
}
}
},
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;
}
至此完成连连看游戏。
最后想问问大家,这两天超级火的“羊了各羊”大家第二关过了吗?
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm
我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI
这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub
我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain
无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
前言一般来说,前端根据后台返回code码展示对应内容只需要在前台判断code值展示对应的内容即可,但要是匹配的code码比较多或者多个页面用到时,为了便于后期维护,后台就会使用字典表让前端匹配,下面我将在微信小程序中通过wxs的方法实现这个操作。为什么要使用wxs?{{method(a,b)}}可以看到,上述代码是一个调用方法传值的操作,在vue中很常见,多用于数据之间的转换,但由于微信小程序诸多限制的原因,你并不能优雅的这样操作,可能有人会说,为什么不用if判断实现呢?但是if判断的局限性在于如果存在数据量过大时,大量重复性操作和if判断会让你的代码显得异常冗余。wxswxs相当于是一个独立
项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU
@作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors 1、什么是behaviors 2、behaviors的工作方式 3、创建behavior 4、导入并使用behavior 5、behavior中所有可用的节点 6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors 1、什么是behaviorsbehaviors是小程序中,用于实现