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>

欢迎交流学习!!!

不定时随缘更新。

原文地址:https://www.cnblogs.com/tcxq/p/10118927.html

时间: 2024-11-02 21:52:26

Canvas+Js制作动量守恒的小球碰撞的相关文章

HTML5 Canvas彩色小球碰撞运动特效

脚本简介 HTML5 Canvas彩色小球碰撞运动特效是一款基于canvas加面向对象制作的运动小球动画特效. 效果展示 http://hovertree.com/texiao/html5/39/ 效果图如下: 代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>HTML5 Canvas彩色小球碰撞运动特效

利用canvas制作乱跑的小球

canvas制作乱跑的小球 说明:将下面的代码放到html的body就可以,键盘控制上(W)下(S)左(A)右(D) <body> <canvas id="canvas" style="border: 1px solid #000;display: block;margin:30px auto;"></canvas> <script type="text/javascript"> var myCan

canvas:制作一个很炫的倒计时

canvas:制作一个很炫的倒计时 1.目的:     很多网站都会用到倒计时,如:天猫等.本文讲述的是一个用canvas实现的绚丽的倒计时. 2.原理: canvas标签类似于html的其他标签,<canvas></canvas>,canvas就相当于一张画布,可以在上面绘制各种自己想要的效果. 数字的点阵实现,利用0和1,0标示不填充,1表示用绿色小球填充.         <canvas id="canvas" width="1200&qu

小球碰撞墙壁----干掉误差

之前一直在沿用之前听课学来的"千篇一律"的小球碰撞墙壁或者地板的计算方法. 忽然发现,小球碰撞的时候,其实小球有一部分是进入了墙的里面,在小球速度并不快的情况下,或许不明显,但是当小球速度变的更快,小球半径也更大的时候,就没法看了 效果如下 代码如下(所有代码都只在chrome或者safari下能用,因为requestAnimationFrame方法我并没有写兼容): <!doctype html> <html> <head> <meta ch

js制作带有遮罩弹出层实现登录小窗口

要实现的效果如下 点击“登录”按钮后,弹出登录小窗口,并且有遮罩层(这个名词还是百度知道的,以前只知道效果,却不知道名字) 在没有点击“登录”按钮之前登录小窗口不显示,点击“登录”按钮后小窗口显示,并且遮罩层笼罩整个页面,使整个页面的其他元素暂时失去行为. 遮罩层的实现:相对于body绝对定位,宽度和高度都和body相同,并且有一定的透明度,使得下面的元素能够被看到.原先的元素的z-index为0,遮罩层的z-index在弹出登录小窗口和原先元素的之间. 说的不是很清楚,还是看代码吧! <!DO

html5 canvas+js实现ps钢笔抠图

html5 canvas+js实现ps钢笔抠图 1. 项目要求需要用js实现photoshop中钢笔抠图功能,就用了近三四天的时间去解决它,最终还是基本上把他实现了. 做的过程中走了不少弯路,最终一同事找到了canvans以比较核心的属性globalCompositeOperation = "destination-out", 属性可以实现通过由多个点构成的闭合区间设置成透明色穿透画布背景色或是背景图片,这样省了许多事. 2.实现效果: 鼠标点完之后会将所有的点连成闭合区间,并可自由拖

初学JS——利用JS制作的别踩白块儿(街机模式) 小游戏

初学JS--利用JS制作的别踩白块儿(街机模式) 小游戏 这个是上个星期5写的了,当时是突然想写个游戏,就想到了别踩白块儿,当时的想法是 可能普通模式的别踩白块儿因为他的"块儿"是滚动的向上这种,以我目前会的技术想不出怎么写, 但是如果是街机模式,通过你每按一次按键之后他像下跳一格这样的就非常好实现了. 通过我目前会的知识,实现的步骤大概是这样的: 建一个4X4的表格,制作2张150X100的图片,一张全白色,一张全黑色,命名为0.JPG,1.JPG 就是说当文件名为0的时候就是白色的

使用node.js制作简易爬虫

最近看了些node.js方面的知识,就像拿它来做些什么.因为自己喜欢摄影,经常上蜂鸟网,所以寻思了一下,干脆做个简单的爬虫来扒论坛的帖子. 直接上代码吧. 1 var sys = require("sys"), 2 http = require("http"), 3 fs = require("fs"); 4 var url = "http://newbbs.fengniao.com/forum/forum_125.html"

CSS3+Js制作的一款响应式导航条

今天制作了一个响应式导航条,能够自动随着不同的屏幕分辨率或浏览器窗口大小的不同而改变导航条的样式,这里主要用到的就是CSS3的Media Query.具体可以查看浅谈响应式布局这篇文章,这里就不花费大量的篇幅介绍了,主要看一下这个导航条该怎么做. 另外需要提到的是,ie6-ie8是不支持CSS3的Media Query的,因此对于ie6-ie8我们需要特殊处理,就让他们保持默认样式,这对于布局及样式上都要考虑到这一点. 首先看一下布局这一块,html代码如下: 1 2 3 4 5 6 7 8 9