前言
最近看到一篇博客,实现了拼图游戏并分享了源码。我感觉很好玩,就拿来改了改,实现了一个自己的版本。核心逻辑没有变,主要是优化了样式和交互,增加了些游戏的趣味性。
原文代码实现是用原生 js 面向对象的方式写的,这让习惯了使用 vue 语法糖的我,再次感到了用原生 js 好麻烦。好在,最近也是在重温原生js,打算再把基础学扎实一点,所以我遵循了原作者,也先用原生 js 做优化,后面还是打算改写为 vue 版本,是为了可以打包为移动端的 App,这样就可以在手机上玩了,哈哈。想拼什么图,就拼什么图,完美。
参考博文
https://blog.csdn.net/dkm123456/article/details/111991734#comments_15924279
拼图逻辑分析
1、一张图分割成几块,怎么分割?
定义构造函数,初始化数据。
function Jigsaw(row,boxWidth){
this.row=row;
this.itemWidth= boxWidth/this.row;
this.fragment=[];//拼图碎片的dom数组
this.originalKeys=[];//拼图碎片的下标,记录最初的正确顺序,方便后面对照拼图是否正确完成。
this.keys=[];//拼图碎片的下标,游戏开始时会被打乱顺序。
this.len=this.row*this.row;
this.init();
}
拼图的尺寸是固定的,难度系数,确定了一张图分割为横纵的多少块,这样每块的宽高也就可以计算了。
分割使用背景图 background 属性,定位呈现整张图的固定部分区域。
background-position 属性设置背景图像的起始位置。
以 900px 的拼图大小分割为 3*3 的拼图碎片为例
(x , y)
x 随着每次换行 归零
y 随着每次换行 自增
游戏初始化
//初始化
init:function(){
var fragment=dom.createDocumentFragment();
var url = imgView.src;
for(var i=0;i<this.len;i++){
var div=dom.createElement('div');
div.style.cssText=`
background:url(${url}) no-repeat -${(i%this.row)*this.itemWidth}px -${Math.floor(i/this.row)*this.itemWidth}px;
height:${this.itemWidth}px;
width:${this.itemWidth}px;
`;
this.fragment.push(div);//每个拼图碎片,都对应唯一的keys[i] 和 originalKeys[i]
this.keys.push(i);
this.originalKeys.push(i);
fragment.appendChild(div);
}
box.innerHTML="";
box.appendChild(fragment);
},
完整的拼图就是多个应用了背景图属性的 div 组合而成的。
2、随机位置实现
随机位置实现,首先要打乱拼图碎片的下标数组。
arrayObject.sort(sortby)
排序函数的巧妙使用,用来打乱拼图碎片的下标数组。
sort 一般用于给乱序的数组排序,这里反其道用之,给正序的数组打乱顺序。参数 a b是数组中的元素。新的排序 依据 排序函数的返回值 来决定 a 和 b 在数组中的前后位置。
this.keys.sort(function(a,b){
console.log('a = '+a+' , b = '+b)
//return a-b
//return Math.random()>0.5?1:-1;
})
乱序
this.keys.sort(function(a,b){
console.log("a = "+a+' , b = '+b)
return Math.random()>0.5?1:-1;
})
经测试,这里 sort()不传参数 a,b 也是可以的,应该是sort()方法在源码实现时,做了默认参数处理。
根据拼图碎片的随机下标,获取拼图碎片的随机 dom ,然后依次给拼图碎片应用绝对定位。
以 900px 的拼图大小分割为 3*3 的拼图碎片为例(原理同上使用背景图定位,所以后面代码实现也可以同上优化)
(x , y)
x 随着每次换行 归零
y 随着每次换行 自增
最外层相对定位,拼图碎片绝对定位。
this.item 是存储的拼图碎片 element 数组
也是在此时,给每个拼图碎片绑定鼠标事件。
start:function(){
//随机位置
this.keys.sort(function(a,b){
return Math.random()>0.5?1:-1;
})
var keys = this.keys;//随机打乱的拼图碎片下标
var colNum=0;
var rowNum=0;
box.innerHTML="";
for(var i=0;i<keys.length;i++){
if(i>0){
if(i%this.row===0){
rowNum++;
colNum=0;
}
}
var item = this.fragment[keys[i]];
item.style.position='absolute';
item.style.left=`${colNum++*this.itemWidth}px`;
item.style.top=`${rowNum*this.itemWidth}px`;
item.pos=i;//pos:item数组元素在 keys 数组中对应的下标 index
item.key=keys[i];//key::item数组元素在 keys 数组中对应的值
th