Jigsaw puzzle made by javascript (html5 canvas), easy to understand

Taking advantage of the time of fishing, I wrote a jigsaw puzzle game, which is easy to operate and refreshing.

Effect picture (the final finish seems to be covered, haha)

Realization ideas

  1. Use the drawImage method of canvas, use 8 parameters to cut the big picture into small pictures, and store each small picture in the corresponding array.
  2. When cutting the image, use two array keys and orig_keys to access the subscript of the small image. If there are 9 small images (keys, input the array of numbers 0-8).
  3. When the start button is clicked, the keys are sorted randomly, and then the corresponding image object is obtained from the small image array, and its display position is updated, so that the image can be disrupted.
  4. Choose a small picture (click this picture again to cancel the current selection status), and then choose another picture will exchange positions.
  5. After each exchange of positions, the array keys and orig_keys are compared. If the two arrays have the same structure, it means that the puzzle is complete.

drawImage use

Can read this article

 

Write ImageDraw constructor

//图片对象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;
	}
	

Slice the picture

  1. Divide the length of the big picture by the number of columns and divide the width of the big picture by the number of rows to get the length and width of the small picture respectively;
  2. Initialize the small picture with a double loop
  3. The keys store the key and posArr array to access dx and dy (used when scrambled)
//对图片进行切片
	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++;
			}
		}
	}

Random order

	this.keys.sort(function(a,b){//随机排序
			return Math.random()>0.5?1:-1;
		})
  1. The keys before scrambled are like this: [0, 1, 2, 3, 4, 5, 6, 7, 8]
  2. After scrambled, the keys look like this: [5, 0, 7, 1, 4, 8, 6, 2, 3]
  3. When looping the small picture object, the subscript starts from 0,1,2, and the key retrieved for the first time is the first element 5 of the keys array.
  4. Use 5 to go to posArr to get the sixth element posArr[5], and set the dx and dy of this element to the small picture with the current subscript of 0. The other principles are the same, which disrupts the picture.
		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; 
			}
		});

Let's see the effect

Add a click event to the canvas and add a judgment to each small picture. If the current small picture is clicked, a frame is added to indicate the selection

Rect constructor

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;
	}

Post-click code

//表示第一次选中
						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);

Effect at this time

Swap positions after selecting another picture

  1. Clear the selection status and indication box
  2. Exchange the pos and key values ​​of two small picture objects
  3. Swap their values ​​in the keys array
  4. Determine whether the keys and orig_keys are consistent at this time, if they are consistent, it means completion
						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)
						}

Finally, add the code for picture replacement and difficulty coefficient to complete

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';
	}

 

Download all codes, no points required

Brothers, give it to three companies, thank you for pulling! !

Guess you like

Origin blog.csdn.net/dkm123456/article/details/114695468