文章有点长但是对于想学习html5 canvas的人来说看完这篇文章是非常值得的。
在线演示地址:为了让百度快些收录,地址放在评论第一条
在这边我们将用到物理学上的速度,加速度,物理边界,碰撞定理,弹性碰撞(非弹性碰撞),动量守恒。
看到这么多是不是很有压力,下面就一一介绍并且最终结果我们将用这些技术制作一个简单的类似行星碰撞的画面(学了这些可以发挥自己的想象创作更有趣的东西比如台球游戏等等)。
1.形状的模拟:
各个物体形状我们用小球来实现定义为Shape类并具有属性原点(x,y)和小球的半径radius;
var Shape = function(x,y,radius)
{
this.x=x;
this.y=y;
this.radius=radius;
}
2.速度的模拟:
物理上的速度包括速率和方向,所以1中的Shape属性不够用我们要新增两个属性x轴和y轴方向速率(vX,vY),为了方便将Shape类命名为Asteroid类此时具有5个属性。
var Asteroid = function(x,y,radius,)
{
this.x=x;
this.y=y;
this.radius=radius;
this.vX=vX;
this.vY=vY;
}
3.模拟加速度:
如果你猜到了加速度和速度一样也是矢量的话那么加速度的类很容易定义新增两加速度的属性,(aX,aY)很容易的为Asteroid类添加这两个属性,这边自己写pass。
4.边界的模拟:
这里的边界指的是画布的上下边框和左右边框,既然明白了这一点那么就不难相到当物体的原点位置减去小球的半径就是距离画布的左边界的距离,以此类推,
假设我们定义了一个临时变量tempAsteroids用来保存小球,那么判断是否会出界是这样的:
if(tempAsteroids.x-tempAsteroids.radius < 0) 检测左边界
{
tempAsteroids.x = tempAsteroids.radius;
tempAsteroids.vX *= -1; 再不改变方向就要越界咯
tempAsteroids.aX *= -1; 这个效果类似与缓冲,自然地加速度会减下来
}
else if( tempAsteroids.x + tempAsteroids.radius > myCanvasWidh){ 检测右边界
tempAsteroids.x = myCanvasWidth - tempAsteroids.radius;
tempAsteroids.vX *= -1; 再不改变方向就要越界咯
tempAsteroids.aX *= -1; 这个效果类似与缓冲,自然地加速度会减下来
}
以上只检测了左右边界,还有上下边界的检测也是同样的道理,以此类推;
5.碰撞模拟:(此下要花点功夫了)
碰撞的模拟一般有两种模型矩形模拟和圆形模拟,矩形的相对简单,园比较难,如果这边你圆都看懂了,那么相信矩形的自己也一定可以模拟出来。
好了开始介绍两个圆是真碰撞的:
(1) 计算两个圆的圆心之间的距离,更直接的说就是判断两个圆的距离是否小于两个圆的半径之和;
(2) 圆心的位置在哪里?光计算半径了还不能确定圆的位置,如果不理解的话建议自己拿起笔来画画就知道了,那么怎么确定呢?
这里介绍数学中的勾股定理,原理就是知道两条边可以计算第三条边的长度。我们用两个圆心,x轴和y轴,以及两个圆心的连线(斜边)。
为了计算斜边先计算两个圆心的位置,定义dX和dY分别对应直角三角形的两直角边的长度斜边为distance;那么斜边的长度的计算就是:
for( var j=i+1;j<asteroidsLength;j++)
{ var tempAsteroidsB = asteroid[j];var dX = tempAsteroidsB.x - tempAsteroids.x;
var dY = tempAsteroidsB.y - tempAsteroids.y;
var distance = Math.sqrt((dX*dX)+(dY*dY)); //勾股定理计算斜边
if( distance < tempAsteroids.radius + tempAsteroidsB.radius) ///比较斜边与两圆心的距离
{
//这里后面提到,也就是怎么弹开的问题了
}
}
6.碰撞的形式:
在高中的时候我们学过碰撞有弹性正碰和非弹性碰撞,实际当中弹性正碰的情况很少,所以这里讨论复杂的非弹性碰撞。
这里处理费弹性碰撞的方法是旋转的方法,如果两个圆不上弹性正碰的话我们旋转让他们弹性正碰然后再旋转回去,听上去很复杂,实际上他就是很复杂,现在本人在应用的时候也就靠记忆和知道有这样的处理方法而已。下面是代码
if(distance<tempAsteroids.radius+tempAsteroidsB.radius)
{ /如果两圆重合,即会发生接触,则计算两圆之间的角度,在下面代码中计算的是负角///
var angle=Math.atan2(dy,dx);
var sine=Math.sin(angle);
var cosine=Math.cos(angle);
/将两圆旋转至水平方向
var x=0;
var y=0;
var xB=dx*cosine+dy*sine;
var yB=dy*cosine-dx*sine;
//旋转速度方向///
var vX=tempAsteroids.vX*cosine+tempAsteroids.vY*sine;
var vY=tempAsteroids.vY*cosine-tempAsteroids.vX*sine;
var vXb=tempAsteroidsB.vX*cosine+tempAsteroidsB.vY*sine;
var vYb=tempAsteroidsB.vY*cosine-tempAsteroidsB.vX*sine;
var vTotal=vX-vXb;
vX=((tempAsteroids.mass-tempAsteroidsB.mass)*vX+2*tempAsteroidsB.mass*vXb)/(tempAsteroids.mass+tempAsteroidsB.mass);
vXb=vTotal+vX;
分离两个物体///
xB=x+(tempAsteroids.radius+tempAsteroidsB.radius);
/将两个物体旋转至原来的位置/
tempAsteroids.x=tempAsteroids.x+(x*cosine-y*sine);
tempAsteroids.y=tempAsteroids.y+(y*cosine+x*sine);
tempAsteroidsB.x=tempAsteroidsB.x+(xB*cosine-yB*sine);
tempAsteroidsB.y=tempAsteroidsB.y+(yB*cosine+xB*sine);
tempAsteroids.vX=vX*cosine-vY*sine;
tempAsteroids.vY=vY*cosine+vX*sine;
tempAsteroidsB.vX=vXb*cosine-vYb*sine;
tempAsteroidsB.vY=vYb*cosine+vXb*sine;
}
好了碰撞检测完毕,下面是介绍动量守恒。
7.动量守恒的模拟:
如果你看到动量守恒这四个字,是不是发现光靠之前定义的Asteroid类还不能完成动量守恒,因为他和质量有关,如果你真想你了,你的思维很好用在IT里一定不错。
好了为之前的类增加质量属性mass就可以了。
好了所有的工作都ok了现在要做的就是你自己去查看源代码,为了方便以及将我的实例不值到新浪应用仓库了,自己用firebug查看源代码里面有注释,再结合本文就ok'了。
如果你认真看完本文的话不知道你有没有成就感,在高中学历那么多的物理知识却都没用上,现在用到了,我当时学习的时候就很兴奋。
如果你觉得本文不错谢谢转载,并请劳教注明作者博客来源,谢谢您的评论就是对我两个小时编辑本文最大的肯定。
本文链接:https://my.lmcjl.com/post/12301.html
4 评论