javascript動畫系列第三篇——碰撞檢測


前面的話

  前面分別介紹了拖拽模擬磁性吸附,當可視區域內存在多個可拖拽元素,就出現碰撞檢測的問題,這也是javascript動畫的一個經典問題。本篇將詳細介紹碰撞檢測

 

原理介紹

  碰撞檢測的方法有很多,接下來使用九宮格分析法

  假設黃色元素要與紅色元素進行碰撞。將紅色元素所處的區域分為9部分,自身處於第9部分,周圍還存在8個部分。只要黃色元素進入紅色元素的第9部分,就算碰撞。否則,都算未碰撞

  總共分為以下5種情況:

  1、處於上側未碰撞區域——1、2、3區域

  2、處於右側未碰撞區域——3、4、5區域

  3、處於下側未碰撞區域——5、6、7區域

  4、處於左側未碰撞區域——1、7、8區域

  5、處於碰撞區域——9區域

 

代碼實現

  我們把上面的原理用代碼實現

function bump(obj,objOther,bgColor){

    /***被碰元素***/
    //被碰元素左側距離可視區域左側的距離
    var L0 = obj.offsetLeft;
    //被碰元素上側距離可視區域上側的距離
    var T0 = obj.offsetTop;
    //被碰元素右側距離可視區域右側的距離
    var R0 = obj.offsetLeft + obj.offsetWidth;
    //被碰元素下側距離可視區域下側的距離
    var B0 = obj.offsetTop + obj.offsetHeight;
    /**侵入元素**/
    var L = objOther.offsetLeft;
    var T = objOther.offsetTop;
    var R = objOther.offsetLeft + objOther.offsetWidth;
    var B = objOther.offsetTop + objOther.offsetHeight;    

    /*******碰撞檢測*******/
    //上側區域if(B < T0)
    //左側區域if(R < L0)
    //右側區域if(L > R0)
    //下側區域if(T > B0)
    
    //碰撞區域
    if(B >= T0 && R >= L0 && L <= R0 && T <= B0){
        obj.style.backgroundColor = 'red';
    }else{
        obj.style.backgroundColor = bgColor;
    }
}

 

完整效果

<div id="test1" style="height: 100px;width: 100px;background:pink;position:absolute;top:0;left:0;">元素一</div>
<div id="test2" style="height: 100px;width: 100px;background:orange;position:absolute;top:150px;left:150px;">元素二</div>
<script>
function addEvent(target,type,handler){
    if(target.addEventListener){
        target.addEventListener(type,handler,false);
    }else{
        target.attachEvent('on'+type,function(event){
            return handler.call(target,event);
        });
    }
}
function getCSS(obj,style){
    if(window.getComputedStyle){
        return getComputedStyle(obj)[style];
    }
    return obj.currentStyle[style];
}    
function bump(obj,objOther){
    bump.objBGColor = (bump.objBGColor === undefined) ? getCSS(obj,'backgroundColor') : bump.objBGColor;
    bump.objOtherBGColor = (bump.objOtherBGColor === undefined) ? getCSS(objOther,'backgroundColor') : bump.objOtherBGColor;    
    /***被碰元素***/
    //被碰元素左側距離可視區域左側的距離
    var L0 = obj.offsetLeft;
    //被碰元素上側距離可視區域上側的距離
    var T0 = obj.offsetTop;
    //被碰元素右側距離可視區域右側的距離
    var R0 = obj.offsetLeft + obj.offsetWidth;
    //被碰元素下側距離可視區域下側的距離
    var B0 = obj.offsetTop + obj.offsetHeight;
    /**侵入元素**/
    var L = objOther.offsetLeft;
    var T = objOther.offsetTop;
    var R = objOther.offsetLeft + objOther.offsetWidth;
    var B = objOther.offsetTop + objOther.offsetHeight;    

    /*******碰撞檢測*******/
    //上側區域if(B < T0)
    //左側區域if(R < L0)
    //右側區域if(L > R0)
    //下側區域if(T > B0)
    
    //碰撞區域
    if(B >= T0 && R >= L0 && L <= R0 && T <= B0){
        obj.style.backgroundColor = objOther.style.backgroundColor ='red';
    }else{
        obj.style.backgroundColor = bump.objBGColor;
        objOther.style.backgroundColor = bump.objOtherBGColor;

    }
}

function drag(ele){
    var x0,y0,x1,y1,isMoving;
    var L0,R0,T0,B0,EH,EW;

    var mousedownHandler = function(e){
        e = e || event;
        //獲取元素距離定位父級的x軸及y軸距離
        x0 = this.offsetLeft;
        y0 = this.offsetTop;
        //獲取此時鼠標距離視口左上角的x軸及y軸距離
        x1 = e.clientX;
        y1 = e.clientY;
        //按下鼠標時,表示正在運動
        isMoving = true;
        //鼠標按下時,獲得此時的頁面區域
        L0 = 0;
        R0 = document.documentElement.clientWidth;
        T0 = 0;
        B0 = document.documentElement.clientHeight;
        //鼠標按下時,獲得此時的元素寬高
        EH = ele.offsetHeight;
        EW = ele.offsetWidth;
    }
    var mousemoveHandler = function(e){
        //如果沒有觸發down事件,而直接觸發move事件,則函數直接返回
        if(!isMoving){
            return;
        }
        e = e || event;
        //獲取此時鼠標距離視口左上角的x軸及y軸距離
        var x2 = e.clientX;
        var y2 = e.clientY;   
        //計算此時元素應該距離視口左上角的x軸及y軸距離
        var X = x0 + (x2 - x1);
        var Y = y0 + (y2 - y1);        
        /******范圍限定*******/
        //獲取鼠標移動時元素四邊的瞬時值
        var L = X;
        var R = X + EW;
        var T = Y;
        var B = Y + EH;
        //在將X和Y賦值給left和top之前,進行范圍限定。只有在范圍內時,才進行相應的移動
        //如果脫離左側范圍,則left置L0
        if(L < L0){X = L0;}
        //如果脫離右側范圍,則left置為R0
        if(R > R0){X = R0 - EW;}
        //如果脫離上側范圍,則top置T0
        if(T < T0){Y = T0;}
        //如果脫離下側范圍,則top置為B0
        if(B > B0){Y = B0 - EH;}

        //將X和Y的值賦給left和top,使元素移動到相應位置
        ele.style.left = X + 'px';
        ele.style.top = Y + 'px';

        bump(test2,test1);
    }
    var mouseupHandler = function(e){
        //鼠標抬起時,表示停止運動
        isMoving = false;
        //釋放全局捕獲
        if(ele.releaseCapture){
            ele.releaseCapture();
        }
    }
    var preventDefaultHandler = function(e){
        e = e || event;
        if(e.preventDefault){
            e.preventDefault();
        }else{
            e.returnValue = false;
        }
        //IE8-瀏覽器阻止默認行為
        if(ele.setCapture){
            ele.setCapture();
        }

}
addEvent(ele,'mousedown',mousedownHandler);
addEvent(ele,'mousedown',preventDefaultHandler);
addEvent(document,'mousemove',mousemoveHandler)
addEvent(document,'mouseup',mouseupHandler)

};

drag(test1);
drag(test2);
</script>    

 

源碼查看


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM