本文实例为大家分享了用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 - <div style="margin: 0 auto;text-algin:center;">
- <button >拖拽模式</button>
- <button >点击模式</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 鼠标对象
- */
- 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 == thi.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。由于没用到项目里,没有考虑兼容问题
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持中国红客联盟。 |