原生JavaScript实现连连看游戏

来源:互联网 发布:淘宝达人主页链接 编辑:程序博客网 时间:2024/05/19 16:05

向大家推荐一款原生JavaScript版连连看游戏,源码可在http://download.csdn.net/detail/zhangjinpeng66/6276583中下载,首页如下图所示:

首先看一下html的布局方式在index.html文件中:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title>连连看</title><link rel="stylesheet" type="text/css" href="css/index.css"/></head><body><center><div id="whole"><div id="gamePanel" tabindex="0"><div id="pieces"></div></div><div id="gameLogo"></div><div id="scorePanel"><span>分  数</span></div><div id="score"><span>0</span></div><div id="timePanel"><span>时  间</span></div><div id="time"><span>0</span></div><div id="button"><input id="start" type="button" onclick="Start();" value="开始"></input><input id="reset" type="button" onclick="Reset();"value="重置"></input></div></div></center><script type="text/javascript" src="js/map.js"></script><script type="text/javascript" src="js/piece.js"></script><script type="text/javascript" src="js/game.js"></script></body></html>


css文件夹下的index.css文件如下:

body {font-size : 16px;font-weight : bold;color : grey;}#whole {border : 1px double #999999;border-width : 5px;width : 800px;height : 505px;position : relative;}#gamePanel {margin: 1px 1px 1px 1px;width : 602px;height : 502px;background : url(../img/background.gif) repeat;position : absolute;}#pieces {margin-top : 35px;border : 1px solid #999999;width : 546px;height : 434px;position: relative;}#pieces .piece {width : 32px;height : 36px;position : relative;cursor : pointer;float : left;}#pieces .track {width : 32px;height : 36px;position : relative;float : left;}#pieces .track2 {width : 32px;height : 36px;position : relative;float : left;background : red;}#gameLogo {margin-top : 60px;border : 1px solid #999999;left : 607px;width : 187px;height : 73px;background : url(../img/logo.gif);position: absolute;}#scorePanel {border : 1px solid #999999;left : 607px;top : 200px;width : 187px;height : 30px;position : absolute;}#score {border : 1px solid #999999;left : 607px;top : 240px;width : 187px;height : 30px;position : absolute;}#timePanel {border : 1px solid #999999;left : 607px;top : 300px;width : 187px;height : 30px;position : absolute;}#time {border : 1px solid #999999;left : 607px;top : 340px;width : 187px;height : 30px;position : absolute;}#button {border : 1px solid #999999;left : 607px;top : 400px;width : 187px;height : 30px;position : absolute;}


 

下面让我们来看一下最核心的js部分实现代码,js部分分为三个源文件即game.js、map.js、piece.js每一个源文件对应一个类,其中本游戏通过game类来操纵map和图片piece对象:

game.js代码如下:

