zoukankan      html  css  js  c++  java
  • js原生图片拼图Demo

    自从找着了工作后已经有将近三个月没有写博客啦。最近在加强js的逻辑练习,所以收集了一些js小练习,手把手把它敲出来了。我把它记录下来,我的学习分享,嘿嘿。。。

    贴下界面:

                                          图一  界面

    这个拼图游戏主要分为几个步骤:

    (1)小图片列表切换,点击显示相应的大图(大图是由20张小图片拼连起来的)

    (2)点击开始游戏后,20张小图片随机排序

    (3)此时鼠标移到大图上显示移动状态,可以拖动,开始记录时间

    (4)碎片拼成原图后显示拼图成功以及所花的时间

    下面我来分解一下流程:

    (1)先展示html及css的代码:

     1 <!DOCTYPE html>
     2 <html>
     3     <head>
     4         <meta charset="utf-8">
     5         <title>拼图游戏</title>
     6         <style>
     7             body,ul,li{margin:0;padding:0;text-align: center;}
     8             body{font:30px/1.5 Tahoma;}
     9             #box{position:relative;width:1024px;height:768px;margin:10px auto;background:#808080;}
    10             #box li{float:left;width:256px;height:154px;overflow:hidden;}
    11             #box li img{width:256px;height:154px;}
    12             #box li.hig{width:256px;height:154px;overflow:hidden;border:2px dashed yellow;}
    13             #box li.hig img{width:256px;height:154px;opacity:0.5;filter:alpah(opacity=50);}
    14             #mask{position:absolute;top:0;left:0;width:1024px;height:768px;background:red;opacity:0;filter:alpha(opacity=0);}
    15             input{cursor:pointer;}
    16             #photo{text-align:center;margin:10px 0;}
    17             #photo img{width:100px;height:auto;border-radius:5px;margin:0 5px;opacity:0.5;filter:alpha(opacity=50);cursor:pointer;}
    18             #photo img.hover{opacity:1;filter:alpha(opacity=100);}
    19             #photo img.selected{border:2px solid yellow;width:96px;height:auto;opacity:1;filter:alpha(opacity=100);}
    20         </style>
    21     </head>
    22     <body>
    23         <div id="photo"><img src="img/flower/img_01.jpg" class="selected" /><img src="img/flower/img_02.jpg" /><img src="img/flower/img_03.jpg" /></div>
    24         <input type="button" value="开始游戏" id="play-btn"/>
    25         <ul id="box"></ul>
    26 </body>
    27 </html>
    View Code

    首先实现如下的效果:

    说明:鼠标悬浮到小图片上,图片透明度变为50%,点击图片,产生黄色边框,下面的大图也跟着变化,点击开始按钮,内容会变成重新开始

    js代码:

     1 var oPhoto=document.getElementById("photo");
     2 var aThumbImg=oPhoto.getElementsByTagName('img');
     3 var oStartBtn=document.getElementById("play-btn");
     4 var oBox=document.getElementById("box");
     5 var isRandom=false;
     6 var dirPath=0;
    var odata=[];
    7 for(var i=0;i<20;i++){ 8 var temp=i+1; 9 odata.push(temp); 10 } 11 for(var i=0;i<aThumbImg.length;i++){ 12 aThumbImg[i].index=i; 13 } 14 oPhoto.onmouseover=function(ev){ 15 var ev = ev || window.event; 16 var target = ev.target || ev.srcElement; 17 if(target.nodeName.toLowerCase()=='img'){ 18 target.className+=' hover'; 19 } 20 } 21 oPhoto.onmouseout=function(ev){ 22 var ev = ev || window.event; 23 var target = ev.target || ev.srcElement; 24 if(target.nodeName.toLowerCase()=='img'){ 25 target.className=target.className.replace(/shover/,''); 26 } 27 } 28 oPhoto.onclick=function(ev){ 29 var ev = ev || window.event; 30 var target = ev.target || ev.srcElement; 31 if(target.nodeName.toLowerCase()=='img'){ 32 for(var i=0;i<aThumbImg.length;i++){ 33 aThumbImg[i].className=''; 34 } 35 target.className='selected'; 36 dirPath=target.index; 37 oStartBtn.value='开始游戏'; 38 oBox.innerHTML="" 39 odata.sort(function(a,b){ 40 return a-b; 41 }); 42 43 } 44 } 45 oStartBtn.onclick=function(){ 46 this.value="重新开始"; 47 oBox.innerHTML=""; 48 }

    上面都是比较简单的,这个游戏的核心还是在于边界判断,移动上。

    (2)现在来实现拖动这一部分,先讲解onmousedown和onmousemove事件

    2.1 首先,还未开始游戏时,我设置了一层遮罩,就是不让其拖动,所以我们来建个遮罩层,也是放在id='box'里面,跟li同级。

    oPhoto.onclick=function(ev){
        creatMask();
    }
    
    function creatMask(){
        var mask=document.createElement('div');
        mask.id='mask';
        mask.style.zIndex=zIndex;
        oBox.appendChild(mask);                    
    }
    creatMask();

    当进入页面是生成遮罩层,点击小图片时,遮罩层还存在,只有点击开始游戏时,才会移除遮罩层。这时候,图片切块才能开始拖动。

    2.2 点击开始游戏,给图片切块注册onmousedown和onmousemove事件

     1 function drag(obj){
     2   obj.style.cursor='move';                      
    obj.onmousedown=function(event){ 3 var event=event||window.event; 4 event.preventDefault(); 5 var start_x=event.clientX-this.offsetLeft; 6 var start_y=event.clientY-this.offsetTop; 7 obj.style.zIndex = zIndex++;
        document.onmousemove=function(event){ 8 var event=event||window.event; 9 event.preventDefault(); 10 var iL=event.clientX-start_x; 11 var iT=event.clientY-start_y; 12 var maxL=obj.parentNode.clientWidth-obj.offsetWidth; 13 var maxT=obj.parentNode.clientHeight-obj.offsetHeight; 14 //边界判断 15 if(iL<0){iL=0;} 16 if(iT<0){iT=0;} 17 if(iL>maxL){iL=maxL;} 18 if(iT>maxT){iT=maxT;} 19 obj.style.left=iL+'px'; 20 obj.style.top=iT+'px'; 22 } 23 } 24 }

    上面的代码主要实现了图片拖动,且拖动范围不能超过box的范围。

    好了,现在要实现拖动的小块与周边的切片的碰撞检测,与之最近的切块显示黄色边框

    效果:

    这其中的原理是:  查找拖动块附近的最近的li,然后给li容器添加黄色边线。

    js代码:

    function findNear(obj){
                            var minLi=null;
                            var minNum=Number.MAX_VALUE;
                            var filterLi=[];
                            var aDistance=[];
                            for(var i=0;i<aLi.length;i++){
                                if(aLi[i]!=obj&&isButt(obj,aLi[i])){                                
                                    aDistance.push(getDistance(obj,aLi[i]));
                                    filterLi.push(aLi[i]);
                                }
                            }
                            var minNum=Number.MAX_VALUE;
                            //遍历查询最小值
                            for(var i=0;i<aDistance.length;i++){
                                if(aDistance[i]<minNum){
                                    minNum=aDistance[i];
                                    minLi=filterLi[i];
                                }
                            }
                            return minLi;
                        }    
    function isButt(obj1,obj2){
                        var l1=obj1.offsetLeft;
                        var lw1=obj1.offsetWidth+l1;
                        var t1=obj1.offsetTop;
                        var th1=obj1.offsetTop+t1;
                        
                        var l2=obj2.offsetLeft;
                        var lw2=obj2.offsetWidth+l2;
                        var t2=obj2.offsetTop;
                        var th2=obj2.offsetTop+t2;
                        //上下左右判断
                        return !(th2<t1||th1<t2||lw2<l1||lw1<l2);
                    }
                    function getDistance(obj1,obj2){
                        var dir_x=(obj1.offsetLeft+obj1.offsetWidth/2)-(obj2.offsetLeft+obj2.offsetWidth/2);
                        var dir_y=(obj1.offsetTop+obj1.offsetHeight/2)-(obj2.offsetTop+obj2.offsetHeight/2);
                        var dir=Math.sqrt(dir_x*dir_x+dir_y*dir_y);
                        return dir;
                    }            

    然后在onmousedown里面调用

    var oNear=null;
    for (i = 0; i < aLi.length; i++) aLi[i].className = "";
          oNear=findNear(obj);//返回一个最靠近obj的块
        //对最近的块显示黄色边框
          if(oNear){
               oNear.className='hig';
         }

    边界判断、isButt()函数、 findNear()函数和的分析图:

    (3)实现了移动拖动这一部分,那么鼠标释放时,又怎么实现拖动块与最近切片的位置交换呢。

    首先,得先清楚一点,取个例子:

    <ul id="box">
       <li>1</li>
       <li>2</li>
       <li>3</li>
    </ul>

    不管你怎么拖动里标签,改变的只是他的left和top,li标签在文档的先后顺序是不会改变的。那我们来看看li标签拖动过程的变化,如下图:

     

    js代码:

    document.onmouseup=function(event){
         document.onmousemove = null;//移除事件
         document.onmouseup = null;
         var event=event||window.event;
         event.preventDefault();
         //鼠标释放后碎片与目标碎片对换
         if(oNear){
            var obj_index=obj.index;
            obj.index=oNear.index;
            oNear.index=obj_index;
           //obj移动到oNear的位置
            startMove(obj,oPos[obj.index]);
            //oNear移动到obj的位置
            startMove(oNear,oPos[oNear.index],function(){
                //判断碎片是否还原成功
         //      console.log(finish());
                if(finish()){
                   alert('恭喜你,拼图游戏完美成功!!!');
                   creatMask();
                }                                        
            });
            oNear.className="";//移除黄色边框
         }else{
             //回到原位
             startMove(obj,oPos[obj.index]);
         }
    }
    function startMove(obj,pos,onEnd){ obj.timer=setInterval(function(){ doMove(obj,pos,onEnd); },30); }
    function doMove(obj,pos,onEnd){ var curOffsetLeft=obj.offsetLeft; var curOffsetTop=obj.offsetTop; //下面设置图片碎片每次向目标点移动的位移 var speedL=(pos.left-curOffsetLeft)/5; var speedT=(pos.top-curOffsetTop)/5; speedL=speedL>0 ? Math.ceil(speedL) : Math.floor(speedL); speedT=speedT>0 ? Math.ceil(speedT) : Math.floor(speedT); obj.style.left=(curOffsetLeft+speedL)+'px'; obj.style.top=(curOffsetTop+speedT)+'px'; //当obj的left等于对换oNear所保存的left,说明已经和它完全吻合了。此时移除计时器。 if(curOffsetLeft==pos.left && curOffsetTop==pos.top){ clearInterval(obj.timer); //如果传入回调函数,则执行回调函数 onEnd && onEnd(); // return; } } function finish(){ var success=true; var tempArr=[]; tempArr.length=0; for(var i=0;i<aLi.length;i++){ for(var j=0;j<aLi.length;j++){ if(i==aLi[j]['index']){ //li标签内图片的序号添加进数组 var img=aLi[j].getElementsByTagName('img')[0]; //返回匹配到的子集元素 var srcIndex=img.src.match(//(d+).jpg/)[1]; // console.log(srcIndex); tempArr.push(srcIndex); } } } for(var i=1;i<=tempArr.length;i++){ if(i!=tempArr[i-1]){ success=false; break; } } return success;
    }

    好啦,整个过程就是这样子。拿来练手还是不错的。

    demo中的图片碎片是我原先切好的,其实我本来是想将原图用程序裁切的,奈何技术不够,所以只能用ps处理了一下,这是我觉得比较遗憾的事啦,有兴趣的你可以实现一下呗。。。

    这里是demo的源代码地址:https://coding.net/u/U_can/p/puzzleGame/git

    
    
  • 相关阅读:
    scala之伴生对象的继承
    scala之伴生对象说明
    “Failed to install the following Android SDK packages as some licences have not been accepted” 错误
    PATH 环境变量重复问题解决
    Ubuntu 18.04 配置java环境
    JDBC的基本使用2
    DCL的基本语法(授权)
    ZJNU 1374
    ZJNU 2184
    ZJNU 1334
  • 原文地址:https://www.cnblogs.com/U-can/p/4975335.html
Copyright © 2011-2022 走看看