使用js编写实现拼图游戏
本文实例为大家分享了用js编写实现拼图游戏的具体代码,供大家参考,具体内容如下
目标
【使用js编写实现拼图游戏】使用原生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
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 = https://www.it610.com/article/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 = ""; 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,leftvar 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,leftvar 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。由于没用到项目里,没有考虑兼容问题
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
推荐阅读
- 网络编程详解
- C语言进阶知识|【C语言字符和字符串的库函数的使用注意事项和模拟】
- vue.js|毕业实习:Vue+Springboot+MySQL实现的订餐系统
- 为什么要使用在线文档协作工具()
- React|React Table 表格组件使用教程 排序、分页、搜索过滤筛选功能实战开发
- 在矩池云使用Disco|在矩池云使用Disco Diffusion生成AI艺术图
- 自动化测试|jmeter使用心得(一)
- Kali Linux下信息搜集工具(命令)使用总结
- 使用js提取url中的参数
- python实现自动生成C++代码的代码生成器