22
2020
04

js碰撞运动之无损碰撞

无损碰撞

  假设两个元素的碰撞,对元素的速度并不产生损耗,而只是改变元素速度方向

  假设元素一在与元素二碰撞前的瞬时速度是v,将该速度分解为平行于碰撞方向的速度v1和垂直于碰撞方向的速度v2

  碰撞发生后,碰撞方向的速度v1变成了反向的v1

  将反向的v1分解到水平方向v1x和垂直方向v1y

  将垂直于碰撞方向的速度v2分解到水平方向v2x和垂直方向v2y

    水平方向的速度vx = v2x - v1x

    垂直方向的速度vy = v2y - v1y

  元素二的速度分解形式与元素一类似,就不再赘述

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
<button id="btn1">开始运动</button>
<button id="reset">还原</button>
<div id="test1" style="height: 150px;width: 150px;background:pink;position:absolute;top:50px;left:50px;border-radius: 50%;"></div>
<div id="test2" style="height: 150px;width: 150px;background:orange;position:absolute;top:250px;left:250px;border-radius: 50%;"></div>
<script>
//声明元素的步长值
//步长值默认值为[-25,-20,-15,-10,-5,0,5,10,15,20]中的一个随机数
test1.stepX =  5*Math.floor(Math.random() * 10 - 5);
test1.stepY =  5*Math.floor(Math.random() * 10 - 5);
test2.stepX =  5*Math.floor(Math.random() * 10 - 5);
test2.stepY =  5*Math.floor(Math.random() * 10 - 5);
btn1.onclick = function(){
    collisionMove({
        obj:test1
    })
    collisionMove({
        obj:test2
    })
}
reset.onclick = function(){
    history.go();
}
function collisionMove(json){
    var obj = json.obj;
    var fn = json.fn;
    //声明x、y轴的当前值
    var curX,curY;
    //声明x、y轴方向
    var dirX = json.dirX;
    var dirY = json.dirY;
    dirX = obj.stepX > 0 ? '+' : '-';
    dirY = obj.stepY > 0 ? '+' : '-';
    //声明offset宽高
    var offsetWidth = obj.offsetWidth;
    var offsetHeight = obj.offsetHeight;
    //声明元素活动区域宽高
    var activeWidth = json.activeWidth;
    var activeHeight = json.activeHeight;
    //元素获取区域宽高默认值为可视区域宽高
    activeWidth = Number(activeWidth) || document.documentElement.clientWidth;
    activeHeight = Number(activeHeight) || document.documentElement.clientHeight;
    //声明left、top样式值
    var left,top;
    //清除定时器
    if(obj.timer){return;}
     //开启定时器
    obj.timer = setInterval(function(){
        //获取x、y轴的当前值
        curX = parseFloat(getCSS(obj,'left'));
        curY = parseFloat(getCSS(obj,'top'));
        bump(test1,test2);
        //更新left、top值
        left = curX + obj.stepX;
        top = curY + obj.stepY;
        //右侧碰壁前一刻,步长大于剩余距离,且元素向右运动时
        if((left > activeWidth - offsetWidth) && (dirX == '+')){
            left = activeWidth - offsetWidth;
        }
        //左侧碰壁前一刻,步长大于剩余距离,且元素向左运动时
        if((Math.abs(obj.stepX) > curX) && (dirX == '-')){
            left = curX;
        }
        //下侧碰壁前一刻,步长大于剩余距离,且元素向下运动时
        if((top > activeHeight - offsetHeight) && (dirY == '+')){
            top = activeHeight - offsetHeight;
        }
        //上侧碰壁前一刻,步长大于剩余距离,且元素向上运动时
        if((Math.abs(obj.stepY) > curY) && (dirY == '-')){
            top = curY;
        }
        obj.style.left= left + 'px';
        obj.style.top = top + 'px';
        //左侧或右侧碰撞瞬间
        if(left == activeWidth - offsetWidth || left == curX){
            obj.stepX = -obj.stepX;
        }
        //上侧或下侧碰撞瞬间
        if(top == activeHeight - offsetHeight || top == curY){
            obj.stepY = -obj.stepY;
        }
        //更新运动方向
        dirX = obj.stepX > 0 ? '+' : '-';
        dirY = obj.stepY > 0 ? '+' : '-';
    },20);            
}

function getCSS(obj,style){
    if(window.getComputedStyle){
        return getComputedStyle(obj)[style];
    }
    return obj.currentStyle[style];
} 
//碰撞检测函数
function bump(obj,objOther){
    /***动态元素***/
    obj.r = obj.offsetWidth/2;
    obj.x0 = parseFloat(getCSS(obj,'left')) + obj.r;
    obj.y0 = parseFloat(getCSS(obj,'top')) + obj.r;
    /**静态元素**/
    objOther.r = objOther.offsetWidth/2;
    objOther.x0 = parseFloat(getCSS(objOther,'left')) + objOther.r;
    objOther.y0 = parseFloat(getCSS(objOther,'top')) + objOther.r;
    //圆心之间的距离
    var len = Math.sqrt((obj.x0-objOther.x0)*(obj.x0-objOther.x0) + (obj.y0-objOther.y0)*(obj.y0-objOther.y0));
    //发生碰撞
    if(len <= obj.r + objOther.r){
    //碰撞方向与水平负方向的夹角a 
        var a = Math.atan(Math.abs((obj.y0-objOther.y0)/(obj.x0-objOther.x0)));
        stepChange(test1,test2,a);
        stepChange(test2,test1,a);
    }
}
//碰撞时,步长变化函数
function stepChange(obj,objOther,a){
    //步长合并
    obj.step = Math.sqrt(obj.stepX*obj.stepX + obj.stepY*obj.stepY);
    //假设总步长方向与x轴方向的夹角为b
    obj.b = Math.atan(Math.abs(obj.stepY/obj.stepX));
    //假设总步长方向与碰撞方向的夹角为c
    obj.c = Math.abs(a - obj.b);
    //步长分解
    //碰撞方向
    obj.step1 = obj.step*Math.cos(obj.c);
    //垂直方向
    obj.step2 = obj.step*Math.sin(obj.c);
    //按照运动元素(侵入元素)的起始运动方向对步长进行重新分解
    //左上
    if(obj.x0 <= objOther.x0 && obj.y0 <= objOther.y0){
        obj.stepX = -obj.step1*Math.cos(a) + obj.step2*Math.sin(a)
        obj.stepY = -obj.step1*Math.sin(a) - obj.step2*Math.cos(a)
    }
    //左下
    if(obj.x0 < objOther.x0 && obj.y0 > objOther.y0){
        obj.stepX = -obj.step1*Math.cos(a) + obj.step2*Math.sin(a)
        obj.stepY = obj.step1*Math.sin(a) + obj.step2*Math.cos(a) 
    }
    //右上
    if(obj.x0 > objOther.x0 && obj.y0 < objOther.y0){
        obj.stepX = obj.step1*Math.cos(a) - obj.step2*Math.sin(a)
        obj.stepY = -obj.step1*Math.sin(a) - obj.step2*Math.cos(a)
    }
    //右下
    if(obj.x0 > objOther.x0 && obj.y0 > objOther.y0){
        obj.stepX = obj.step1*Math.cos(a) - obj.step2*Math.sin(a)
        obj.stepY = obj.step1*Math.sin(a) + obj.step2*Math.cos(a)
    }
}
</script>        
	</body>
</html>

原文链接:https://www.qiquanji.com/post/8704.html

本站声明:网站内容来源于网络,如有侵权,请联系我们,我们将及时处理。

gzh

微信扫码关注

更新实时通知

« 上一篇 下一篇 »

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。