javascript 連連看小遊戲(附上參考來源)

  • 3016
  • 0

摘要:javascript 連連看小遊戲(附上參考來源)

為了SV的姐姐,

終於完成這個小遊戲了~

不過中間隔這麼久是因為SV之前過的焦頭爛額,
快要永無止境的加班的緣故。

 

感謝網友臨風小築:
http://www.shirne.com/?cid=30&id=25

然後SV的姐姐喜歡玩無止境的遊戲,於是就製作成這樣了:

http://mail2.tmue.edu.tw/~9716025/Link/
 

想要參考的網友,希望能附上臨風小築當參考資料(而不是SV喔)!

圖片是SV之前畫給巴友們的圖,因此不建議使用><
(畢竟是別人的勇造)

然後如果需要教學,就開始吧(咦)!

自己建設的方法為:
準備檔案空間,新增兩個資料夾:img、source
img裡面放圖片(檔名皆數字+.png,如1.png,從1開始。SV是用16張圖)
接著source資料夾要放五個外部連結檔案(js和css的),
SV一一介紹:

block.js:

 

function block(obj,x,y){
	var _=this;
	_.ele=obj;
	_.x=x;
	_.y=y;
	_.type=shapes.Rnd();
	
	_.ele.style.left=(_.x-1)*size[0]+'px';
	_.ele.style.top=(_.y-1)*size[1]+'px';
	_.setStyle();
	_.ele.onclick=function(){
		if(prev && prev.ele!==_.ele){
			_.link(prev);
		}else{
			_.active();
		}
	}
}
block.prototype.setStyle=function(){
	this.ele.style.background='url('+imgfolder+this.type+'.png) center center no-repeat';
}

block.prototype.move=function(t){
	var op=[this.x,this.y];
	map[(op[1]-1)*level.x+op[0]]=0;
	switch(t){
		case 1:
		if(this.y>1 && !map[(this.y-2)*level.x+this.x]){
			this.y=this.y-1;
			this.ele.style.top=(this.y-1)*size[1]+'px';
		}
		break;
		case 2:
		if(this.y<map.length-1 && !map[this.y*level.x+this.x]){
			this.y=this.y+1;

			this.ele.style.top=(this.y-1)*size[1]+'px';
		}
		break;
		case 3:
		if(this.x>1 && !map[(this.y-1)*level.x+this.x-1]){
			this.x=this.x-1;
			this.ele.style.left=(this.x-1)*size[0]+'px';
		}
		break;
		case 4:
		if(this.x<map.length-1 && !map[(this.y-1)*level.x+this.x+1]){
			this.x=this.x+1;
			this.ele.style.left=(this.x-1)*size[0]+'px';
		}
		break;
	}
	map[(this.y-1)*level.x+this.x]=this;
};
block.prototype.active=function( b){
	if(prev===this){
		prev=null;if( !b)removeClass.call(this.ele,'active');
	}else{
		if( !b)prev=this;
		addClass.call(this.ele,'active');
	}
};
block.prototype.link=function(o){
	var _=this;
	if(_.type==o.type){
		way.init([_.x,_.y],[o.x,o.y]);
		if(way.finded){
			way.show(function(){
				_.hide();
				o.hide();
				prev=null;
			});
			return;
		}
	}
	o.active();
	_.active();
};
block.prototype.hide=function(){
	box.removeChild(this.ele);
	map[(this.y-1)*level.x+this.x]=0;
	counter--;
	link.move([this.x,this.y],level.type);
	if(counter<=0){
		link.start();
	}
};

 

config.js:

 

Array.prototype.pushItem=function(Item){
	this.push(Item);
	return this;
};
function $(id){return document.getElementById(id)}
function ce(tag,prop,inner){
	var d=document.createElement(tag);
	if(prop){
		for(var i in prop)
			if(i=='class') d.className=prop[i];
			else if(i=='style') d.style.cssText=prop[i];
			else d.setAttribute(i, prop[i]);
	}
	if(inner) d.innerHTML=inner;
	return d;
}
function addClass(cls){
	if(!this.className.match(new RegExp('\\b'+cls+'\\b','g'))){
		this.className=this.className
		.split(/\s+/g).pushItem(cls).join(' ');
	}
}
function removeClass(cls){
	this.className=this.className
	.replace(new RegExp('(^|\\s+)'+cls+'\\b','g'),'');
}
document.onselectstart=function(){return false};

