使用js编写实现拼图游戏

2022-07-13,,

本文实例为大家分享了用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 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 鼠标对象
                 */
                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。由于没用到项目里,没有考虑兼容问题

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

《使用js编写实现拼图游戏.doc》

下载本文的Word格式文档,以方便收藏与打印。