zoukankan      html  css  js  c++  java
  • Canvas+Js制作动量守恒的小球碰撞

    目的:通过js实现小球碰撞并实现动量守恒

    canvas我们就不多说了,有用着呢。

    我们可以通过canvas画2D图形(圆、方块、三角形等等)3D图形(球体、正方体等待)。

    当然这只是基础的皮毛而已,canvas的强大之处在于可以做游戏,导入模型,粒子效果,实现漫游又或者全景和VR。

    这里我们介绍纯js写的2D小球碰撞。(主要是博主的Three.js不咋地)

    好吧,老规矩,先上图!

    额。。。很尴尬的是博主的截图功底不咋地,没有截下碰撞的瞬间。

    话不多说,开始教程。

    首先我们需要创建画布给它一个id方便后面监听处理。

    <body>
    <canvas id="myCanvas"></canvas>
    </body>

    然后是Js代码

    //声明画布大小为屏幕的1/3
        var width = window.innerWidth/3;
        var  height = window.innerHeight/3;
        var canvas = document.getElementById("myCanvas");
        canvas.width = width;
        canvas.height = height;
        //创建2d画笔
        var ctx = canvas.getContext("2d");
        //填充颜色设置为黑色(背景色)
        ctx.fillStyle = "#000";
        //将整个画布填充
        ctx.fillRect(0,0,width,height);

    这是Canvas最基本的操作,我们解释一下fillRect(x,y,width,height);这个函数。

    x和y填充的起始坐标点,width和height是填充区域的宽和高。

     由于我们创建的是带有物理性质的小球,所以我们用一个函数封装创建小球的代码。

    以后创建小球直接调用它就行了。

    function Ball(x,y,vx,vy,ax,ay,size,rou,color,ctx){
        //参数传值
        //x,y为坐标点 vx,vy为小球水平和垂直方向上的速度 ax,ay为加速度 
        //size 为大小 rou为密度 color颜色 ctx画笔
        this.x = x;
        this.y = y;
        this.vx = vx;
        this.vy = vy;
        this.rou = rou;
        this.size = size;
        this.ax = ax;
        this.ay = ay;
        this.m = Math.PI*this.size*this.size*rou;//求出质量
        
        this.draw = function(ctx){
            ctx.fillStyle=color;
            //console.log(this.x, this.y,this.size);
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.size, 0, Math.PI*2,false);//画圆
            ctx.fill();
            ctx.closePath();
        }
        this.draw(ctx);
    }

    接下来实例化出两个小球。

    //碰撞检测 动量守恒
        //x,y,vx,vy,ax,ay,size,rou,color,ctx
        var balla = new Ball(20,0.5*height,5,-3,0,0,8,1,"#ff0",ctx);
        var ballb = new Ball(width-20,0.5*height,-3,5,0,0,13,1,"#0ff",ctx);
        var ballc = new Ball(width/2,0.5*height,7,4,0,0,13,1,"#0ff",ctx);

    然后我们封装了一个函数来实现小球是实时更新。

    function animation(){
    
            //小球的速度等于速度加上加速度
            balla.vx+= balla.ax;
            balla.vy+=balla.ay;
            //小球的位移等于小球现在的坐标加上速度
            balla.x+= balla.vx;
            balla.y+=balla.vy;
    
            ballb.vx+= ballb.ax;
            ballb.vy+=ballb.ay;
            ballb.x+= ballb.vx;
            ballb.y+=ballb.vy;
            //基于距离的碰撞检测
            var pointdis=(balla.x-ballb.x)*(balla.x-ballb.x)+(balla.y-ballb.y)*(balla.y-ballb.y);//坐标距离
            var pointsize=(balla.size+ballb.size)*(balla.size+ballb.size);//半径距离
            if( pointdis <= pointsize)
            {
                console.log("haha");
                //这里是能量守恒公式
                var ballavx =((balla.m-ballb.m)*balla.vx+2*ballb.m*ballb.vx)/(balla.m+ballb.m);
                var ballavy =((balla.m-ballb.m)*balla.vy+2*ballb.m*ballb.vy)/(balla.m+ballb.m);
                var ballbvx=((ballb.m-balla.m)*ballb.vx+2*balla.m*balla.vx)/(balla.m+ballb.m);
                var ballbvy=((ballb.m-balla.m)*ballb.vy+2*balla.m*balla.vy)/(balla.m+ballb.m);
                balla.vx = ballavx;
                balla.vy = ballavy;
    
                ballb.vx = ballbvx;
                ballb.vy = ballbvy;
                //小Bug改进
                if(Math.abs(balla.vx-ballb.vx)<0.01&&Math.abs(balla.vy-ballb.vy)<0.01)
                {
                    console.log(balla.vx);
                    balla.vx=-balla.vx;
                    balla.vy=-balla.vy;
                    return;
                }
            }
            
            //判断是否碰撞到画布的边缘
            if(balla.x+balla.size>=width||balla.x-balla.size<=0)
            {
                balla.vx*=-0.98;
            }
            if(balla.y+balla.size>=height||balla.y-balla.size<=0)
            {
                balla.vy*=-0.98;
            }
    
            if(ballb.x+ballb.size>=width||ballb.x-ballb.size<=0)
            {
                ballb.vx*=-0.98;
            }
            if(ballb.y+ballb.size>=height||ballb.y-ballb.size<=0)
            {
                ballb.vy*=-0.98;
            }
            
            //清空画布,画出小球
            ctx.fillStyle = "#000";
            ctx.fillRect(0,0,width,height);
            balla.draw(ctx);
            ballb.draw(ctx);
            //console.log(ballb.vy);
    
        }

    最后我们让他30毫秒更新一次。

        setInterval(animation,30);

    OK,又大功告成了。自己动手试试吧!

    懒人福利!!!

    完整代码。

    <html>
    <head>
    <style>
    body{margin:0;}
    </style>
    </head>
    <body>
    <canvas id="myCanvas"></canvas>
    </body>
    <script>
        //声明画布大小为屏幕的1/3
        var width = window.innerWidth/3;
        var  height = window.innerHeight/3;
        var canvas = document.getElementById("myCanvas");
        canvas.width = width;
        canvas.height = height;
        //创建2d画笔
        var ctx = canvas.getContext("2d");
        //填充颜色设置为黑色(背景色)
        ctx.fillStyle = "#000";
        //将整个画布填充
        ctx.fillRect(0,0,width,height);
        
        //碰撞检测 动量守恒
        //x,y,vx,vy,ax,ay,size,rou,color,ctx
        var balla = new Ball(20,0.5*height,5,-3,0,0,8,1,"#ff0",ctx);
        var ballb = new Ball(width-20,0.5*height,-3,5,0,0,13,1,"#0ff",ctx);
        var ballc = new Ball(width/2,0.5*height,7,4,0,0,13,1,"#0ff",ctx);
        
        setInterval(animation,30);
        function animation(){
    
            //小球的速度等于速度加上加速度
            balla.vx+= balla.ax;
            balla.vy+=balla.ay;
            //小球的位移等于小球现在的坐标加上速度
            balla.x+= balla.vx;
            balla.y+=balla.vy;
    
            ballb.vx+= ballb.ax;
            ballb.vy+=ballb.ay;
            ballb.x+= ballb.vx;
            ballb.y+=ballb.vy;
            //基于距离的碰撞检测
            var pointdis=(balla.x-ballb.x)*(balla.x-ballb.x)+(balla.y-ballb.y)*(balla.y-ballb.y);//坐标距离
            var pointsize=(balla.size+ballb.size)*(balla.size+ballb.size);//半径距离
            if( pointdis <= pointsize)
            {
                console.log("haha");
                //这里是能量守恒公式
                var ballavx =((balla.m-ballb.m)*balla.vx+2*ballb.m*ballb.vx)/(balla.m+ballb.m);
                var ballavy =((balla.m-ballb.m)*balla.vy+2*ballb.m*ballb.vy)/(balla.m+ballb.m);
                var ballbvx=((ballb.m-balla.m)*ballb.vx+2*balla.m*balla.vx)/(balla.m+ballb.m);
                var ballbvy=((ballb.m-balla.m)*ballb.vy+2*balla.m*balla.vy)/(balla.m+ballb.m);
                balla.vx = ballavx;
                balla.vy = ballavy;
    
                ballb.vx = ballbvx;
                ballb.vy = ballbvy;
                //小Bug改进
                if(Math.abs(balla.vx-ballb.vx)<0.01&&Math.abs(balla.vy-ballb.vy)<0.01)
                {
                    console.log(balla.vx);
                    balla.vx=-balla.vx;
                    balla.vy=-balla.vy;
                    return;
                }
            }
            
            //判断是否碰撞到画布的边缘
            if(balla.x+balla.size>=width||balla.x-balla.size<=0)
            {
                balla.vx*=-0.98;
            }
            if(balla.y+balla.size>=height||balla.y-balla.size<=0)
            {
                balla.vy*=-0.98;
            }
    
            if(ballb.x+ballb.size>=width||ballb.x-ballb.size<=0)
            {
                ballb.vx*=-0.98;
            }
            if(ballb.y+ballb.size>=height||ballb.y-ballb.size<=0)
            {
                ballb.vy*=-0.98;
            }
            
            //清空画布,画出小球
            ctx.fillStyle = "#000";
            ctx.fillRect(0,0,width,height);
            balla.draw(ctx);
            ballb.draw(ctx);
            //console.log(ballb.vy);
    
        }
    function Ball(x,y,vx,vy,ax,ay,size,rou,color,ctx){
        //参数传值
        //x,y为坐标点 vx,vy为小球水平和垂直方向上的速度 ax,ay为加速度 
        //size 为大小 rou为密度 color颜色 ctx画笔
        this.x = x;
        this.y = y;
        this.vx = vx;
        this.vy = vy;
        this.rou = rou;
        this.size = size;
        this.ax = ax;
        this.ay = ay;
        this.m = Math.PI*this.size*this.size*rou;//求出质量
        
        this.draw = function(ctx){
            ctx.fillStyle=color;
            //console.log(this.x, this.y,this.size);
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.size, 0, Math.PI*2,false);//画圆
            ctx.fill();
            ctx.closePath();
        }
        this.draw(ctx);
    }
    </script>
    </html>

    欢迎交流学习!!!

    不定时随缘更新。

  • 相关阅读:
    谁是你随时可以说话的人
    我们在帝都这么拼,为的是什么?
    CVE-2016-4758: UXSS in Safari's showModalDialog
    JSON-SCHEMA
    JS城市data
    linux(centos )mongodb install
    python pip install
    基于chrome内核的UXSS
    Trying to hack Redis via HTTP requests
    Apache Solr 访问权限控制
  • 原文地址:https://www.cnblogs.com/tcxq/p/10118927.html
Copyright © 2011-2022 走看看