手记

原生js做的小demo,实现小球碰撞模拟(适配各种屏幕)

作者:liushuai

HTML:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>随机生成div</title>
<style>
html{
height: 100%;
}
body{
width:100%;
margin:0;
padding:0;
height:100%;
}
div.wrap{
height:100%;
position: relative;
overflow: hidden;
margin:0;
padding:0;

}

div:not(.wrap){
border-radius: 50%;
/*-webkit-animation:tanslateAni 5000ms infinite linear alternate;*/
/*transition: all 10000ms linear;*/
}
div:nth-of-type(2){
-webkit-animation-delay:2000ms;
}
div:nth-of-type(3){
-webkit-animation-delay:4000ms;
}
div:nth-of-type(4){
-webkit-animation-delay:-1000ms;
}

@-webkit-keyframes tanslateAni{
0% {-webkit-transform:rotate(10deg) translate3d(0px,0px,0)}
35% {-webkit-transform:rotate(0deg) translate3d(20px,0px,0)}
70% {-webkit-transform:rotate(-10deg) translate3d(0px,0px,0)}
100% {-webkit-transform:rotate(0deg) translate3d(-20px,0px,0)}
}
</style>
</head>
<body>
<div class="wrap" id='parent'></div>
<script src="ball.js">
</script>
</body>
</html>

js:

var elWidth=110;
var containerWidth;
var color=['red','green','blue','black','yellow'];//随机的颜色
var ballNum=20;
//var pageHeight=window.screen.height;
var pageHeight=document.body.clientHeight;
//var pageWidth=window.screen.width;
var pageWidth=document.body.clientWidth;
containerWidth=pageWidth;
var sizeRange=60;
var balls=[];

window.onload=function(){
    createBalls(elWidth+sizeRange,pageWidth,pageHeight,ballNum);
    setInterval(function(){ballHit(balls,pageWidth,pageHeight)},30)
}
//生成虚拟网格
function createTable(ballWidth,pageWidth,pageHeight){
    var col=Math.floor(pageWidth/ballWidth);
    var marginH=pageWidth%ballWidth;
    var marginV=pageHeight%ballWidth;
    var row=Math.floor(pageHeight/ballWidth);
    var total=col*row;
    var ballMap=[];
    for(var i=0;i<total;i++){//网格map存入一维数组
        //top、left值有较大偏差原因:/、%运算为小数,与Java不同
        ballMap[i]={left:marginH/2+Math.floor(i%col)*ballWidth,top:marginV/2+Math.floor(i/col)*ballWidth}
    }
    return ballMap;
}
//生成小球
var spaceIndex=25;
function createBalls(ballWidth,pageWidth,pageHeight,ballNum){
    var ballMap=createTable(ballWidth,pageWidth,pageHeight);
    var range=ballMap.length
    if(ballNum>=range-spaceIndex){
        ballNum=range-spaceIndex;
    }
    var ballsData=[];
    var ballIndex;

    ballIndex=getRandom(0,range,ballNum);

    for(var i=0;i<ballIndex.length;i++){
        ballsData[i]=ballMap[ballIndex[i]];
    }
    renderBalls(ballsData,ballNum);
}
//渲染小球
function renderBalls(ballData,ballNum){
    for(var i=0;i<ballNum;i++){
        var divBall=createEl('div')
        //(待改进),用面向对象方式改进
        balls.push({el:divBall,left:ballData[i].left,top:ballData[i].top,
            vx:Math.random()*6-3,vy:Math.random()*6-3,
            raduis:parseInt(divBall.style.width)/2});
    }
    for(var j=0;j<ballNum;j++){
        balls[j].el.style.left=balls[j].left+'px';
        balls[j].el.style.top=balls[j].top+'px';
    }
}

//随机数去重
function noRepeat(arr,newNum,range){
        var isRepeat=false;
        for(var i=0;i<arr.length;i++){
            if(newNum==arr[i]){
                isRepeat=true;
                break;
            }
        }
        if(isRepeat){
            newNum=Math.floor(Math.random()*range);
            noRepeat(arr,newNum,range);
        }else{
            return newNum;
        }
}

//随机数去重工具函数2
function getRandom(min,max,n){
    if (n > (max - min + 1) || max < min) {
        return null;
    }
    var result = [];
    var count = 0;
    while(count < n) {
        var num =Math.floor(Math.random() * (max - min)) + min;
        var flag = true;
        for (var j = 0; j < n; j++) {
            if(num == result[j]){
                flag = false;
                break;
            }
        }
        if(flag){
            result[count] = num;
            count++;
        }
    }
    return result;
}

//随机生成一个dom元素
function createEl(el,text){
    var elment=document.createElement(el);
    document.getElementById('parent').appendChild(elment);
    var len=Math.ceil(Math.random()*sizeRange);
    elment.style.width=len+elWidth+'px';
    elment.style.height=len+elWidth+'px';
    elment.style.backgroundColor=color[Math.floor(Math.random()*5)];
    elment.style.position='absolute';
    elment.innerHTML=text||"";
    return elment;
}

function moveBall(balls){
    for(var i=0;i<balls.length;i++){
        balls[i].left+=balls[i].vx;
        balls[i].top+=balls[i].vy;
        balls[i].el.style.left=balls[i].left+'px';
        balls[i].el.style.top=balls[i].top+'px';
    }
}

var spring= 1;//球与球之间弹性系数
var bounce=-1;//球与边缘之间弹性系数
function ballHit(balls,pageWidth,pageHeight){
    //检测边缘
    for(var i=0;i<balls.length;i++){
        if(balls[i].left<=0||balls[i].left>=pageWidth-2*balls[i].raduis){
            balls[i].vx*=bounce;
        }
        if(balls[i].top<=0||balls[i].top>=pageHeight-2*balls[i].raduis){
            balls[i].vy*=bounce;
        }
    }
    //检测小球与小球
    for (i=0;i<balls.length;i++) {
        var ball1=balls[i];
        ball1.x=ball1.left+ball1.raduis;
        ball1.y=ball1.top+ball1.raduis;
        for (j=i+1;j<balls.length;j++) {
            var ball2=balls[j];
            ball2.x=ball2.left+ball2.raduis;
            ball2.y=ball2.top+ball2.raduis;
            dx=ball2.x-ball1.x;
            dy=ball2.y-ball1.y;
            var dist=Math.sqrt(dx*dx + dy*dy);
            var misDist=ball1.raduis+ball2.raduis;
            if(dist < misDist) {
                var angle=Math.atan2(dy,dx);
                tx=ball1.x+Math.cos(angle) * misDist;
                ty=ball1.y+Math.sin(angle) * misDist;
                ax=(tx-ball2.x) * spring;
                ay=(ty-ball2.y) * spring;
                ball1.vx-=ax;
                ball1.vy-=ay;
                ball2.vx+=ax;
                ball2.vy+=ay;
            }
        }
    }
    moveBall(balls);
}
15人推荐
随时随地看视频
慕课网APP

热门评论

试了的,还是有bug,让小球运动长点就会出现沿着边框不规则运动,甚至会跑出边框,跟我的一样

查看全部评论