像《连连看》这样的经典游戏一定是90后的孩子玩的。无论是在电脑上还是在手机上,规则都很简单,只需连接相同的方块并消除即可。不需要超过三个连接线。小编最近撰文介绍了这款经典游戏,并首次展示了游戏界面:
分析:如何连接
连连看游戏的核心是如何判断两个方块是否相连。这其实就是一般游戏中的寻路算法之一。如何找到从一点到另一点的最短路径。不过寻路算法的实现过程比较复杂,因此本文不会深入探讨。这里会用另一种思维方式来寻找路径。
边肖编了一个java学习资料,私信回复[01]获取源代码。
在连连看中,只能排除以下三种情况。
直线连接。
一个角落。
两个角。
前两种情况比较简单,但第三种情况可能在游戏中有多重联系。
看起来很复杂。其实你只需要计算出地图上X轴和Y轴上可以直接相连的两个方块的坐标,每个方块就可以得到两个数组(X轴和Y轴上可以直接相连的点),然后在两个方块的X轴和Y轴数组上做一个比较运算就可以得到角点位置。
以上简单分析了connection的基本实现思路,接下来开始编写代码。
程序
生成地图
点击事件
获取电缆
画一条连接线
生成地图
当然,首先要做的就是随机生成一张地图。
game.vue
从".' 导入单元格/细胞'
来自“导入实用程序./utils”
'从'./config'导入配置
来自“导入主题”./主题
导出默认值{
成分:{
细胞
},
数据() {
返回{
CellData[], //地图数据数组
CurrentSelectnull, //当前选中的框。
ConfigObject.assign(config) //配置信息
}
},
计算:{
当前主题(){
//当前主题
返回主题。过滤器(e=e.name===this.config.默认主题)[0]
}
},
已安装(){
this.init()
},
方法:{
//.
}
}
cell.vue
这里,div empty :before 和:after 伪类用于显示连接器。
导出默认值{
名称:'细胞',
道具:['isSelected','isBlank','className','lineClass','isLine'],
计算:{
班级名称(){
返回{
'已选择'this.isSelected, //已选择。
'空白'this.isblank,/空白色
[this.className]:是
}
}
}
}
为了更好的扩展链接盒的内容,我们使用数组来保存不同色块的类名,然后将对应的类名放在色块上,并通过CSS控制色块的背景图片。
在里面(){
console.time('initData')
this.cellData=this.initData()
console.timeEnd('initData')
},
初始化数据(){
//classNames=['a', 'b', 'c', 'd'] 每个元素代表一个盒子的类名。
//生成一个方阵,并将类名放入其中。莱特塞尔集团=
这。当前主题。类名.map (e={
返回{
IsBlank:false, //当为空白框时。
ClassName:e, //盒子的类名。
LineClass:' ', //连接线的类名。
IsLine:false, //是否应该显示连接线?
已选择:假
}
})
/空白框
让空白单元格{
是空白:是的,
班级名称: ””,
行类:“”,
是线:假,
已选择:假
}
//首先根据配置的块数随机取出几个块LetRandomCellGroup=utils. ArrayRandom(单元格组,
这。配置。 CellGroupCount) 取自方阵。
//然后随机填充一个地图数据let cell data=
实用程序。 ArrayfilbyRandomGroup(this . config . row * this . config . col, RandomCell Group) 根据配置中的行和列。
//将数据按照行的大小转换成二维数组,然后在外面包裹一层空的白色节点。
/*
* 实用程序.dyadicArrayWrap
* 通过填充包装二进制数组
* @params arr 源arr
* @params 填充要包装的源数组
*
* 0 0 0 0 0
* 1 1 1 0 1 1 1 0
* 1 1 1=0 1 1 1 0
* 1 1 1 0 1 1 1 0
* 0 0 0 0 0 */让结果=utils . dyadicarraywrap(utils . arraytodyadic(单元格数据, this.config.col), BlankCell)
//最后给节点设置行列坐标。
结果.forEach((列,行)={
cols.forEach((单元格,列)={
单元格.行=行
单元格.列=列
})
})
返回结果
}
最后,我们得到了地图数据的二维数组。
选择活动
下一步是选择框事件。
为了提高性能,点击事件没有直接绑定到盒子上,而是绑定到外表上,由事件代理实现。我还想在这里抱怨一下,Vue 目前没有事件代理。为了提高绑定的性能,我们需要自己实现一个事件代理。
//点击事件代理。
手柄点击(电动){
//如果盒子上没有触发点击事件,则退出if(ev.target.nodeName!=='TD ') 并返回
//获取点击框的坐标。如果该框为空,则退出letcol=ev.target.cellIndex
让行=ev 。目标。父节点。行索引
让当前单元格=this .单元格数据[行[列]
if(currentCell.isBlank===true) 返回
this.selectCell(当前Cell)
},
//选择框
选择单元格(currCell){
if(!this.currentSelect){
//如果没有选中框,直接设置选中的currCell.isSelected=true。
this.currentSelect=currCellre
转动
}
if(this .当前选择===当前单元格){
//如果点击的框与选中的框相同,则取消该框的选中状态。 currCell.isSelected=false。
this.currentSelect=null
返回
}
letprevCell=this.currentSelect
//利用className判断前后两个块的图片是否相同if(prevCell.className!==currCell.className){
//如果两个块的类名不同,则将点击的块设置为选中状态prevCell.isSelected=false。
currCell.isSelected=true
this.currentSelect=currCell
返回
}
//获取两个块的连接路径数组console.time('getLine ').
让结果=这个。 getline(上一个单元格, currCell)
console.timeEnd('getLine')
if(结果.length===0){
//如果没有获取到连接线,则说明两个块无法连接,则将点击的块设置为选中状态prevCell.isSelected=false。
currCell.isSelected=true
this.currentSelect=currCell
}否则{
//如果获取到连接线,则将两个方块设置为空白prevCell.isBlank=true。
currCell.isBlank=true
prevCell.className=' '
currCell.className=' '
prevCell.isSelected=false
currCell.isSelected=false
this.currentSelect=null
//最后画出连接线。
this.drawLine(结果)
}
}
选择的逻辑判断就到这里了,接下来就是本文的核心,如何获取连接路径。
获取电缆
这篇内容有点长,我分几部分来写。
首先介绍一下下面多次提到的可连线。。
搜索可连接线时,红色方块是要搜索的方块,黑色是另一个方块,白色是空的白色方块。这样就可以从红色方块开始向前和向后遍历,得到一个可访问的方块集合对象,如图中全是白色方块。
getLine
找到连接线的入口
getLine(上一条, 当前){
//连接器数组
让结果=[]
//用直线连接。
//
分别获取最后选中框在X轴和Y轴上的可连接线。 Gethorizontaline 和getVerticalLine 都返回一个Set 对象。使用必须快速有效地确定某个框是否letpreview=this。 gethorizontaline (prev) 包含在可连接线路中。
letprevH=this .gethorizontalline(prev)
if(prev .has(curr)) 返回this.getBeeline(prev, curr)
让prevv=this .getverticalline(prev)
if(prev .has(curr)) 返回this.getBeeline(prev, curr)
//如果直线连接失败,则获取另一个方格的可连接线。
让currh=this .gethorizontalline(curr)
让currv=this .getverticalline(curr)
//快速判断。如果X轴和Y轴上的正方形的可连接长度为0,则返回空数组。
If ((!prevH.size!prev .size)" |(!currH.size!currV.size)) 返回结果
//可以连接一个角。
//分别判断X轴和Y轴上可连接线的交点。
etintersection=this . getintersection(prevH, currV) | 获取交集(prevH, currV) | |这。 getintersection(prevV, currV)