var map=[],
	size=[42,42],
	prev=null,
	imgfolder='img/',
	imgnumber=53,
	shapes=[],
	counter,
	box=document.getElementById('box'),
	level=null,
	levels=[
		   {x:8,y:8,shapes:Math.ceil(.3*imgnumber),type:0},
		  ];

for(var i=1;i<imgnumber;i++){
	document.createElement('img').src=imgfolder+i+'.png';
}

shapes.Rnd=function(){
	var index=Math.ceil(Math.random()*(this.length-1));
	return this.splice(index,1)[0];
};

link.start();

 

way.js:
 

var way={
	finded:false,
	init:function(p1,p2){
		var _=this, i, j, k, line;
		if(_.point && _.finded && _.path.length){
			if((_.point[0]==p1 && _.point[1]==p2)||
				(_.point[1]==p1 && _.point[0]==p2)){
				_.path.pop();
			}
		}
		_.path=[];
		_.finded=false;
		_.point=[p1,p2];
		
		
		var stepX = p1[0] > p2[0] ? -1 : 1,
			stepY = p1[1] > p2[1] ? -1 : 1;
		
		
		if(p1[1] == p2[1]){
			for( k = p1[0]; k*stepX < p2[0]*stepX; k += stepX)
				_.path.push([k, p1[1]]);
			if( this.check() )
				return this;
		}else if(p1[0] != p2[0]){
			for( i = p1[1]; i*stepY <= p2[1]*stepY; i += stepY){
				for( j = p1[1]; j*stepY < i*stepY; j += stepY)
					_.path.push([p1[0],j]);
				for( k = p1[0]; k*stepX < p2[0]*stepX; k += stepX)
					_.path.push([k, j]);
				for( ; j*stepY < p2[1]*stepY; j += stepY)
					_.path.push([p2[0],j]);
				
				if( this.check() )
					return this;
			}
		}
		
		
		if(p1[0] == p2[0]){
			for( k = p1[1]; k*stepY < p2[1]*stepY; k += stepY)
				_.path.push([p1[0], k]);
			if( this.check() )
				return this;
		}else if(p1[1] != p2[1]){
			for( i=p1[0]; i*stepX <= p2[0]*stepX; i += stepX){
				for( j = p1[0]; j*stepX < i*stepX; j += stepX)
					_.path.push([j, p1[1]]);
				for( k = p1[1]; k*stepY < p2[1]*stepY; k += stepY)
					_.path.push([j, k]);
				for( ; j*stepX < p2[0]*stepX; j += stepX)
					_.path.push([j, p2[1]]);
				
				if( this.check() )
					return this;
			}
		}
		
		
		if(p1[0]>p2[0])maxSide=Math.max(p2[0],level.x-p1[0]+1);
		else maxSide=Math.max(p1[0],level.x-p2[0]+1);
		if(p1[1]>p2[1])maxSide=Math.max(p2[1],level.y-p1[1]+1,maxSide);
		else maxSide=Math.max(p1[1],level.y-p2[1]+1,maxSide);
		
		for( var i=1; i <= maxSide; i++){
			
			line = Math.min(p1[1],p2[1])-i;
			if(line >= 0){
				for( j = p1[1]; j > line; j--)
					_.path.push([p1[0], j]);
				for( k = p1[0]; k*stepX < p2[0]*stepX; k += stepX)
					_.path.push([k, j]);
				for( ; j < p2[1]; j++)
					_.path.push([p2[0], j]);
	
				if( this.check() )
					return this;
			}
			
			line = Math.max(p1[1],p2[1])+i;
			if(line <= level.y+1){
				for( j = p1[1]; j < line; j++)
					_.path.push([p1[0], j]);
				for( k = p1[0]; k*stepX < p2[0]*stepX; k += stepX)
					_.path.push([k, j]);
				for( ; j > p2[1]; j--)
					_.path.push([p2[0], j]);
				
				if( this.check() )
					return this;
			}
			
			line = Math.min(p1[0],p2[0])-i;
			if(line >= 0){
				for( j = p1[0]; j > line; j--)
					_.path.push([j, p1[1]]);
				for( k = p1[1]; k*stepY < p2[1]*stepY; k += stepY)
					_.path.push([j, k]);
				for( ; j < p2[0]; j++)
					_.path.push([j, p2[1]]);
				
				if( this.check() )
					return this;
			}
			line = Math.max(p1[0],p2[0])+i;
			if(line <= level.x+1){
				for( j = p1[0]; j < line; j++)
					_.path.push([j, p1[1]]);
				for( k = p1[1]; k*stepY < p2[1]*stepY; k += stepY)
					_.path.push([j, k]);
				for( ; j > p2[0]; j--)
					_.path.push([j, p2[1]]);
				
				if( this.check() )
					return this;
			}
		}
		
		return this;
	},
	
	check:function (){
			var _=this;
			for ( var i = 1; i < _.path.length; i++ ){
				if(_.path[i][0]<1 || _.path[i][1]<1 || 
					_.path[i][0]>level.x || _.path[i][1]>level.y){
					continue;
				}else if(map[(_.path[i][1]-1)*level.x+_.path[i][0]] ){
					_.path=[];
					return false;
				}
			}
			_.path.push(_.point[1]);
			_.finded=true;
			return true;
		},
	
	show:function( fn){
		var path=ce('div'),pathWord=['─','│','┌','┐','└','┘'];
		
		path.appendChild(ce('div',{'class':'line','style':'left:'+ 
							(this.path[0][0]-1)*size[0]
							+'px;top:'+ (this.path[0][1]-1)*size[1] +'px'},eptype(this.path[0],this.path[1])));
		for(var i=1;i<this.path.length-1; i++){
			path.appendChild(ce('div',{'class':'line','style':'left:'+ (this.path[i][0]-1)*size[0] +'px;top:'+ (this.path[i][1]-1)*size[1] +'px'},pathWord[type(this.path[i],this.path[i-1],this.path[i+1])]));
		}
		path.appendChild(ce( 'div',{'class':'line','style':'left:'+ (this.path[i][0]-1)*size[0] +'px;top:'+ (this.path[i][1]-1)*size[1] +'px'},eptype(this.path[i],this.path[i-1]) ));
		box.appendChild(path);
		fn();
		this.find();
		setTimeout(function(){box.removeChild(path);},300);
		
		
		function eptype(p, p1){
			switch(p[0]-p1[0]){
				case -1:
					return '<p class="b2">'+ pathWord[0] +'</p>';
				case 1:
					return '<p class="b1">'+ pathWord[0] +'</p>';
				default:
					switch(p[1]-p1[1]){
					case -1:
						return '<p class="b4">'+ pathWord[1] +'</p>';
					case 1:
						return '<p class="b3">'+ pathWord[1] +'</p>';
					}
			}
		}
		
		
		function type(p, p1, p2){
			switch(p[0]-p1[0]){
			case -1:
				switch(p2[1]-p[1]){
				case -1:	
					return 4;
				case 1:		
					return 2;
				default:	
					return 0;
				}
			case 1:		
				switch(p2[1]-p[1]){
				case -1:	
					return 5;
				case 1:		
					return 3;
				default:	
					return 0;
				}
			default:
				if(p[1]>p1[1]){	
					switch(p2[0]-p[0]){
					case -1:	
						return 5;
					case 1:		
						return 4;
					default:	
						return 1;
					}
				}else{	
					switch(p2[0]-p[0]){
					case -1:	
						return 3;
					case 1:		
						return 2;
					default:	
						return 1;
					}
				}
			}
		}
	},

	find:function(){
		for(var i=1;i<map.length;i++){
			if(map[i]){
				for(var j=i+1;j<map.length;j++){
					if(map[j] && map[i].type==map[j].type){
						this.init([map[i].x,map[i].y],[map[j].x,map[j].y]);
						if(this.finded){
							window.tip=false;
							window.finded=[map[i],map[j]];
							return;
						}
					}
				}
			}
		}
		window.finded=null;
	}
};

 

