Aprovechando el tiempo de pesca, escribí un juego de rompecabezas, que es fácil de operar y refrescante.
Imagen de efecto (el acabado final parece estar cubierto, jaja)
Ideas de realización
- Utilice el método de lienzo drawImage, utilice 8 parámetros para cortar la imagen grande en imágenes pequeñas y almacene cada imagen pequeña en la matriz correspondiente.
- Al cortar la imagen, use dos claves de matriz y orig_keys para acceder al subíndice de la imagen pequeña. Si hay 9 imágenes pequeñas (claves, ingrese la matriz de números 0-8).
- Cuando se hace clic en el botón de inicio, las claves se ordenan aleatoriamente, y luego se obtiene el objeto de imagen correspondiente de la pequeña matriz de imágenes y se actualiza su posición de visualización, de modo que la imagen se puede interrumpir.
- Elija una imagen pequeña (haga clic en esta imagen nuevamente para cancelar el estado de selección actual), y luego elija otra imagen para intercambiar posiciones.
- Después de cada intercambio de posiciones, se comparan las claves de matriz y orig_keys. Si las dos matrices tienen la misma estructura, significa que el rompecabezas está completo.
uso de drawImage
Escribir constructor ImageDraw
//图片对象ImageDraw构造函数
function ImageDraw(o,obj){
this.id='',
this.image=0,//图片对象(必填)
this.sx=0,//图片切片开始x位置(显示整个图片的时候不需要填)
this.sy=0,//图片切片开始y位置(显示整个图片的时候不需要填)
this.sWidth=0, //图片切片开始宽度(显示整个图片的时候不需要填)
this.sHeight=0,//图片切片开始高度(显示整个图片的时候不需要填)
this.dx=0, //图片目标x位置(必填)
this.dy=0, //图片目标y位置(必填)
this.dWidth=0,//图片目标显示宽度(宽度不缩放时不必填)
this.dHeight=0//图片目标高度高度(高度不缩放时不必填)
this.init(o,obj);
}
ImageDraw.prototype.init=function(o,obj){
this.lol=obj;
for(var key in o){
this[key]=o[key];
}
return this;
}
ImageDraw.prototype.render=function(context){
draw(context,this);
function draw(context,obj) {
var ctx=context;
ctx.save();
if(!obj.image || getType(obj.dx)=='undefined' || getType(obj.dy)=='undefined'){
throw new Error("绘制图片缺失参数");
return;
}
ctx.translate(obj.dx,obj.dy);
if(getType(obj.sx)!='undefined' && getType(obj.sy)!='undefined' && obj.sWidth && obj.sHeight && obj.dWidth && obj.dHeight){
//裁剪图片,显示时候有缩放
ctx.drawImage(obj.image, obj.sx, obj.sy, obj.sWidth, obj.sHeight, 0, 0, obj.dWidth, obj.dHeight);
}else if(obj.dWidth && obj.dHeight){
ctx.drawImage(obj.image, 0, 0, obj.dWidth, obj.dHeight);//原始图片,显示时候有缩放
}else{
ctx.drawImage(obj.image,0, 0);//原始图片,显示时候无缩放
}
ctx.restore();
}
}
ImageDraw.prototype.isPoint=function(pos){
//鼠标位置的x、y要分别大于dx、dy 且x、y要分别小于 dx+dWidth、dy+dHeight
if(pos.x>this.dx && pos.y>this.dy && pos.x<this.dx+this.dWidth && pos.y<this.dy+this.dHeight ){//表示处于当前图片对象范围内
return true;
}
return false;
}
Corta la imagen
- Divida la longitud de la imagen grande por el número de columnas y divida el ancho de la imagen grande por el número de filas para obtener la longitud y el ancho de la imagen pequeña respectivamente;
- Inicialice la imagen pequeña con un bucle doble
- Las claves almacenan la clave y la matriz posArr para acceder a dx y dy (se usa cuando se codifica)
//对图片进行切片
Jigsaw.prototype.sliceImage=function(){
var imgObj = this.imgObj;
var img,image,key=this.imageIndex,renderArr=this.renderArr;
var countX=this.countX,countY=this.countY;
image=imgObj[key];
var disX = this.w/countX,//小图片的宽
disY = this.h/countY;//小图片的高
//相关数组清空处理
renderArr.length=0;
this.orig_keys.length=0;
this.keys.length=0;
this.posArr.length=0;
//初始化小图片对象
var x=y=n=0;
for(var i=0;i<countX;i++){
x = i*disX;
for(var j=0;j<countY;j++){
y = j*disY;
img = new ImageDraw({image:image,sx:x,sy:y,sWidth:disX,sHeight:disY, dx:x, dy:y ,dWidth:disX,dHeight:disY},this);
renderArr.push(img);
img.key=n;//设置key值
img.keyPos=n;//设置所处于的位置
this.orig_keys.push(n);
this.keys.push(n);
this.posArr.push({x:x,y:y})
n++;
}
}
}
Orden aleatorio
this.keys.sort(function(a,b){//随机排序
return Math.random()>0.5?1:-1;
})
- Las claves antes codificadas son así: [0, 1, 2, 3, 4, 5, 6, 7, 8]
- Después de codificar, las claves se ven así: [5, 0, 7, 1, 4, 8, 6, 2, 3]
- Cuando el objeto de imagen pequeña está en bucle, el subíndice comienza desde 0, 1, 2, y la clave recuperada por primera vez es el primer elemento 5 de la matriz de claves.
- Utilice 5 para ir a posArr y obtener el sexto elemento posArr [5], y establezca dx y dy de este elemento en la imagen pequeña con el subíndice actual de 0. Los otros principios son los mismos, lo que interrumpe la imagen.
var key,pos;
//排序后重新更改位置,达到打乱图片的效果
_.each(this.renderArr,function(item,index){
if(item){
key = that.keys[index];
pos = that.posArr[key];
//改变dx,dy既可
item.dx=pos.x;
item.dy=pos.y;
item.image=that.imgObj[that.imageIndex];
item.key=key;
item.keyPos=index;
}
});
Veamos el efecto
Agregue un evento de clic al lienzo y agregue un juicio a cada imagen pequeña. Si se hace clic en la imagen pequeña actual, se agrega un marco para indicar la selección
Constructor rect
function Rect(o){
this.x=0,//x坐标
this.y=0,//y坐标
this.width=100,//宽
this.height=40,//高
this.thin=true,//线段薄一点
this.init(o);
}
Rect.prototype.init=function(o){
for(var key in o){
this[key]=o[key];
}
}
Rect.prototype.render=function(context){
this.ctx=context;
innerRender(this);
function innerRender(obj){
var ctx=obj.ctx;
ctx.save()
ctx.beginPath();
ctx.translate(obj.x,obj.y);
if(obj.lineWidth){
ctx.lineWidth=obj.lineWidth;
}
if(obj.thin){
ctx.translate(0.5,0.5);
}
ctx.rect(0,0,obj.width,obj.height);
if(obj.fill){//是否填充
obj.fillStyle?(ctx.fillStyle=obj.fillStyle):null;
ctx.fill();
}
if(obj.stroke){//是否描边
obj.strokeStyle?(ctx.strokeStyle=obj.strokeStyle):null;
ctx.stroke();
}
ctx.restore();
}
return this;
}
Código post-clic
//表示第一次选中
item.selected=true;
//添加一个边框用来指示被选择
var rect = new Rect({
x:item.dx,
y:item.dy,
width:item.dWidth,
height:item.dHeight,
stroke:true,
strokeStyle:'skyblue'
})
rect.img=item;
this.renderRectArr.push(rect);
Efecto en este momento
Cambiar posiciones después de seleccionar otra imagen
- Borrar el estado de selección y el cuadro de indicación
- Intercambie los valores pos y clave de dos pequeños objetos de imagen
- Intercambia sus valores en la matriz de claves
- Determine si las claves y orig_keys son consistentes en este momento, si son consistentes, significa finalización
var itemSelected = this.renderRectArr[0].img;
//将已选择的dx、dy拷贝给x、y
var x = itemSelected.dx,y=itemSelected.dy;
//进行位置交换
itemSelected.dx=item.dx,itemSelected.dy=item.dy,
item.dx=x,item.dy=y;
//清空选择状态及指示框
itemSelected.selected=false;
this.renderRectArr.length=0;
//位置的交换
var from_pos = itemSelected.keyPos;
var from_key = itemSelected.key;
var target_pos = item.keyPos;
var target_key = item.key;
itemSelected.pos=target_pos;
itemSelected.key=target_key;
item.pos=from_pos;
item.key=from_key;
//交换他们在this.keys中的位置
this.keys.splice(from_pos,1,target_key);
this.keys.splice(target_pos,1,from_key);
//如果相等表示已经找好了
if(this.diff(this.orig_keys,this.keys)){//每次交换完成以后都要进行一次判断,看是否完成拼图
setTimeout(function(){
alert("恭喜你已完成!");
console.log('完成了');
},0)
}
Finalmente, agregue el código para el reemplazo de la imagen y el coeficiente de dificultad para completar
var box = document.getElementById('box');
var start = document.getElementById('start');
jigsaw.init(box,start);
function up(type){
var el = document.getElementById("difficulty_"+type);
if(el){
var val=el.value;
if(val<10){
val++;
el.value=val;
if(type='col'){
jigsaw.countY=val;
}else{
jigsaw.countX=val;
}
}
}
}
function down(type){
var el = document.getElementById("difficulty_"+type);
if(el){
var val=el.value;
if(val>3){
val--;
el.value=val;
if(type='col'){
jigsaw.countY=val;
}else{
jigsaw.countX=val;
}
}
}
}
var index=1;
var small_img =document.getElementsByClassName("small_img")[0];
document.getElementById("next").onclick=function(){
var src = small_img.src;
var reg = /(\d+)\.jpeg$/;
var arr = reg.exec(src);
if(arr.length>1){
index = ++arr[1];
if(index>16){
index=1;
}
jigsaw.imageIndex=index;
jigsaw.draw();
}
small_img.src='./images/'+index+'.jpeg';
}