用javascript做一个webgame连连看大家看下
最后成品代码写的仓促,没有容错,封装也不合理,只实现了核心部分,其他部分,喜欢添加的旧添加吧。
下面就开始我的教程(姑且算是教程吧,草草写点吧,时间太少,大家原谅)
以最高难度游戏级别作的分析。
第一步,大体分析
看看游戏主要包含哪些元素,发现3部分,一些成对的图片块,一个能盛图片块的方盘容器,一个能连接两个图块的线。
第二步,元素分析
图块:图块一共有32种不同的图案,每种图案4张,图块会相应鼠标的点击,图块会消失,图块有高度和宽度。
方盘:能承载128个图块,2维承载,横向16块,纵向8块,方盘可以放图块,可以打乱已有图块的位置顺序。
连线:游戏的核心,连接两块图块得中心点,最多只能折两次,不能穿透图块,连线可以通过方盘外部
第三步,抽象
有了上面的分析,把3个元素抽象成3个对象,怎么抽象的,自己动脑吧,我写的代码就是因为动脑不足,导致封装乱七八糟的。
第四部,核心算法
1,洗牌算法(很简单的算法)
把2维数组的数据推到1维数组,交换数据中位置属性,重新按照位置放置元素
2,查找路径:
其实连连看最主要的地方就是如何查找两个图块之间的一条最多只有两个折点的路径,这里的实现方法有很多种,我这里实现的是找到的方法,不是最短路径或者最优路径的方法。
根据研究你会发现,连线可以分成两部分,一部分是法线,一部分是图块投影到法线上的射线,那么,我们就可以利用这个关系,查找一条路径。
首先,设两个图块A,B,那么每个图块都有X向和Y向两条射线,那么如果存在一条Y向法线在AB的X射线公共区之间,或者存在X向法线在AB的Y射线公共区之间,那么就找到了一条路径。
没有实现的地方:(这些基本都是无关紧要了,关口可以根据洗牌的方法很容易改造出来,有兴趣你就去实现吧)
计时、计分、提示、关口
我们-www.jb51.net 连连看
.select{filter:Gray}
#lineDiv{height:20px}
.lineDot{position:absolute; background:#f60;padding:0;font-size:0;width:10px;height:10px}
#gridDiv{padding:50px;background:#000;border:5px solid #ccc}
#gridTalbe{background-repeat:no-repeat; background-position:center; margin:0}
#gridTalbe td{width:41px;height:50px;}
#gridTalbe img{width:40px; border-right:1px solid #666;}
body{ padding:0; margin:0}
/************************************************************************
设计:tot
时间:2007-12-29
MSN:xiaotot@msn.com
************************************************************************/
//记录被选择图块的信息
var selectImg = "";
var selectX = 0;
var selectY = 0;
//图块宽度和高度,用来计算画线的位置
var stepX = 41;
var stepY = 50;
//初始化棋盘,只能以oGrid命名
var oGrid = new objGrid(16,8);
/*****************************功能函数*******************************************/
//数组元素随机排序,tot设计,修改请保留
function rndArray(arr){
var le = arr.length;
for(var i=0; i point.X){
if(this.arrGrid[i][point.Y] != ""){
maxX = i - 1;
break;
}
}
}
//垂直查找最远射点
for(i = 0; i point.Y){
if(this.arrGrid[point.X][i] != ""){
maxY = i - 1;
break;
}
}
}
return {
MinX : minX,
MinY : minY,
MaxX : maxX,
MaxY : maxY
}
}
//查找法线
obj.findNormal = function(sPoint,ePoint){
var startPoint, endPoint
var sRadial = this.findRadial(sPoint);
var eRadial = this.findRadial(ePoint);
var pass;//是否可以通过标志
maxSX = Math.max(sRadial.MinX,eRadial.MinX)
minEX = Math.min(sRadial.MaxX,eRadial.MaxX);
maxSY = Math.max(sRadial.MinY,eRadial.MinY);
minEY = Math.min(sRadial.MaxY,eRadial.MaxY)
//查找横法线
if( maxSY ";
for(i = 0; i ";
for(j = 0; j ";
if(this.arrGrid[j][i] != "")
tempHtml += this.arrGrid[j][i].toHtml();
tempHtml += "
";
}
tempHtml += "
";
}
tempHtml += "
";
gDiv.innerHTML = tempHtml;
}
//设置背景
obj.setGridBackground = function(img){
var gTable = document.getElementById("gridTalbe");
gTable.style.backgroundImage = "url(images/" + img + ")";
this.backGround = img;
}
//执行初始化
obj.init(arrImgBlock);
return obj;
}
//图块对象
function objImgBlock(pic){
var obj = new Object();
obj.picName = pic;
obj.x = 0;
obj.y = 0;
obj.toHtml = function(){
return ""
}
return obj;
}
//坐标点对象,对应于承载图块的二元数组下标
function objPoint(x,y){ return{ X : x, Y : y }}
//点击图块的动作
function clickImg(x,y){
eObj = event.srcElement;
if((selectImg.name == eObj.name) && (selectImg !== eObj)){
if(Line(new objPoint(selectX,selectY),new objPoint(x,y))){
selectImg.style.display = "none";
eObj.style.display = "none";
selectImg = "";
selectX = 0; selectY = 0;
}else changeSelect(eObj,x,y)
}else{
changeSelect(eObj,x,y)
}
}
//更换选择的图块
function changeSelect(o,x,y){
selectImg.className = "";
selectImg = o;
selectImg.className = "select";
selectX = x; selectY = y;
}
//画线
function Line(sPoint,ePoint){
var nLine = oGrid.findNormal(sPoint,ePoint);
if(nLine){
oGrid.arrGrid[sPoint.X][sPoint.Y] = "";
oGrid.arrGrid[ePoint.X][ePoint.Y] = "";
drawLine(sPoint,nLine.sP);
drawLine(nLine.sP,nLine.eP);
drawLine(ePoint,nLine.eP);
setTimeout(clearLine,500);
return true;
}else{
return false
}
}
//连接两点的画线函数
function drawLine(sPoint,ePoint){
var startPoint, endPoint, lineType = true;//默认画横线
var lineLen;//画线长度
var linDiv = document.getElementById("lineDiv");
var O = document.getElementById("gridTalbe");
//原点的绝对坐标
var oPoint = new objPoint(GetAbsoluteLocation(O).absoluteLeft - 25, GetAbsoluteLocation(O).absoluteTop - 30);
if(sPoint.X == ePoint.X){ //画竖线
if(sPoint.Y > ePoint.Y){//判断起始点
startPoint = ePoint;
endPoint = sPoint;
}else{
startPoint = sPoint;
endPoint = ePoint;
}
lineLen = endPoint.Y - startPoint.Y + 1;
lineType = false;
}else{//画横线
if(sPoint.X > ePoint.X){//判断起始点
startPoint = ePoint;
endPoint = sPoint;
}else{
startPoint = sPoint;
endPoint = ePoint;
}
lineLen = endPoint.X - startPoint.X + 1;
}
for(i = 1; i
");
lineDot.style.left = lineType ? (oPoint.X + stepX * (startPoint.X + i) + "px") : (oPoint.X + stepX * (startPoint.X + 1) + "px");
lineDot.style.top = lineType ? (oPoint.Y + stepY * (startPoint.Y + 1) + "px") : (oPoint.Y + stepY * (startPoint.Y + i) + "px");
linDiv.insertBefore(lineDot);
}
}
//清除画线
function clearLine(){
var linDiv = document.getElementById("lineDiv");
linDiv.innerHTML = "";
}
//调试用
function debug(str){
var linDiv = document.getElementById("debug");
linDiv.innerHTML = str + "
" + linDiv.innerHTML;
}
function odebug(obj,oname){
var linDiv = document.getElementById("debug");
for(o in obj){
if(typeof(obj[o]) == "object"){
odebug(obj[o],oname + o + ".")
}
else linDiv.innerHTML = oname + o + "=" + obj[o] + "
" + linDiv.innerHTML;
}
}
[Ctrl+A 全选 注:如需引入外部Js需刷新才能执行]