main.js:
 

var link={
	start	: function(){
		this.enter();
	},
	resort:function (){
		for(var i=1; i < map.length; i++){
			if(map[i]){
				shapes.push(map[i].type);
			}
		}
		for(var i=1; i < map.length; i++){
			if(map[i]){
				map[i].type=shapes.Rnd();
				map[i].setStyle();
			}
		}
		
		way.find();
	},
	show:function (){
		if(window.finded){
			window.finded[0].active(true);
			window.finded[1].active(true);
			window.tip=true;
		}else{
			alert('');
		}
	},
	enter:function(){
		var temp;
		level		= levels[0];
		box.style.width	= (level.x*size[0])+'px';
		box.style.height= (level.y*size[1])+'px';

		for(var i=1;i<level.x*level.y;i+=2){
			shapes[i]=shapes[i+1]=Math.ceil(Math.random()*level.shapes);
		}
		
		for(var j=1;j<=level.y;j++){
			for(var i=1;i<=level.x;i++){
				map[(j-1)*level.x+i]=new block(temp=ce('p',{'class':'block'}),i,j);
				box.appendChild(temp);
			}
		}
		box.style.display= 'block';
		counter			= level.x*level.y;
		way.find();
	},
	move:function( p, t, k){
		if(t===0)return;
		var index;
		if(k===undefined)k=1;
		switch(t){
			case 1:
				for(var i=p[1];i<level.y*k;i++)
					if(map[index=i*level.x+p[0]])map[index].move(t);
				break;
			case 2:
				for(var i=p[1]; i>level.y*(1-k); i--)
					if(map[index=(i-1)*level.x+p[0]])map[index].move(t);
				break;
			case 3:
				for(var i=p[0]+1; i<=level.x*k; i++)
					if(map[index=(p[1]-1)*level.x+i])map[index].move(t);
				break;
			case 4:
				for(var i=p[0]-1; i>level.x*(1-k); i--)
					if(map[index=(p[1]-1)*level.x+i])map[index].move(t);
				break;
			case 5:
				if(p[0]/p[1] >= level.x/level.y){
					if((level.x-p[0])/p[1] >= level.x/level.y)
						this.move( p, 2);
					else
						this.move( p, 3);
				}else{
					if((level.y-p[1])/p[0] >= level.y/level.x)
						this.move( p, 4);
					else
						this.move( p, 1);
				}
				return;
			case 6:
				if(p[0]/p[1] >= level.x/level.y){
					if((level.x-p[0])/p[1] >= level.x/level.y)
						this.move( p, 1, .5);
					else
						this.move( p, 4, .5);
				}else{
					if((level.y-p[1])/p[0] >= level.y/level.x)
						this.move( p, 3, .5);
					else
						this.move( p, 2, .5);
				}
				return;
			case 7:
				if(p[1]<=level.y*.5)
					this.move(p, 1, .5);
				else
					this.move(p, 2, .5);
				return;
			case 8:
				if(p[0]<=level.x*.5)
					this.move(p, 3, .5);
				else
					this.move(p, 4, .5);
				return;
			case 9:
				if(p[1]<=level.y*.5)
					this.move(p, 3);
				else
					this.move(p, 4);
				return;
			case 10:
				if(p[0]<=level.x*.5)
					this.move(p, 1);
				else
					this.move(p, 2);
				return;
			case 11:
				this.move( p, Math.ceil(Math.random()*4));
			default:
				return;
		}
	}
}

 

