zoukankan      html  css  js  c++  java
  • (canvas)两小球碰撞后的速度问题研究

    这两天在研究canvas碰撞

    先把小球开始运动的图拿出来

    参考了一下别的的代码,在两个小球碰撞处理上,我觉得不完善

    怎么样处理才算完善呢,当然是要用高中物理学的动量守恒了和机械能守恒了

    机械能守恒我其实忘了,特地百度了下

    用高中老师的话就是,联立,解得,PS:结果我是网上找的,也存在看错的可能

     碰撞的逻辑我来简要所以下

    1.当小球撞到墙,对应的x轴或者y轴的速度成 -1,效果是反弹

    2.当两个小球碰撞时,由上面的公式,我们会分别计算speedX和speedY

    由于动量守恒,我们再效果图中能发现,同一方向相撞,小球会马上获得一个大的速度,而打球减速并不明显

    最后慢慢传递,很多球都停止了,但是最后一般来说,还是有一个球载运动的

     

    最后小球还是会有重叠的情况,我再分析下。。。

    我觉得像子弹打物块一样,接触物体的发生了变化,但是子弹还是有向前的速度,且速度比物块大

    两个小球接触的时候也是这样,球1撞到球2,但是球1的速度还是比2快,于是球1就叠到球2上了

    然后在叠的过程中,在逻辑里还是处于碰撞,还在发生能量转移。

    事实证明,叠起来的球过了几秒就静止了,

    通常是速度大的小球,接触到速度小的大球,接触后小球的速度还是别大球快。于是叠在一起,叠在一起后,还在进行能量转换,最后保持平衡,

    静止,或者用同样的速度运行。所以出现了叠在一起不分开的情况

    当一个小球的速度够快,碰撞大球的时候才会出现以上情况

    当我把球的半径改成一样

    应该就不会发生了

    <script type="text/javascript">
        var canvas = document.getElementById("canvas1");
        var ctx = canvas.getContext("2d");
        //随机函数
        function randomNum (m,n) {
            return Math.floor(Math.random() * (n - m + 1) + m);
        }
        //创建小球类
        function Ball () {
            //随机小球半径
            this.r = randomNum(20,30);
            //随机颜色
            this.color = 'rgb(' + randomNum(0,255) + ',' + randomNum(0,255) + ',' + randomNum(0,255) + ')';
            //随机小球的位置
            this.x = randomNum(this.r,canvas.width-this.r);
            this.y = randomNum(this.r,canvas.height-this.r);
            //小球速度X轴1和-1;
            this.speedX = randomNum(2,5) * randomNum(0,1) ? 1 : -1;
            this.speedY = randomNum(2,5) * randomNum(0,1) ? 1 : -1;
    
        }
        //小球移动
        Ball.prototype.move = function () {
            this.x += this.speedX;
            this.y += this.speedY;
            //判断是否碰到边界
            //左边界
            if (this.x <= this.r) {
                this.x = this.r;
                //反弹
                this.speedX *= -1;
            }
            //右边界
            if (this.x >= canvas.width-this.r) {
                this.x = canvas.width-this.r;
                this.speedX *= -1;
            }
            if (this.y <= this.r) {
                this.y = this.r;
                this.speedY *= -1;
            }
            if (this.y >= canvas.height-this.r) {
                this.y = canvas.height-this.r;
                this.speedY *= -1;
            }
        }
        //绘制小球
        Ball.prototype.drawBall = function () {
            ctx.beginPath();
            ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);
            ctx.fillStyle = this.color;
            ctx.fill();             
        }
        //创建小球的对象
        var balls = [];
        for (var i = 0;i < 5;i++) {
            var ball = new Ball();
            balls.push(ball);
        }
        //让小球移动
        setInterval(function () {
            ctx.clearRect(0,0,canvas.width,canvas.height);
            for (var i = 0;i < balls.length;i++) {
                balls[i].move();
                balls[i].drawBall();
                //移动后检测小球碰撞反弹
                for (j = 0;j < balls.length;j++) {
                    //判断不是同一个球
                    if (balls[i] == balls[j]) {
                        continue;//不做碰撞检测
                    }
                    //碰撞检测
                    if (ballCrash(balls[i],balls[j])) {
                        /*
                         1.物理公式动量守恒,假设每个球的质地均匀,那么小球的质量与半径有关
                         2.我们用1一次方的算法,实际平面球质量和r的平方有关,立体球和r的三次方有关
                         3.由动量守恒,m1*v1+m2*v2=m1*v1'+m2*v2'
                         4.机械能守恒,平方我就不写了,两个方程联立
                         */
                        var fzx=(balls[i].r - balls[j].r)*balls[i].speedX + 2*balls[j].r*balls[j].speedX;
                        var fzx2=2*balls[i].r*balls[i].speedX+(balls[i].r - balls[j].r)*balls[j].speedX;
                        var fzy=(balls[i].r - balls[j].r)*balls[i].speedY + 2*balls[j].r*balls[j].speedY;
                        var fzy2=2*balls[i].r*balls[i].speedY+(balls[i].r - balls[j].r)*balls[j].speedY;
                        var fm=balls[i].r + balls[j].r;
    
                        balls[i].speedX=(fzx/fm);
                        balls[i].speedY=(fzy/fm);
                        balls[j].speedX=(fzx2/fm);
                        balls[j].speedY=(fzy2/fm);              
                    }
                }
            }
        },0.1)
      
    
        //碰撞检测
        function ballCrash (ball1,ball2) {
            //两个小球之间的距离
            var distance = Math.sqrt(Math.pow(ball1.x - ball2.x,2) + Math.pow(ball1.y - ball2.y,2));
            //两球的距离小于两个半径的和即为碰撞
            if (distance <= ball1.r + ball2.r) {
                return true;//碰撞
            } else{
                return false;//没有碰撞
            }
        }
    </script>
    

    重叠的情况用下面代码可以避免,但是有时候会出别的bug

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>小球碰撞反弹</title>
        <style type="text/css">
            #canvas1{
                border: 4px dashed black;
                margin: 0 auto;
                display: block;
            }
        </style>
    </head>
    <body>
        <canvas id="canvas1" width="600" height="600"></canvas>
    </body>
    <script type="text/javascript">
        var canvas = document.getElementById("canvas1");
        var ctx = canvas.getContext("2d");
        //随机函数
        function randomNum (m,n) {
            return Math.floor(Math.random() * (n - m + 1) + m);
        }
        //创建小球类
        function Ball () {
            //随机小球半径
            this.r = randomNum(15,30);
            //随机颜色
            this.color = 'rgb(' + randomNum(0,255) + ',' + randomNum(0,255) + ',' + randomNum(0,255) + ')';
            //随机小球的位置
            this.x = randomNum(this.r,canvas.width-this.r);
            this.y = randomNum(this.r,canvas.height-this.r);
            //小球速度X轴1和-1;
            this.speedX = randomNum(2,5) * randomNum(0,1) ? 1 : -1;
            this.speedY = randomNum(2,5) * randomNum(0,1) ? 1 : -1;
    
        }
        //小球移动
        Ball.prototype.move = function () {
            this.x += this.speedX;
            this.y += this.speedY;
            //判断是否碰到边界
            //左边界
            if (this.x <= this.r) {
                this.x = this.r;
                //反弹
                this.speedX *= -1;
            }
            //右边界
            if (this.x >= canvas.width-this.r) {
                this.x = canvas.width-this.r;
                this.speedX *= -1;
            }
            if (this.y <= this.r) {
                this.y = this.r;
                this.speedY *= -1;
            }
            if (this.y >= canvas.height-this.r) {
                this.y = canvas.height-this.r;
                this.speedY *= -1;
            }
        }
        //绘制小球
        Ball.prototype.drawBall = function () {
            ctx.beginPath();
            ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);
            ctx.fillStyle = this.color;
            ctx.fill();             
        }
        //创建小球的对象
        var balls = [];
        for (var i = 0;i < 10;i++) {
            var ball = new Ball();
            balls.push(ball);
        }
        //让小球移动
        setInterval(function () {
            ctx.clearRect(0,0,canvas.width,canvas.height);
            for (var i = 0;i < balls.length;i++) {
                balls[i].move();
                balls[i].drawBall();
                //移动后检测小球碰撞反弹
                for (j = 0;j < balls.length;j++) {
                    //判断不是同一个球
                    if (balls[i] == balls[j]) {
                        continue;//不做碰撞检测
                    }
                    //碰撞检测
                    if (ballCrash(balls[i],balls[j])) {
                   
                        /*
                         1.物理公式动量守恒,假设每个球的质地均匀,那么小球的质量与半径有关
                         2.我们用1一次方的算法,实际平面球质量和r的平方有关,立体球和r的三次方有关
                         3.由动量守恒,m1*v1+m2*v2=m1*v1'+m2*v2'
                         4.机械能守恒,平方我就不写了,两个方程联立
                         */
                        var fzx=(balls[i].r - balls[j].r)*balls[i].speedX + 2*balls[j].r*balls[j].speedX;
                        var fzx2=2*balls[i].r*balls[i].speedX+(balls[i].r - balls[j].r)*balls[j].speedX;
                        var fzy=(balls[i].r - balls[j].r)*balls[i].speedY + 2*balls[j].r*balls[j].speedY;
                        var fzy2=2*balls[i].r*balls[i].speedY+(balls[i].r - balls[j].r)*balls[j].speedY;
                        var fm=balls[i].r + balls[j].r;
    
                        balls[i].speedX=(fzx/fm);
                        balls[i].speedY=(fzy/fm);
                        balls[j].speedX=(fzx2/fm);
                        balls[j].speedY=(fzy2/fm);              
                    }
                }
            }
        },1)
      
    
        //碰撞检测
        function ballCrash (ball1,ball2) {
    
            //两个小球之间的距离
            var distance = Math.sqrt(Math.pow(ball1.x - ball2.x,2) + Math.pow(ball1.y - ball2.y,2));
            //两球的距离小于两个半径的和即为碰撞
            if (distance == ball1.r + ball2.r) {
    
                return true;//碰撞
            }else if( distance < ball1.r + ball2.r){
                if(Math.pow(ball1.speedX,2)+Math.pow(ball1.speedY,2)>Math.pow(ball2.speedX,2)+Math.pow(ball2.speedY,2)){
                    if(ball1.speedX>0){
                        ball2.x=ball2.x+ball1.r + ball2.r - distance;
                        if(ball1.speedY > 0){
                            ball2.y=ball2.y+ball1.r + ball2.r - distance;
                        }else{
                            ball2.y=ball2.y-ball1.r - ball2.r + distance;
                        }
                    }else{
                         ball2.x=ball2.x-ball1.r - ball2.r + distance;
                         if(ball1.speedY > 0){
                            ball2.y=ball2.y+ball1.r + ball2.r - distance;
                        }else{
                            ball2.y=ball2.y-ball1.r - ball2.r + distance;
                        }
                    }
                    
               }else{
                    if(ball2.speedX>0){
                        ball1.x=ball1.x+ball1.r + ball2.r - distance;
                        if(ball2.speedY > 0){
                            ball1.y=ball1.y+ball1.r + ball2.r - distance;
                        }else{
                            ball1.y=ball1.y-ball1.r - ball2.r + distance;
                        }
                    }else{
                         ball1.x=ball1.x-ball1.r - ball2.r + distance;
                         if(ball2.speedY > 0){
                            ball1.y=ball1.y+ball1.r + ball2.r - distance;
                        }else{
                            ball1.y=ball1.y-ball1.r - ball2.r + distance;
                        }
                    }
               }
               return true;
            }
            else{
                return false;//没有碰撞
            }
        }
    
    </script>
    </html> 
    
  • 相关阅读:
    初学mysql数据库
    类与对象课堂总结
    CNN网络的基本介绍(三)
    CNN网络的基本介绍(二)
    CNN网络的基本介绍(一)
    Android studio界面布局的简单介绍
    Android studio初见及结构分析
    JDBC实现Mysqual的增删改查
    BufferedReader统计TXT文本
    JAVA的异常处理
  • 原文地址:https://www.cnblogs.com/anxiaoyu/p/6707836.html
Copyright © 2011-2022 走看看