// 游戏控制类var Game = {// 游戏背景gamePanel : null,// 分数score : 0,// 时间time : 0,// 图片映射表pieceMap : null,// 图片列表pieceList : [],// 图片列表不包含图片pieceImgList : [],// 图片随机数列表randomList : [],// 轨迹列表trackList : [],// 游戏是否开始isGameBigin : false,// 游戏是否结束isGameOver : false,// 游戏是否重置isGameReset : false,// 图片元素是否第一次点击isFirstClick : true,// 开始游戏start : function() {document.getElementById("start").disabled = true;document.getElementById("reset").disabled = false;if (this.isGameReset) {this.isGameOver = false;this.startTime();return;} else if (this.isGameBegin) {return;} else {this.init();return;}},reset : function() {document.getElementById("start").disabled = false;document.getElementById("reset").disabled = true;this.clear();this.initPieces();this.initImgPieces();this.time = 0;document.getElementById("time").innerHTML = 0;this.score = 0;document.getElementById("score").innerHTML = 0;this.isGameReset = true;this.isGameBegin = true;},// 初始化init : function() {if (this.isGameBegin) {return;}this.pieceMap = new Map();var _this = this;this.time = 0;this.startTime();this.gamePanel = document.getElementById("pieces");this.initPieces();this.initImgPieces();this.isGameBegin = true;},// 将随机生成的150张图片添加进画布initPieces : function() {var _this = this;this.initRandomList();// 打乱随机列表排序this.messRandomList();for (var i = 0; i < 204; i ++) {var piece = new Piece(this);this.pieceList.push(piece);var x = (i%17);var y = Math.floor(i/17);this.pieceMap.put(x+","+y, piece);piece.setPosition(x, y);this.gamePanel.appendChild(piece.dom);if (x == 0 || x == 16 || y == 0 || y == 11) {piece.track = document.createElement("div");piece.track.className = "track";piece.dom.appendChild(piece.track);piece.isTracked = true;continue;} else {if (x == 1 || x == 15 || y == 1 || y == 10) {piece.setAtEdge(true);}this.pieceImgList.push(piece);}}},// 初始化图片initImgPieces : function() {for (var i = 0; i < this.pieceImgList.length; i ++) {this.pieceImgList[i].initImg();this.pieceImgList[i].img.src = "img/pieces/"+this.randomList[i]+".gif"this.pieceImgList[i].setImgSrc(this.pieceImgList[i].img.src);// 执行图片点击事件this.pieceImgList[i].onClick();}},// 初始化随机表initRandomList : function() {// 获取随机数列,成双出现for (var i = 0; i < 75; i ++) {var random = parseInt(Math.random()*22*10000, 10);var number = random%23;this.randomList.push(number);this.randomList.push(number);}},// 打乱随机表messRandomList : function() {for (var i = 0; i < this.randomList.length; i ++) {var random = parseInt(Math.random()*15*10000, 10);var number = random%150;var temp;temp = this.randomList[i];this.randomList[i] = this.randomList[number];this.randomList[number] = temp;}},// 开始计时startTime : function() {var _this = this;if (this.isGameOver) {return;} else {this.time ++;document.getElementById("time").innerHTML = this.time;this.isGameBegin = true;setTimeout(function() {_this.startTime();}, 1000);}},// 清除clear : function() {for (var i = 0; i < this.pieceList.length; i ++) {this.gamePanel.removeChild(this.pieceList[i].dom);}this.pieceList = [];this.randomList = [];this.pieceImgList = [];this.isGameOver = true;this.isGameBegin = false;}}window.onload = function() {document.getElementById("start").disabled = false;document.getElementById("reset").disabled = true;}// 游戏开始入口function Start() {Game.start();}// 游戏重置入口function Reset() {Game.reset();}


 

自定义的js版映射结构map.js源文件如下:

var Map = function(){this.data = [];}Map.prototype = {put : function(key, value) {this.data[key] = value;},get : function(key) {return this.data[key];},remove : function(key) {this.data[key] = null;},isEmpty : function() {return this.data.length == 0;},size : function() {return this.data.length;}}

 

 

图片类piece.js源文件如下:

var Piece = function(game) {// 游戏对象this.game = game;// 是否为边缘元素this.isEdge = false;// 是否挨着边缘元素this.atEdge = false;// 图片dom元素this.dom = null;// 图片元素this.img = null;// 图片元素来源this.src = null;// 轨迹元素this.track = null;// 是否可以作为轨迹this.isTracked = false;// 选中标记元素this.selected = null;// 图片横向排列this.x = 0;// 图片纵向排列this.y = 0;// 图片闪烁Idthis.flashId = null;// 图片是否点击this.onClicked = false;// 闪烁次数this.flashCount = 0;this.init();}Piece.prototype = {// 初始化init : function() {this.dom = document.createElement("div");this.dom.className = "piece";this.selected = document.createElement("img");},// 初始化图片initImg : function() {this.img = document.createElement("img");this.dom.appendChild(this.img);},// 满足算法后初始化track元素initTrack : function() {if (this.flashId != null) {// 停止闪烁this.stopFlash();}//alert("initTrack middle");if (this.track != null) {return;}this.onClicked = false;this.dom.removeChild(this.img);this.track = document.createElement("div");this.track.className = "track";this.dom.appendChild(this.track);},// 位图片设置来源setImgSrc : function(src) {this.src = src;},// 为图片设置二维排列位置setPosition : function(x, y) {this.x = x;this.y = y;},// 为图片设置选中元素setSelected : function() {if (this.flashCount ++ % 2 == 0) {//this.dom.removeChild(this.img);//this.selected.src = "img/selected.gif";//this.dom.appendChild(this.selected);this.img.src = "img/pieces/flash.gif";} else {//if (this.selected != null) {//this.dom.removeChild(this.selected);//}this.img.src = this.src;//this.dom.appendChild(this.img);}},// 设置是否为边缘元素setEdge : function(isEdge) {this.isEdge = isEdge;},// 设置是否挨着边缘元素setAtEdge : function(atEdge) {this.atEdge = atEdge;},// 开始闪烁flash : function() {var _this = this;this.flashId = setInterval(function() {_this.setSelected();}, 500);},// 停止闪烁stopFlash : function() {clearInterval(this.flashId);if (this.flashCount % 2 == 1) {//if (this.selected != null) {//this.dom.removeChild(this.selected);//}this.img.src = this.src;//this.dom.appendChild(this.img);}},// 对象被选择的内部函数onClick : function() {if (this.onClicked) {return;}var _this = this;this.img.onclick = function() {if (!document.getElementById("start").disabled) {return;}if (_this.onClicked) {return;}if (_this.checkPiece()) {return;}_this.flash();_this.onClicked = true;};},// 检查是否有被点击的图片checkPiece : function() {for (var i = 0; i < this.game.pieceList.length; i ++) {if (this.game.pieceList[i].onClicked && !this.game.pieceList[i].equal(this)) {if (this.game.pieceList[i].equalImage(this)) {//alert("The same Image");this.searchTrack(this.game.pieceList[i]);} else {this.game.pieceList[i].stopFlash();this.game.pieceList[i].onClicked = false;this.onClicked = false;return false;}return true;} else {continue;}}return false;},// 是否为同一个对象equal : function(piece) {return (this.x == piece.x && this.y == piece.y);},// 是否为同一个图片equalImage : function(piece) {return this.src == piece.src;},// 搜寻路径searchTrack : function(piece) {if (this.isNear(piece)) {this.linkTrack(piece);return;}if (this.isReach(piece) || this.isReach2(piece)) {this.linkTrack(piece);return;}},// 是否相邻isNear : function(piece) {var a = (Math.abs(piece.x - this.x) == 1) && (piece.y == this.y)|| (Math.abs(piece.y - this.y) == 1) && (piece.x == this.x);return a;},// 直线isStraightReach : function(piece) {//alert("isStraightReach");if (this.isNear(piece)) {return true;}var a = false;var b = false;// 沿y轴方向搜索if (this.x == piece.x) {//alert("!!!!!!!!!!!");for (var i = this.min(this.y, piece.y) + 1; i < this.max(this.y, piece.y); i ++) {//alert("this.x == piece.x: " + piece.x + "," + i);if (this.game.pieceMap.get(piece.x + "," + i).isPass()) {a = true;this.game.trackList.push(this.game.pieceMap.get(piece.x + "," + i));continue;} else {a = false;this.game.trackList = [];return a;}}}// 沿x轴方向搜索if (this.y == piece.y) {//alert("!!!!!!!!!!!");for (var i = this.min(this.x, piece.x) + 1; i < this.max(this.x, piece.x); i ++) {//alert("this.y == piece.y: " + i + "," + piece.y);if (this.game.pieceMap.get(i + "," + piece.y).isPass()) {b = true;this.game.trackList.push(this.game.pieceMap.get(i + "," + piece.y));continue;} else {b = falsethis.game.trackList = [];return b;}}}return a || b;},// 拐一次弯搜索isReach1 : function(piece) {//alert("isReach1");var corner_1 = this.game.pieceMap.get(this.x + "," + piece.y);var corner_2 = this.game.pieceMap.get(piece.x + "," + this.y);var _this = this;if ((_this.isStraightReach(corner_1))&& (corner_1.isStraightReach(piece))&& corner_1.isPass()) {//alert("corner_1: " + this.x + "," + piece.y);this.game.trackList.push(corner_1);return true;}if ((_this.isStraightReach(corner_2))&& (corner_2.isStraightReach(piece))&& corner_2.isPass()) {//alert("corner_2: " + piece.x + "," + this.y);this.game.trackList.push(corner_2);return true;}return false;},// 直接或拐一次弯搜索isReach : function(piece) {var a = this.isStraightReach(piece);var b = this.isReach1(piece);return a || b;},// 拐两次弯搜索isReach2 : function(piece) {// 沿x轴正向搜索for (var i = this.x + 1; i < 17; i ++) {if (!this.game.pieceMap.get(i + "," + this.y).isPass()) {this.game.trackList = [];break;} else if (this.game.pieceMap.get(i + "," + this.y).isReach(piece)&& this.game.pieceMap.get(i + "," + this.y).isPass()) {this.game.trackList.push(this.game.pieceMap.get(i + "," + this.y));return true;}}// 沿x轴搜索for (var i = this.x - 1; i >= 0; i --) {if (!this.game.pieceMap.get(i + "," + this.y).isPass()) {this.game.trackList = [];break;} else if (this.game.pieceMap.get(i + "," + this.y).isReach(piece)&& this.game.pieceMap.get(i + "," + this.y).isPass()) {this.game.trackList.push(this.game.pieceMap.get(i + "," + this.y));return true;}}// 沿y轴搜索for (var i = this.y - 1; i >= 0; i --) {if (!this.game.pieceMap.get(this.x + "," + i).isPass()) {this.game.trackList = [];break;} else if (this.game.pieceMap.get(this.x + "," + i).isReach(piece)&& this.game.pieceMap.get(this.x + "," + i).isPass()) {this.game.trackList.push(this.game.pieceMap.get(this.x + "," + i));return true;}}// 沿y轴正向搜索for (var i = this.y + 1; i < 12; i ++) {if (!this.game.pieceMap.get(this.x + "," + i).isPass()) {this.game.trackList = [];break;} else if (this.game.pieceMap.get(this.x + "," + i).isReach(piece)&& this.game.pieceMap.get(this.x + "," + i).isPass()) {this.game.trackList.push(this.game.pieceMap.get(this.x + "," + i));return true;}}return false;},// 路径连接linkTrack : function(piece) {this.initTrack();piece.initTrack();this.changeScore();this.showTrack(piece);},// 显示足迹showTrack : function(piece) {this.game.trackList.push(piece);this.track.className = "track2";for (var i = 0; i < this.game.trackList.length; i ++) {//alert(i);this.game.trackList[i].track.className = "track2";}var _this = this;setTimeout(function() {_this.hideTrack()}, 500);},// 隐匿足迹hideTrack : function() {for (var i = 0; i < this.game.trackList.length; i ++) {this.game.trackList[i].track.className = "track";}this.game.trackList = [];this.track.className = "track";this.isTracked = true;},// 分数增加changeScore : function() {this.game.score += 100;document.getElementById("score").innerHTML = this.game.score;},min : function(a, b) {if (a < b) {return a;} else {return b;}},max : function(a, b) {if (a > b) {return a;} else {return b;}},// 判断是否通过isPass : function() {return this.track != null;}}


 

 

以上是源文件的代码,具体的实现代码请关注CSDN中zhangjinpeng66下载。下面讲一下连连看游戏最核心的部分,js实现搜索路径。

js实现搜索路径算法首先最简单的是判断两个图片能否直线到达函数代码如下:

// 直线isStraightReach : function(piece) {//alert("isStraightReach");if (this.isNear(piece)) {return true;}var a = false;var b = false;// 沿y轴方向搜索if (this.x == piece.x) {//alert("!!!!!!!!!!!");for (var i = this.min(this.y, piece.y) + 1; i < this.max(this.y, piece.y); i ++) {//alert("this.x == piece.x: " + piece.x + "," + i);if (this.game.pieceMap.get(piece.x + "," + i).isPass()) {a = true;this.game.trackList.push(this.game.pieceMap.get(piece.x + "," + i));continue;} else {a = false;this.game.trackList = [];return a;}}}// 沿x轴方向搜索if (this.y == piece.y) {//alert("!!!!!!!!!!!");for (var i = this.min(this.x, piece.x) + 1; i < this.max(this.x, piece.x); i ++) {//alert("this.y == piece.y: " + i + "," + piece.y);if (this.game.pieceMap.get(i + "," + piece.y).isPass()) {b = true;this.game.trackList.push(this.game.pieceMap.get(i + "," + piece.y));continue;} else {b = falsethis.game.trackList = [];return b;}}}return a || b;},



该函数实现了连连看判断两图片是否符合连接条件的最简单的一步,然后是拐一次弯搜索。

// 拐一次弯搜索isReach1 : function(piece) {//alert("isReach1");var corner_1 = this.game.pieceMap.get(this.x + "," + piece.y);var corner_2 = this.game.pieceMap.get(piece.x + "," + this.y);var _this = this;if ((_this.isStraightReach(corner_1))&& (corner_1.isStraightReach(piece))&& corner_1.isPass()) {//alert("corner_1: " + this.x + "," + piece.y);this.game.trackList.push(corner_1);return true;}if ((_this.isStraightReach(corner_2))&& (corner_2.isStraightReach(piece))&& corner_2.isPass()) {//alert("corner_2: " + piece.x + "," + this.y);this.game.trackList.push(corner_2);return true;}return false;},


 

 

在拐一次弯搜索的函数中调用了直接搜索的函数,同样最复杂的拐两次弯搜索也会调用拐一次弯搜索的函数。

// 拐两次弯搜索isReach2 : function(piece) {// 沿x轴正向搜索for (var i = this.x + 1; i < 17; i ++) {if (!this.game.pieceMap.get(i + "," + this.y).isPass()) {this.game.trackList = [];break;} else if (this.game.pieceMap.get(i + "," + this.y).isReach(piece)&& this.game.pieceMap.get(i + "," + this.y).isPass()) {this.game.trackList.push(this.game.pieceMap.get(i + "," + this.y));return true;}}// 沿x轴搜索for (var i = this.x - 1; i >= 0; i --) {if (!this.game.pieceMap.get(i + "," + this.y).isPass()) {this.game.trackList = [];break;} else if (this.game.pieceMap.get(i + "," + this.y).isReach(piece)&& this.game.pieceMap.get(i + "," + this.y).isPass()) {this.game.trackList.push(this.game.pieceMap.get(i + "," + this.y));return true;}}// 沿y轴搜索for (var i = this.y - 1; i >= 0; i --) {if (!this.game.pieceMap.get(this.x + "," + i).isPass()) {this.game.trackList = [];break;} else if (this.game.pieceMap.get(this.x + "," + i).isReach(piece)&& this.game.pieceMap.get(this.x + "," + i).isPass()) {this.game.trackList.push(this.game.pieceMap.get(this.x + "," + i));return true;}}// 沿y轴正向搜索for (var i = this.y + 1; i < 12; i ++) {if (!this.game.pieceMap.get(this.x + "," + i).isPass()) {this.game.trackList = [];break;} else if (this.game.pieceMap.get(this.x + "," + i).isReach(piece)&& this.game.pieceMap.get(this.x + "," + i).isPass()) {this.game.trackList.push(this.game.pieceMap.get(this.x + "," + i));return true;}}return false;},

 

该函数以点击的图片为中心分别沿x轴,y轴展开搜索。

以上是本游戏代码的全部内容。具体游戏源码请到CSDN中zhangjinpeng66的资源里下载。

 

原创粉丝点击