master.css:
 

* { margin:0; padding:0 }

body { padding-top:40px }
#head { width:900px; margin:0 auto; font-size:12px; line-height:2em}
#head a{color:#363;text-decoration:none}
#head .button{width:60px;height:24px;text-align:center;}

#box { border:1px #ccc solid; position:relative; margin:50px auto; display:none }
#box .block { border:1px #ddf solid; background:#666; width:40px; height:40px; color:#fff; text-align:center; line-height:40px; font-family:"Arial"; position:absolute; cursor:pointer }
#box .line { width:42px; height:42px; color:#fa0; font-size:42px; line-height:42px; position:absolute; z-index:99}
#box .line .b1{width:21px;overflow:hidden;float:left}
#box .line .b2{width:21px;overflow:hidden;float:right}
#box .line .b3{height:21px;overflow:hidden;}
#box .line .b4{height:21px;overflow:hidden;margin-top:21px;}
#box .active { width:38px;height:38px; border:2px solid #fa0; color:#fa0 }

 

接著主要網頁index.html是:
 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" type="text/css" href="source/master.css" />
<title>Linkers</title>
</head>
<body>
參考來源:http://www.shirne.com/?cid=30&id=25
(臨風小築)
<div id="head">
</div>
<div id="box"></div>
<script type="text/javascript" src="source/block.js"></script>
<script type="text/javascript" src="source/way.js"></script>
<script type="text/javascript" src="source/main.js"></script>
<script type="text/javascript" src="source/config.js"></script>
</body>
</html>

 

SV不得不佩服原作的程式很有條理~而且還用了很多SV沒學過的技巧,真的很厲害喔!


如果要修改圖片的大小,是修改config.js的size=(42,42)
修改畫面大小是修改config.js的levels陣列裡的8x8

順帶一提因為原作的消掉模式很多,config.js裡的levels的type:0可以改成0~6等等(原本是配合不同關卡)!
然後因為連連看的線是用文字表示的,檔案必須是utf-8比較好喔~

嗯嗯,大概就是這樣了!

真的再次佩服原作,
然後真的很謝謝原作!

因為還有很多方法SV也是一知半解,不一定能幫大家解答,
就分享到這囉~