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>

    欢迎交流学习!!!

    不定时随缘更新。

  • 相关阅读:
    javaweb请求编码 url编码 响应编码 乱码问题 post编码 get请求编码 中文乱码问题 GET POST参数乱码问题 url乱码问题 get post请求乱码 字符编码
    windows查看端口占用 windows端口占用 查找端口占用程序 强制结束端口占用 查看某个端口被占用的解决方法 如何查看Windows下端口占用情况
    javaWeb项目中的路径格式 请求url地址 客户端路径 服务端路径 url-pattern 路径 获取资源路径 地址 url
    ServletRequest HttpServletRequest 请求方法 获取请求参数 请求转发 请求包含 请求转发与重定向区别 获取请求头字段
    HttpServletResponse ServletResponse 返回响应 设置响应头设置响应正文体 重定向 常用方法 如何重定向 响应编码 响应乱码
    Servlet主要相关类核心类 容器调用的过程浅析 servlet解读 怎么调用 Servlet是什么 工作机制
    linq查询语句转mongodb
    winddows rabbitmq安装与配置
    Redis For Windows安装及密码
    出现,视图必须派生自 WebViewPage 或 WebViewPage错误解决方法
  • 原文地址:https://www.cnblogs.com/tcxq/p/10118927.html
Copyright © 2011-2022 走看看