我们简单来说下用用JS实现这样简单的拼图游戏可以有那两种方法。一种是拖拽拼图,一种是经典的九宫格拼图,可以自定义参数设置游戏难度
先看看截图效果
拖拽模式(拖拽图片切换图片)
点击模式(点击图片与空白区域切换位置)
不多说,直接上代码
css
#canvasBox{ margin: 0 auto; position: fixed; border: 2px solid #f00; overflow: hidden; } .item{ display: inline-block; border: 1px solid #f00; position: absolute; top: 0; left: 0; transition: 0.1s; }
html
<div style="margin: 0 auto;text-algin:center;"> <button onclick="setGame('block', 'none')">拖拽模式</button> <button onclick="setGame('none', 'block')" >点击模式</button> </div> <div id="canvasBox"></div> <div id="canvasBox2"></div>
javascript
/* * @title JigsawGame 拼图游戏 * @params obj Object 游戏参数 * { * @param Id String 容器id * @param imgUrl String 图片路径 * @param level Number 游戏难度 简单:1 || 普通:2 || 困难:3 * @param gameType Number 游戏类型 拖动版本:1 || 点击版本:2 * } * @author beideng */ function JigsawGame(obj){ // 初始化容器 this.Id = document.getElementById(obj.Id); // 初始化图片 this.img = new Image(); this.img.src = obj.imgUrl; // 容器最大宽度 this.windowWidth = document.body.clientWidth; this.maxWidth = this.windowWidth > 750 ? 750 : (this.windowWidth * 0.9); // 设置容器宽高 this.Id.style.width = this.maxWidth + "px"; this.Id.style.height = this.maxWidth + "px"; this.Id.style.left = (this.windowWidth - this.maxWidth)/2 + "px"; this.Id.style.top = 50 + "px"; // 获取容器范围 this.boxOffsetY = parseFloat(this.Id.style.top); this.boxOffsetX = parseFloat( this.Id.style.left); // 关卡(简单:1 || 普通:2 || 困难:3) if(obj.level == 1 || obj.level == 2 || obj.level == 3 ){ this.Level = obj.level; }else{ this.level = 1; } // 难度 var diffArr = [3, 4, 5]; this.Diff= diffArr[this.Level-1]; // canvas宽高 this.cW = this.maxWidth/ this.Diff; this.cH = this.maxWidth/ this.Diff; // 记录的小方块个数 this.number = 0; // 正确的数组 this.numberArr = []; // 存储小方块的中心点坐标 this.centerXY = []; /* * 获取游戏类型 */ this.gameType = obj.gameType || 1; // 记录最后一个元素的标记 this.lastElement = { sign: 0, left: 0, top: 0, Id: obj.Id + 1 }; // 初始化 this.Init(); } /* * 操作方法 * */ JigsawGame.prototype = { /* * @method 初始化 */ Init: function(){ var that = this; this.img.onload = function(){ // 格子宽高 var LevelW = that.img.width/that.Diff; var LevelH = that.img.height/that.Diff; for(var i = 0 ; i < that.Diff; i++){ for(var j = 0 ; j < that.Diff; j++){ // 初始化小方块 that.initCube(i, j, LevelW, LevelH); } } // 打乱小方块 that.upsetElement(); // 游戏类型判断 if(that.gameType == 1){ // 监听拖动 that.Id.addEventListener("mousedown",function(event){ that.mouseDown(event); }, false); }else{ // 获取空白小方块坐标 that.getLastElement(); // 监听点击 that.Id.addEventListener("click",function(event){ that.mouseClick(event); }, false); } } }, /* * @method 初始化小方块 * @param i Number 循环值 * @param j Number 循环值 * @param j LevelW 小方块宽 * @param j LevelH 小方块高 */ initCube: function(i, j, LevelW, LevelH){ // 创建一个小方块 var item = document.createElement("div"), cW = this.cW, cH = this.cH; item.className = "item"; item.setAttribute("data-index", this.number); item.style.width = cW + "px"; item.style.height = cH + "px"; item.style.left = i * cW + "px"; item.style.top = j * cH + "px"; item.innerHTML = "<canvas class='' width='"+ cW +"' height='"+ cH +"'></canvas>"; this.Id.appendChild(item); var canvas = item.querySelector("canvas"); var ctx = canvas.getContext("2d"); /* * 当游戏为点击类型时 * 去掉最后一个小方块里的图片 * 且记录当前元素的坐标以及编号 */ if(this.gameType != 1 && j == this.Diff-1 && i == this.Diff-1){ this.lastElement.sign = this.number; item.id = this.lastElement.Id; }else{ ctx.drawImage(this.img, i * LevelW, j * LevelH , LevelW, LevelH, 0 , 0, cW, cH) } // 每添加一个就压入一次到数组 this.numberArr.push({ x: i*cW +"px" , y: j*cH +"px" }); this.number++; // 压入初始中心点 this.centerXY.push({ x: i*cW + cW / 2, y: j*cH + cH / 2 }); }, /* * @method 悬停拖住小方块 * @param event Object 鼠标对象 */ mouseDown: function(event){ console.log(event) var event = event || window.event; var that = this; var target = event.target || event.srcElement; // 保证拖动的是想要的元素 if( target.parentElement.className.toLowerCase() == "item"){ var Element = target.parentElement; // 存储当前元素的top,left var thisTop = parseFloat( Element.style.top ); var thisLeft = parseFloat( Element.style.left ); // 获取当前点击的位置 var pageX = event.pageX; var pageY = event.pageY; // 拖动 document.onmousemove = function(e){ console.log(e) that.mouseMove(e, Element, thisTop, thisLeft, pageY, pageX); return false; } // 松开 document.onmouseup = function(e){ that.mouseUp(e, Element, thisTop, thisLeft) // 释放拖拽 document.onmousemove = null; document.onmouseup = null; return false; } } return false; }, /* * @method 拖动小方块 * @param e Object 鼠标对象 */ mouseMove: function(e, Element, thisTop, thisLeft, pageY, pageX){ var pageX2 = e.pageX; var pageY2 = e.pageY; Element.style.top = thisTop + (pageY2 - pageY) + "px"; Element.style.left = thisLeft + (pageX2 - pageX) + "px"; Element.style.zIndex = 1000; }, /* * @method 松开小方块 * @param e Object 鼠标对象 */ mouseDown: function(event){ console.log(event) var event = event || window.event; var that = this; var target = event.target || event.srcElement; // 保证拖动的是想要的元素 if( target.parentElement.className.toLowerCase() == "item"){ var Element = target.parentElement; // 存储当前元素的top,left var thisTop = parseFloat( Element.style.top ); var thisLeft = parseFloat( Element.style.left ); // 获取当前点击的位置 var pageX = event.pageX; var pageY = event.pageY; // 拖动 document.onmousemove = function(e){ console.log(e) that.mouseMove(e, Element, thisTop, thisLeft, pageY, pageX); return false; } // 松开 document.onmouseup = function(e){ that.mouseUp(e, Element, thisTop, thisLeft) // 释放拖拽 document.onmousemove = null; document.onmouseup = null; return false; } } return false; }, /* * @method 拖动小方块 * @param e Object 鼠标对象 */ mouseMove: function(e, Element, thisTop, thisLeft, pageY, pageX){ var pageX2 = e.pageX; var pageY2 = e.pageY; Element.style.top = thisTop + (pageY2 - pageY) + "px"; Element.style.left = thisLeft + (pageX2 - pageX) + "px"; Element.style.zIndex = 1000; }, /* * @method 松开小方块 * @param e Object 鼠标对象 */ mouseUp: function(e, Element, thisTop, thisLeft){ var that = this, cW = this.cW, cH = this.cH; // 检测当前拖动替换目标 var moveCenterX = parseFloat(Element.style.left) + cW / 2; var moveCenterY = parseFloat(Element.style.top) + cH / 2; var changeElementIndex = this.checkChangeElement(moveCenterX, moveCenterY); var changeElement = this.Id.getElementsByClassName("item")[changeElementIndex]; // 限制拖拽范围 // 当松开的坐标xy在容器范围内 if( e.pageX < this.boxOffsetX || e.pageX > (this.boxOffsetX + this.maxWidth) || e.pageY < this.boxOffsetY || e.pageY > (this.boxOffsetY + this.maxWidth) ){ console.log("释放") Element.style.top = thisTop + "px"; Element.style.left = thisLeft + "px"; }else{ // 判断当前元素是否离开了自己的格子 if( Element.getAttribute("data-index") == changeElement.getAttribute("data-index")){ Element.style.top = thisTop + "px"; Element.style.left = thisLeft + "px"; }else{ // 进行替换 Element.style.top = changeElement.style.top ; Element.style.left = changeElement.style.left ; changeElement.style.top = thisTop + "px"; changeElement.style.left = thisLeft + "px"; changeElement.style.zIndex = 1000; // 更新小方块中心点 this.updateElement(); } } // 消除层级问题 setTimeout(function(){ Element.style.zIndex = 0; changeElement.style.zIndex = 0; if(that.compareArray()){ alert("恭喜你,拼图成功!"); } }, 150); // 判断拼图完成 console.log(this.compareArray()) console.log(this.numberArr) }, /* * @method 检测当前拖动替换目标 * @param moveLeft Number 鼠标移动的x值 * @param moveTop Number 鼠标移动的y值 * @return minIndex Number 返回目标对象下标 * 通过三角函数检测当前拖动对象中心点和其他所有对象中心点距离,离谁最近就和谁替换 */ checkChangeElement: function(moveLeft, moveTop){ // 最小距离 var minDistance = null; // 最小距离替换目标 var minIndex = null; for(var i = 0 ; i < this.centerXY.length; i++){ var x = Math.abs( moveLeft - this.centerXY[i].x ); var y= Math.abs( moveTop - this.centerXY[i].y ); var val = Math.ceil(Math.sqrt( x * x + y * y)); // 初次判断 if(minDistance == null){ minDistance = val; minIndex = i; } // 后续判断 if(minDistance > val){ minDistance = val; minIndex = i; } } // 返回目标对象下标 return minIndex; }, /* * @method 更新小方块中心点 */ updateElement: function(){ var allElement = this.Id.getElementsByClassName("item"), cW = this.cW, cH = this.cH; this.centerXY = []; for(var i = 0 ; i < allElement.length; i++){ this.centerXY.push({ x: parseFloat(allElement[i].style.left) + cW / 2, y: parseFloat(allElement[i].style.top) + cH / 2 }); } }, /* * @method 点击小方块 * @param event Object 鼠标对象 * @ 1、点击当前非空白小方块 * @ 2、获取其坐标,并加减一个一个方块宽度,用这个加减坐标去检索空白小方块是否在目标小方块周边 * @ 3、如果在,则替换这两个小方块的坐标 */ mouseClick: function(event){ console.log(event) var event = event || window.event; var that = this; var target = event.target || event.srcElement; // 保证拖动的是想要的元素 if( target.parentElement.className.toLowerCase() == "item"){ var Element = target.parentElement; // 当当前点击目标为空白小方块时,终止函数 if(Element.getAttribute("data-index") == this.lastElement.sign){ return ; } // 存储当前元素的top,left var thisTop = parseFloat( Element.style.top ); var thisLeft = parseFloat( Element.style.left ); // 点击检测空白方块是否在当前对象周边 if(this.mouseClickCheck(thisTop, thisLeft)){ console.log(222) // 获取空白元素 var lastElement = document.getElementById(this.lastElement.Id); // 替换这两个元素的坐标 Element.style.top = lastElement.style.top; Element.style.left = lastElement.style.left; lastElement.style.top = thisTop + "px"; lastElement.style.left = thisLeft + "px"; this.lastElement.left = thisLeft ; this.lastElement.top = thisTop; // 消除层级问题 setTimeout(function(){ if(that.compareArray()){ alert("恭喜你,拼图成功!"); } }, 150); // 判断拼图完成 console.log(this.compareArray()) console.log(this.numberArr) } } return false; }, /* * @method 点击检测空白方块是否在当前对象周边 * @param thisTop Number 当前点击元素的top * @param thisLeft NUmber 当前点击元素的left * @return Boolean 是否在周边 */ mouseClickCheck: function(thisTop, thisLeft){ var cW = this.cW, cH = this.cH; if(thisTop == this.lastElement.top && (thisLeft - cH) == this.lastElement.left){ return true; } if(thisTop == this.lastElement.top && (thisLeft + cH) == this.lastElement.left){ return true; } if((thisTop - cW) == this.lastElement.top && thisLeft == this.lastElement.left){ return true; } if((thisTop + cW) == this.lastElement.top && thisLeft == this.lastElement.left){ return true; } return false; }, /* * @method 获取空白元素left,right */ getLastElement: function(){ // 获取空白元素 var lastElement = document.getElementById(this.lastElement.Id); console.log(this.lastElement); this.lastElement.left = parseFloat(lastElement.style.left) ; this.lastElement.top = parseFloat(lastElement.style.top); }, /* * @method 打乱小方块 * 以小方块的个数为次数,每次随机抽取两个小于小方块的数,然后替换两个dom元素的定位坐标 */ upsetElement: function(){ for (var i = 0; i < this.number-1; i++) { // 获取两个不相等的随机值 var n1 = Math.floor(Math.random()*this.number); var n2 = Math.floor(Math.random()*this.number); do{ n2 = Math.floor(Math.random()*this.number); }while(n1 == n2) // 替换当前的两个小方块的坐标 var allElement = this.Id.getElementsByClassName("item"); var Top = allElement[n1].style.top ; var Left = allElement[n1].style.left ; allElement[n1].style.top = allElement[n2].style.top ; allElement[n1].style.left = allElement[n2].style.left ; allElement[n2].style.top = Top ; allElement[n2].style.left = Left ; } }, /* * @method 比较小方块是否拼图完成 * @return boolean * 获取切换小方块后,获取小方块的序号并与正确排序数组进行比较 */ compareArray: function(){ // 获取序号 var allElement = this.Id.getElementsByClassName("item"); for(var i = 0; i < this.number-1; i++){ // 比较序号 if( this.numberArr[i].x != allElement[i].style.left || this.numberArr[i].y != allElement[i].style.top ){ return false; } } return true; }, } // 实例化一个对象 var box = new JigsawGame({ Id: 'canvasBox', imgUrl: '../image/lingtai.jpg', level: 1, gameType: 1 }); // 实例化一个对象 var box2 = new JigsawGame({ Id: 'canvasBox2', imgUrl: '../image/lingtai.jpg', level: 1, gameType: 2 }); function setGame(a, b){ document.getElementById("canvasBox").style.display = a; document.getElementById("canvasBox2").style.display = b; } setGame("block", "none");
在上述代码中只是稍微修改一下样式和触发事件,就是一个h5版本的demo。但有一点要注意,在设计代码时,并没有考虑到兼容性。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/128141.html
摘要:之前写过一篇基于的表格分页组件的文章,主要介绍了组件的编写方法,有兴趣的可以访问这里进行阅读前言为了进一步让大家了解的神奇魅力,了解的一种以数据为驱动的理念,本文主要利用实现了一个数字拼图游戏,其原理并不是很复杂,效果图如下展示地址为有能力 之前写过一篇《基于Vue.js的表格分页组件》的文章,主要介绍了Vue组件的编写方法,有兴趣的可以访问这里进行阅读:https://segment...
我们看看js实现简单拼图游戏的详细代码,HTML仅有一个id为game的div,也不错编写CSS,仅要img文件夹中放置一个图片文件就行,此处我放置的是LOL皇子的图片,图片名为'lol.png' <divid="game"> </div> 下面展示具体效果 多的不说,直接上js代码 /** *游戏配置 */ ...
摘要:基本需求有一个固定区域,被拆分成个同等大小的碎片,拿走其中一块,靠近缺口的块可以向缺口方向移动当拼出原来的图样视为完成。左右移动很简单,序号大的序号小的即可。 先不废话,请看演示。 showImg(https://segmentfault.com/img/bVyoj2);showImg(https://segmentfault.com/img/bVyoj5); 公司要搞这么个微信活动...
阅读 498·2023-03-27 18:33
阅读 706·2023-03-26 17:27
阅读 606·2023-03-26 17:14
阅读 575·2023-03-17 21:13
阅读 498·2023-03-17 08:28
阅读 1752·2023-02-27 22:32
阅读 1259·2023-02-27 22:27
阅读 2065·2023-01-20 08:28