The final product code was written in a hurry, with no fault tolerance, and unreasonable encapsulation. Only the core part was implemented, and the other parts were old additions that you liked.
Let’s start my tutorial (let’s call it a tutorial, I’ll just write it down in a hurry, I have too little time, please forgive me)
Analysis at the highest difficulty level of the game.
First step, general analysis
Look at the main elements of the game and find 3 parts, some pairs of picture blocks, a square container that can hold the picture blocks, and a line that can connect the two blocks. .
The second step, element analysis
Picture blocks: There are 32 different patterns in total, 4 of each pattern. The tiles will disappear in response to the click of the mouse. The tiles have height and width.
Square plate: Can hold 128 tiles, 2-dimensional bearing, 16 tiles horizontally and 8 tiles vertically. The square plate can hold tiles and disrupt the order of existing tiles.
Connection: The core of the game, connect two tiles to get the center point. It can only be folded twice at most and cannot penetrate the tiles. The connection can pass outside the square plate
The third step, abstract
With the above analysis, 3 elements are abstracted into 3 objects. How to abstract it, you can use your own brain. The code I wrote is because of lack of brain power, which leads to messy encapsulation.
Part 4, core algorithm
1, shuffling algorithm (very simple algorithm)
Push the data from the 2-dimensional array to the 1-dimensional array and exchange the position attributes in the data. Replace the elements according to the position
2. Find the path:
In fact, the most important thing about Lianliankan is how to find a path between two tiles with at most two vertices, here There are many ways to implement. What I implement here is the method found, not the shortest path or the optimal path.
According to research, you will find that the connection can be divided into two parts, one part is the normal line, and the other part is the ray projected by the block onto the normal line. Then, we can use this relationship to find a path.
First, suppose there are two blocks A and B. Then each block has two rays in the X direction and Y direction. Then if there is a Y-direction normal line in AB's X-ray common Between areas, or if there is an X-direction normal between the Y-ray common areas of AB, then a path is found.
Places that are not implemented: (These are basically irrelevant. The pass can be easily modified according to the shuffling method. If you are interested, just implement it)
Timing, scoring, prompts, Passage
]<script>
/************************************************************************
设计: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 < le; i++){
var s = Math.floor(Math.random()*le);
var zx = arr[i].x;
var zy = arr[i].y;//这里不能写成z=arr[i],因为object是引用
arr[i].x = arr[s].x;
arr[i].y = arr[s].y;
arr[s].x = zx;
arr[s].y = zy;
}
}
//数组元素随机排序
function ArrayRnd(arr,times){
for(i = 0; i < times; i++)rndArray(arr)
}
//获取Html元素的绝对位置
function GetAbsoluteLocation(element){
if ( arguments.length != 1 || element == null ) return null;
var offsetTop = element.offsetTop;
var offsetLeft = element.offsetLeft;
var offsetWidth = element.offsetWidth;
var offsetHeight = element.offsetHeight;
while( element = element.offsetParent ) {
offsetTop += element.offsetTop;
offsetLeft += element.offsetLeft;
}
return {
absoluteTop: offsetTop,
absoluteLeft: offsetLeft,
offsetWidth: offsetWidth,
offsetHeight: offsetHeight
};
}
/*****************************封装对象*******************************************/
//方盘对象,用来放置图块,tot设计,修改请保留
function objGrid(width,height){
var imgNum = 32; //图块样式个数
var gridNum = width * height;
//初始化图块所用的图片名
var arrImg = new Array(imgNum);
for(i = 0;i < imgNum; i++) arrImg[i] = "llk_" + i;
//初始化图块数组
var arrImgBlock = new Array(gridNum);
for(i = 0; i< gridNum; i++){
arrImgBlock[i] = new objImgBlock(arrImg[Math.floor(i /4)]);
arrImgBlock[i].x = Math.floor(i / height);
arrImgBlock[i].y = i % height;
}
//打乱次序
ArrayRnd(arrImgBlock,5);
//生成方盘对象
var obj = new Object();
obj.backGround = "back.gif";//方盘的背景图片
obj.arrGrid = new Array(width);
//初始化方盘二维数组
for(i = 0; i < width; i++)
obj.arrGrid[i] = new Array(height);
//向放盘中放置图块
obj.init = function (arrBlock){
for(i = 0; i < width; i++)
for(j = 0; j < height; j++){
this.arrGrid[i][j] = "";
}
grid = arrBlock.length;
for(i = 0; i < grid; i++)
this.arrGrid[arrBlock[i].x][arrBlock[i].y] = arrBlock[i];
this.drawGrid()
this.setGridBackground(this.backGround)
}
//洗牌
obj.shuffle = function (){
var arrIBlock = new Array();
for(i = 0; i < width; i++)
for(j = 0; j < height; j++)
if(this.arrGrid[i][j] != "")arrIBlock.push(this.arrGrid[i][j]);
ArrayRnd(arrIBlock,5);
this.init(arrIBlock);
}
//查找最远射点
obj.findRadial = function (point){
var minX = -1, minY = -1, maxX = width, maxY = height;
//水平查找最远射点
for(i = 0; i < width; i++){
if(i < point.X){
if(this.arrGrid[i][point.Y] != "")
minX = point.X;
else{
if(minX == point.X) minX = i;
}
}else if(i > point.X){
if(this.arrGrid[i][point.Y] != ""){
maxX = i - 1;
break;
}
}
}
//垂直查找最远射点
for(i = 0; i < height; i++){
if(i < point.Y){
if(this.arrGrid[point.X][i] != "")
minY = point.Y;
else{
if(minY == point.Y) minY = i;
}
}else if(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 <= minEY){
if(maxSY == -1){
startPoint = new objPoint(sPoint.X,-1);
endPoint = new objPoint(ePoint.X,-1);
}else if(minEY == height){
startPoint = new objPoint(sPoint.X,height);
endPoint = new objPoint(ePoint.X,height);
}
else{
for(j = maxSY; j <= minEY; j++){
pass = true;
for(i = Math.min(sPoint.X,ePoint.X) + 1; i < Math.max(sPoint.X,ePoint.X); i++){
if(this.arrGrid[i][j] != "") pass = false;
}
if(pass){
startPoint = new objPoint(sPoint.X,j);
endPoint = new objPoint(ePoint.X,j);
}
}
}
}//查找竖法线
else if( maxSX <= minEX){
if(maxSX == -1){
startPoint = new objPoint(-1,sPoint.Y);
endPoint = new objPoint(-1,ePoint.Y);
}else if(minEX == width){
startPoint = new objPoint(width,sPoint.Y);
endPoint = new objPoint(width,ePoint.Y);
}
else{
for(i = maxSX; i <= minEX; i++){
pass = true;
for(j = Math.min(sPoint.Y,ePoint.Y) + 1; j < Math.max(sPoint.Y,ePoint.Y); j++){
if(this.arrGrid[i][j] != "") pass = false;
}
if(pass){
startPoint = new objPoint(i,sPoint.Y);
endPoint = new objPoint(i,ePoint.Y);
}
}
}
}
//返回法线端点
if(startPoint){
return{sP : startPoint, eP : endPoint}
}
else {return false};
}
//画方盘
obj.drawGrid = function (){
var gDiv = document.getElementById("gridDiv");
var tempHtml = "<table id=gridTalbe border=0 cellpadding=0 cellspacing=0 align=center>";
for(i = 0; i < height; i++){
tempHtml += "";
for(j = 0; j < width; j++){
tempHtml += "<td>";
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 "<img name=" + this.picName + " onclick=clickImg(" + this.x + "," + this.y + ") src=images/"
+ this.picName + ".gif>"
}
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 <= lineLen; i++){
var lineDot = document.createElement("<div class=lineDot>");
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;
}
}
</script>