基于Win API,通过算法实现圆与鼠标指针(点)的碰撞的模拟

来源:互联网 发布:ios软件开发教程 编辑:程序博客网 时间:2024/05/17 22:51
最近稍微研究了一下通过移动鼠标指针来与一个二维球(就是个圆)碰撞的算法,一开始的思路是通过纯几何+物理公式的方式来实现功能,但是后来发现这样实现起来实在是很复杂,用了太多的三角函数,而且还设计到了很多不同情况的处理。后来想到了物理当中力的传导本质上是两个矢量的相加和相减,试了一下用矢量的方式来表示碰撞情况,果然比纯几何的要简单很多,计算也简单了一些,如果有更好的算法也各位看官也可以探讨一下。

先明确几个概念。首先,在Win API编程当中,屏幕的坐标空间和平时物理上用的坐标空间是不一样的


由于在电脑屏幕上y轴的正方向与一般的物理坐标系y轴方向是相反的,因此在一些涉及到方向的计算当中要额外注意一下


其次在本次表达速度的时候,都是通过x轴方向速度和y轴方向速度结合的矢量来表达的


下面进入正题

碰撞的触发条件是通过不断获取指针坐标,当指针与圆的距离小于圆的半径时,即满足触发条件

<span style="white-space:pre"></span>double Distance = sqrt(double(pow((double)(nowCursor.x - currpt.x), 2) + pow((double)(nowCursor.y - currpt.y), 2)));if(Distance <= DIAMETER){if(InCircleFlag == FALSE){Speed_Pollo = CalVectorSpeed();InCircleFlag = TRUE;}}
那么在触发了碰撞的那一刻,指针相对于圆心的坐标就成为了碰撞的方向,由于指针是不会被弹走的,所以在这里是完全弹性碰撞,那么当指针不动时,给圆的力如下图所示

假设是理想情况,碰撞的面永远只有这一个点,那么给予圆的力的方向永远是指向圆心的方向,那么多余的没有指向圆心方向的力就会提供给旋转,旋转在本篇先不(mei)讨(nong)论(hao)了。

由于刷新率的问题,碰撞肯定不是刚好在边上的,但是在这里这个碰撞点提供的只是一个方向,因此跟是不是在边上没关系,只要指向圆心就行了。
那么这个弹力的大小要怎么算呢,由于是完全弹性碰撞,因此圆本身的速度在这个弹力方向上的分量不仅被完全抵消,而且还被完全弹了回来。

最后得出的2a,就是当指针不动时,圆撞到指针上获得的速度大小和方向。但是由于圆本身就有一个速度,因此撞完之后肯定不是完全按照速度a的方向来走,那么这里就用到了矢量相减


以上所有图的速度都是用矢量表示,因此长度就代表大小,箭头所指方向就是速度方向

现在概念大概理解了,就要开始算啦

计算所有向量角度的函数

double Action::CalVectorAngle(SPEED Vector){double Angle = atan((double)(Vector.ySpeed/(Vector.xSpeed + 0.0001)));//为了防止除以0//arctan值域为-2/PI到2/PI,无法表达所有角度,因此要根据相对位置来加减角度得到真实角度if (Vector.xSpeed < 0 && Vector.ySpeed >= 0){Angle = Angle + PI;}else if (Vector.xSpeed < 0 && Vector.ySpeed < 0){Angle = Angle - PI;}return Angle;}
在这里说明一下角度与实际的区别


接下来就可以开始着手计算2a所表示的速度矢量了,算出来2a之后b的速度矢量也直接就出来了。

等了个等,为什么要说计算2a的就能直接得出b的速度。因为他们的所指向的点是同一个点呀,所以算出2a就等于算出b,但是算出b其实并不是最后实际的速度,因为在他的起点不是从圆心开始。因此在算出b之后,还应当在v'的方向上进行一个平移,把起点移动到圆心,才是我们最终的速度向量b'


b'就是我们最后要的速度矢量了

下面贴代码

SPEED Action::CalVectorSpeed(){//总是叫圆不好听,叫个Pollo好了SPEED CursorImpect;//指针碰撞时的矢量CursorImpect.xSpeed = nowCursor.x - currpt.x;CursorImpect.ySpeed = nowCursor.y - currpt.y;double CursorAngle = CalVectorAngle(CursorImpect);//指针与pollo碰撞时的角度double RealCursorAngle = CursorAngle - PI;//得到指针给予速度的角度(上图中的2a)double CircleAngle = CalVectorAngle(Speed_Pollo);//pollo本身的速度角度(上图中的v)double CursorMoveAngle = CalVectorAngle(Speed_Cursor);<span style="white-space:pre"></span>//指针移动时的角度double CursorSpeedAngle = fabs(CursorMoveAngle - RealCursorAngle);//指针的速度通过该角度传入有效速度double ResultAngle;SPEED ResultSpeed;//碰撞结果的速度矢量(既用作上图中的b也用作b')ResultSpeed.xSpeed = Speed_Pollo.xSpeed;ResultSpeed.ySpeed = Speed_Pollo.ySpeed;double MPolloSpeed;//pollo Speed的模double MCursorSpeed;//指针速度的模ResultAngle = abs(CircleAngle - CursorAngle);//只有当pollo速度角度和指针碰撞角度的夹角小于90度时,结果向量才为矢量相减计算if(ResultAngle <= PI/2 && ResultAngle >= -PI/2){MPolloSpeed = sqrt(pow(Speed_Pollo.xSpeed, 2) + pow(Speed_Pollo.ySpeed, 2));//Pollo本身速度的模MCursorSpeed = MPolloSpeed * cos(ResultAngle) * 2;//通过碰撞,指针给予pollo的速度的模(v'只取了大小没取方向,速度大小与v是相同的)MCursorSpeed += sqrt(pow(Speed_Cursor.xSpeed, 2) + pow(Speed_Cursor.ySpeed, 2)) * cos(CursorSpeedAngle);//指针能提供的有效速度加成ResultSpeed.xSpeed = MCursorSpeed * cos(RealCursorAngle);//通过速度的模和指针给的速度的方向,计算出两个矢量相减之后的速度向量ResultSpeed.ySpeed = MCursorSpeed * sin(RealCursorAngle);ResultSpeed.xSpeed = ResultSpeed.xSpeed + Speed_Pollo.xSpeed;//通过与pollo自身速度矢量的平行位移,得出真实的速度向量ResultSpeed.ySpeed = ResultSpeed.ySpeed + Speed_Pollo.ySpeed;<span style="white-space:pre"></span>(本来是减v',但是-v = v'所以就变成了加上v了)}//当碰撞夹角不符合上面的角度时,即为矢量相加计算else{MCursorSpeed = (sqrt(pow(Speed_Cursor.xSpeed, 2) + pow(Speed_Cursor.ySpeed, 2)) * 3) * cos(CursorSpeedAngle);//指针能提供的有效速度加成ResultSpeed.xSpeed = MCursorSpeed * cos(RealCursorAngle);//通过指针提供的速度的模和指针碰撞的方向,计算出指针提供的速度的向量ResultSpeed.ySpeed = MCursorSpeed * sin(RealCursorAngle);ResultSpeed.xSpeed += Speed_Pollo.xSpeed;//通过将pollo自身速度向量平移到指针速度向量上,算出向量相加的结果ResultSpeed.ySpeed += Speed_Pollo.ySpeed;}return ResultSpeed;}

代码当中涉及到了另外两个概念,一个是指针速度,另一个是矢量相加


在碰撞的时候大多数情况下都不是指针静止的时候,因此碰撞的时候如果能够算上指针的速度肯定会更真实一些。那么指针的速度就是由定时器连续取的两个位置计算得到的。而指针提供的速度的方向也跟碰撞时2a的方向完全相同,在计算时仅仅只用在2a上额外加上指针速度在该方向的分量就可以了。


第二个是矢量相加。可以看到在上面的例子中,都是圆一头撞到指针上的情况,那么如果是指针速度比较快,从后面爆菊追上了圆呢,那么这种情况下实际上是矢量相加的情况。


这时候改变原本运动状态的力完全由指针本身的移动速度提供,这种情况相对于矢量相减的要简单很多,就不重新说明了

程序压缩包链接,使用的是vs2010平台 

http://download.csdn.net/detail/polley88/9434737

0 0
原创粉丝点击