双圆碰撞简析

之前在SSZX上课时写老程序Star,准备加上碰撞系统.碰撞后的速度改变比较简单,正交分解即可,但碰撞检测却卡了一段时间

双圆碰撞检测,最简单的碰撞检测.它的确很简单,至少与其他碰撞检测相比,有着更易于思考的算法,更少的参数.在一个月前开始思考怎么实现时,我的构思是这样:

struct Ball{double x;double y;//表示圆所处的位置,(x,y).
double xm;
double ym;//xm,ym表示每次移动的量,即每一帧将其X方向移动xm,Y方向移动ym.
double r;//圆的半径
}ball[MAXNUM];
inline double distant_sum(const ball &a,const ball &b){
return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2));
}//返回两距离>//存储一个圆的结构体

double x;double y;//表示圆所处的位置,(x,y).double xm;double ym;//xm,ym表示每次移动的量,即每一帧将其X方向移动xm,Y方向移动ym.double r;//圆的半径}ball[MAXNUM];inline double distant_sum(const ball &a,const ball &b){ return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2));}//返回两距离


然后这样:

if(distant_sum(ball[i],ball[j])<ball[i].r+ball[j].r)
  {/*other process*/}

也就是说,两圆距离小于半径和时,即判定为碰撞.这个方法非常显然,非常简单,但显然,它在两圆的速度很高时,是很不可靠的:

虽然一个圆运动速度如此之快的情况是很少的,在高速下撞击另一个圆的几率也不大,但毕竟有BUG就要修.

查阅了一些关于碰撞检测的资料后,在某东方同人的检测代码中发现了一个有趣的方法:每次移动(有选择性的)判断两圆碰撞时,将圆用循环暴力慢慢移动,每次移动较小的圆的半径长度(或是一更小的时间单位),暴力检测每次移动后是否碰撞.

这种方法能解决大部分的BUG,但显然也只是"大部分":

而且可以想象如果优化不好,这种方法在球很多是得有多卡........代码就不上了,敲了半天没调好.

最后我放弃了投机取巧,选择了更暴力的方法,就是直接算碰撞点.

不考虑两圆的速度,而考虑相对另一圆的速度,即假设一个不动,另一个的速度为两圆的相对速度,这样,可以将情况看作一个圆在一帧内沿一段一次函数运动,另一个不动,检测而这是否碰撞

事实上,这个问题等价于在一段一次函数上是否存在一个点(动圆圆心)到另一点(定圆圆心)的距离小于等于一个常量(两圆半径和),如果有,返回距离开始点最近的那个点(显然大部分碰撞的情况会有两个点到另一圆圆心距离等于两圆半径和)

这就非常简单了,稍微推一下公式就行了:

((y1 - y2)/(x1 - x2)*x + y1 - (y1 - y2)/(x1 - x2)*x1 - y3)^2 + (x - x3)^2 - (r + R)^2=0

(图中忘写=0)

然后就用求根公式:

x == (-2 x1^2 x3 + 4 x1 x2 x3 - 2 x2^2 x3 - 2 x2 y1^2 + 2 x1 y1 y2 +

2 x2 y1 y2 - 2 x1 y2^2 - 2 x1 y1 y3 + 2 x2 y1 y3 + 2 x1 y2 y3 -

2 x2 y2 y3 - \[Sqrt]((2 x1^2 x3 - 4 x1 x2 x3 + 2 x2^2 x3 +

2 x2 y1^2 - 2 x1 y1 y2 - 2 x2 y1 y2 + 2 x1 y2^2 +

2 x1 y1 y3 - 2 x2 y1 y3 - 2 x1 y2 y3 + 2 x2 y2 y3)^2 -

4 (-x1^2 + 2 x1 x2 - x2^2 - y1^2 + 2 y1 y2 -

y2^2) (r^2 x1^2 + 2 r R x1^2 + R^2 x1^2 - 2 r^2 x1 x2 -

4 r R x1 x2 - 2 R^2 x1 x2 + r^2 x2^2 + 2 r R x2^2 +

R^2 x2^2 - x1^2 x3^2 + 2 x1 x2 x3^2 - x2^2 x3^2 -

x2^2 y1^2 + 2 x1 x2 y1 y2 - x1^2 y2^2 - 2 x1 x2 y1 y3 +

2 x2^2 y1 y3 + 2 x1^2 y2 y3 - 2 x1 x2 y2 y3 - x1^2 y3^2 +

2 x1 x2 y3^2 - x2^2 y3^2)))/(2 (-x1^2 + 2 x1 x2 - x2^2 -

y1^2 + 2 y1 y2 - y2^2))

||

 x == (-2 x1^2 x3 + 4 x1 x2 x3 - 2 x2^2 x3 - 2 x2 y1^2 + 2 x1 y1 y2 +

2 x2 y1 y2 - 2 x1 y2^2 - 2 x1 y1 y3 + 2 x2 y1 y3 + 2 x1 y2 y3 -

2 x2 y2 y3 + \[Sqrt]((2 x1^2 x3 - 4 x1 x2 x3 + 2 x2^2 x3 +

2 x2 y1^2 - 2 x1 y1 y2 - 2 x2 y1 y2 + 2 x1 y2^2 +

2 x1 y1 y3 - 2 x2 y1 y3 - 2 x1 y2 y3 + 2 x2 y2 y3)^2 -

4 (-x1^2 + 2 x1 x2 - x2^2 - y1^2 + 2 y1 y2 -

y2^2) (r^2 x1^2 + 2 r R x1^2 + R^2 x1^2 - 2 r^2 x1 x2 -

4 r R x1 x2 - 2 R^2 x1 x2 + r^2 x2^2 + 2 r R x2^2 +

R^2 x2^2 - x1^2 x3^2 + 2 x1 x2 x3^2 - x2^2 x3^2 -

x2^2 y1^2 + 2 x1 x2 y1 y2 - x1^2 y2^2 - 2 x1 x2 y1 y3 +

2 x2^2 y1 y3 + 2 x1^2 y2 y3 - 2 x1 x2 y2 y3 - x1^2 y3^2 +

2 x1 x2 y3^2 - x2^2 y3^2)))/(2 (-x1^2 + 2 x1 x2 - x2^2 -

y1^2 + 2 y1 y2 - y2^2))

判别式为:

-(1/((x1 - x2)^2))

4 (-r^2 x1^2 - 2 r R x1^2 - R^2 x1^2 + 2 r^2 x1 x2 + 4 r R x1 x2 +

2 R^2 x1 x2 - r^2 x2^2 - 2 r R x2^2 - R^2 x2^2 - r^2 y1^2 -

2 r R y1^2 - R^2 y1^2 + x2^2 y1^2 - 2 x2 x3 y1^2 + x3^2 y1^2 +

2 r^2 y1 y2 + 4 r R y1 y2 + 2 R^2 y1 y2 - 2 x1 x2 y1 y2 +

2 x1 x3 y1 y2 + 2 x2 x3 y1 y2 - 2 x3^2 y1 y2 - r^2 y2^2 -

2 r R y2^2 - R^2 y2^2 + x1^2 y2^2 - 2 x1 x3 y2^2 + x3^2 y2^2 +

2 x1 x2 y1 y3 - 2 x2^2 y1 y3 - 2 x1 x3 y1 y3 + 2 x2 x3 y1 y3 -

2 x1^2 y2 y3 + 2 x1 x2 y2 y3 + 2 x1 x3 y2 y3 - 2 x2 x3 y2 y3 +

x1^2 y3^2 - 2 x1 x2 y3^2 + x2^2 y3^2)

好了,为题解决,写了个小程序验证:

#include<cmath>
 #include<windows.h>
 #include<iostream>
 #include<cstdio>
 #include<cstdlib>
 #include<cstring>

 #include<algorithm>
 #include<vector>
 #include<iostream>
 #include<ctime>
 #include<process.h>
#include<vector>
/*DCY11011 2016*/

 using namespace std;
 HANDLE h=CreateFile(TEXT("CONOUT$"),GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);

vector <double> xy,c1;

struct Ball{
	double x;
	double y;
	double xm;
	double ym;
	double r;
};

Ball ball[3];

 bool Circle(HDC hdc,int x,int y,int r){
 	return Ellipse(hdc,x-r,y-r,x+r,y+r);
 }

 HPEN hpen;
 HBRUSH hbrush;
 HWND hwnd=0;
 HDC dc,hmem;

int setfillcolor(COLORREF c){
	DeleteObject(hbrush);
	hbrush=CreateSolidBrush(c);
	SelectObject(hmem,hbrush);
	return 0;
}
int setcolor(COLORREF c,int a=1){
	DeleteObject(hpen);
	hpen=CreatePen(PS_SOLID,a,c);
	SelectObject(hmem,hpen);
	return 0;
}
int in(int a,int b,int c,int d,int x,int y)
{
	return x>a&&x<c&&y>b&&y<d;
}
void line(HDC hdc,int a,int b,int c,int d)
{
     MoveToEx (hdc,a,b,NULL) ;
     LineTo   (hdc,c,d) ;
}
int bar(HDC hdc,int x,int y,int x1,int y1){
	RECT rc={x,y,x1,y1};
	FillRect(hdc,&rc,hbrush);
	return 0;
}
int ctx,cty;
double xc1,yc1,xc2,yc2;
RECT rc;

bool ea=0;
void Worker(LPVOID lpParam){
 	const volatile bool *run=(bool *)lpParam;
 	while(*run){

 		GetClientRect(FindWindow(TEXT("ConsoleWindowClass"),TEXT("Star C")),&rc);
		ctx=rc.right;cty=rc.bottom;
		ea=1;
		for(int i=0;i<3;i++){
			//碰撞检测
			{
				for(int j=i+1;j<3;j++){
					double x2=ball[i].xm-ball[j].xm;
					double y2=ball[i].ym-ball[j].ym;
					double x1=ball[i].x;
					double y1=ball[i].y;
					double x3=ball[j].x;
					double y3=ball[j].y;
					double L=ball[i].r+ball[j].r;

					double t=sqrt(- pow((x1-x2),2)* (-L*L* (x1*x1 - 2*x1*x2 + x2*x2 + pow((y1-y2),2)) +pow((x2*y1-x3*y1-x1*y2+x3*y2+x1*y3-x2*y3),2)));
					if(t<0)continue;
  					xc1 = (1/(
 	 				pow((x1-x2),2)+ pow((y1-y2),2)))*(x1*x1*x3 - 2*x1*x2*x3 + x2*x2*x3 + x2*y1*y1 -
				    x1*y1*y2 - x2*y1*y2 + x1*y2*y2 + x1*y1*y3 - x2*y1*y3 - x1*y2*y3 +
				    x2*y2*y3 +
				    t);
				    yc1 = (y1 - y2)/(x1 - x2)*xc1 + y1 - (y1 - y2)/(x1 - x2)*x1;
				    xc2 = (1/(
 	 				pow((x1-x2),2)+ pow((y1-y2),2)))*(x1*x1*x3 - 2*x1*x2*x3 + x2*x2*x3 + x2*y1*y1 -
				    x1*y1*y2 - x2*y1*y2 + x1*y2*y2 + x1*y1*y3 - x2*y1*y3 - x1*y2*y3 +
				    x2*y2*y3 -
				    t);
				    yc2 = (y1 - y2)/(x1 - x2)*xc2 + y1 - (y1 - y2)/(x1 - x2)*x1;

				    if(((xc1>=x1&&xc1<=x2+x1)||(xc1>=x2+x1&&xc1<=x1))&&((yc1>=y1&&yc1<=y2+y1)||(yc1>=y2+y1&&yc1<=y1)))
				    {
				    	c1.push_back(xc1);c1.push_back(yc1);
				    }
				    if(((xc2>=x1&&xc2<=x2+x1)||(xc2>=x2+x1&&xc2<=x1))&&((yc2>=y1&&yc2<=y2+y1)||(yc2>=y2+y1&&yc2<=y1)))
				    {
				    	c1.push_back(xc1);c1.push_back(yc1);
				    }
				    if(abs(x1-xc1)<abs(x1-xc2))
				    {
				    	 xy.push_back(xc1);
				    	 xy.push_back(yc1);
				    	 xy.push_back(i);
				    	 xy.push_back(j);
				    }

				    else{

					    xy.push_back(xc2);
					    xy.push_back(yc2);
					    xy.push_back(i);
				    	xy.push_back(j);
				    }
         			//system("cls") ;
				}
			}

			ea=0;
			ball[i].x+=ball[i].xm;
			ball[i].y+=ball[i].ym;

			if(ball[i].x>600||ball[i].x<0)ball[i].xm=-ball[i].xm;
			if(ball[i].y<0||ball[i].y>500)ball[i].ym=-ball[i].ym;

		}

 		Sleep(100);
 	}
 	_endthread();
 }
 void Messageer(LPVOID lpParam){
 	const volatile bool *run=(bool *)lpParam;
 	while(*run){

 		while(!GetAsyncKeyState(VK_LBUTTON )&&0x8000);
 		while(GetAsyncKeyState(VK_LBUTTON )&&0x8000){
 			//cout<<"LBUTTON_DOWN"<<endl;
 			Sleep(10);
 		}
 	}
 	_endthread();
 }

 void ConsoloPrinter(LPVOID lpParam){
 	const volatile bool *run=(bool *)lpParam;
 	dc=GetDC(hwnd);hmem=CreateCompatibleDC(dc);
 	HBITMAP hbit=CreateCompatibleBitmap(dc,1000,700);
 	ReleaseDC(hwnd,dc);
 	SelectObject(hmem,hbit);
 	SetBkMode(hmem,TRANSPARENT);
	 while(*run){

 	  setfillcolor(0x000000);
 	  bar(hmem,0,0,ctx,cty);

 	  SetTextColor(hmem,0xddffdd);
 	  char temp[40];
 	  sprintf(temp,"Test Text");
 	  TextOut(hmem,100,100,temp,strlen(temp));

 	  for(int i=0;i<3;i++){
 	  	setcolor(RGB(255,0,0),1);
 	  	Circle(hmem,ball[i].x,ball[i].y,ball[i].r);
 	  }
 	  while(ea); 

 	  while(!xy.empty()){

 	  	double x,y,x1,y1;
 	  	y1=xy.back();xy.pop_back();
 	  	x1=xy.back();xy.pop_back();
		y=xy.back();xy.pop_back();
 	  	x=xy.back();xy.pop_back();
 	  	sprintf(temp,"%lf-%lf",&x1,&y1);
 	    TextOut(hmem,x,y,temp,strlen(temp));

 	    setfillcolor(0xffff00);
 	    Circle(hmem,x,y,5);
 	  }
 	  while(!c1.empty()){
 	  	double x,y;
 	  	y=c1.back();c1.pop_back();
		x=c1.back();c1.pop_back();
		setfillcolor(RGB(255,0,0));
		Circle(hmem,x,y,10) ;
 	  }

 	  HDC hdc=GetDC(hwnd);
 	  BitBlt(hdc,0,96,1000,700,hmem,0,0,SRCCOPY);
 	  ReleaseDC(hwnd,hdc);
	  DeleteObject(hbrush);
	  DeleteObject(hpen);
 	  Sleep(1000/60);
	 }
 	DeleteObject(hpen);
 	DeleteObject(hbrush);
 	_endthread();
 }
 int main(){

 	ball[0]={0,0,4,3,30};
 	ball[1]={300,300,5,-5,40};
 	ball[2]={100,100,2,2,50};
 	SetConsoleTitle("Star C");
 	Sleep(500);
	hwnd=FindWindow(0,"Star C");
	MoveWindow(hwnd,100,0,1000,700,1);
	COORD cd={120,50};
	SetConsoleScreenBufferSize(h,cd);
	CloseHandle(h);
	bool run=true;
	_beginthread(ConsoloPrinter,0,&run);
	_beginthread(Worker,0,&run);
	_beginthread(Messageer,0,&run);
	while(run){
		system("cls");
		cout<<"Input...->";
		string t;
		cin>>t;
		if(t=="Commad"){
			//function
			continue;
		}
		cout<<"No such instruction!(input 'help' for help!)"<<endl;
		getchar();getchar();
	}

}
时间: 2024-11-25 14:35:40

双圆碰撞简析的相关文章

web应用构架LAMT及tomcat负载简析

Httpd    (mod_jk.so) workers.properties文件 uriworkermap.properties文件 <--AJP1.3--> Tomcat  --> jdk 大致流程:apache服务器通过mod_jk.so 模块处理jsp文件的动态请求.通过tomcat worker等待执行servlet/JSP的tomcat实例.使用 AJP1.3协议与tomcat通信.tomcat有借助jdk解析. 负载就是 多台tomcat.共同解析apache发送的jsp请

CentOS的网络配置简析

我们在进行对CentOS的网络配置时,一般会从IP地址(IPADDR).子网掩码(NETMASK).网关(Gateway).主机名(HOSTNAME).DNS服务器等方面入手.而在CentOS中,又有着不同的命令或配置文件可以完成这些配置操作,接下来,我们将从ifcfg系命令,iproute2系命令以及配置文件3个方面来简析网络配置的方法. 一.ifcfg系命令 ifcfg系命令包括ifconfig,route,netstat和hostname. 1.ifconfig命令 用来配置一个网络接口.

JDK源码简析--java.lang包中的基础类库

题记 JDK,Java Development Kit. 我们必须先认识到,JDK只是,仅仅是一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含量来说,还是在一个层级上,它们都是需要被编译成字节码,在JRE中运行的,JDK编译后的结果就是jre/lib下得rt.jar,我们学习使用它的目的是加深对Java的理解,提高我们的Java编码水平. 本系列所有文章基于的JDK版本都是1.7.16. 本节内容 在本节中,简析java.lang包所包

经验模态分解法简析 (转)

http://blog.sina.com.cn/s/blog_55954cfb0102e9y2.html 美国工程院士黄锷博士于1998年提出的一种信号分析方法:重点是黄博士的具有创新性的经验模态分解(Empirical Mode Decomposition)即EMD法,它是一种自适应的数据处理或挖掘方法,非常适合非线性,非平稳时间序列的处理,本质上是对数据序列或信号的平稳化处理. 1:关于时间序列平稳性的一般理解: 所谓时间序列的平稳性,一般指宽平稳,即时间序列的均值和方差为与时间无关的常数,

Java Annotation 及几个常用开源项目注解原理简析

PDF 版: Java Annotation.pdf, PPT 版:Java Annotation.pptx, Keynote 版:Java Annotation.key 一.Annotation 示例 Override Annotation Java 1 2 3 @Override public void onCreate(Bundle savedInstanceState); Retrofit Annotation Java 1 2 3 @GET("/users/{username}&quo

Linux网络性能优化方法简析

Linux网络性能优化方法简析 2010-12-20 10:56 赵军 IBMDW 字号:T | T 性能问题永远是永恒的主题之一,而Linux在网络性能方面的优势则显而易见,这篇文章是对于Linux内核中提升网络性能的一些优化方法的简析,以让我们去后台看看魔术师表演用的盒子,同时也看看内核极客们是怎样灵活的,渐进的去解决这些实际的问题. AD:2014WOT全球软件技术峰会北京站 课程视频发布 对于网络的行为,可以简单划分为 3 条路径:1) 发送路径,2) 转发路径,3) 接收路径,而网络性

.NET设计模式简析

首先,是设计模式的分类,我们知道,常用的设计模式共23种.但总体来说,设计模式氛围三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单列模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. 行为型模式,共十一种:策略模式.模版方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.转改模式.访问者模式.终结者模式.解释器模式. 另外还有并发型模式和线程池模式等. 介绍了分类,下面简单说下设计模式的六大原则

SpringMVC学习——概念、流程图、源码简析(一)

学习资料:开涛的<跟我学SpringMVC.pdf> 众所周知,springMVC是比较常用的web框架,通常整合spring使用.这里抛开spring,单纯的对springMVC做一下总结. 概念 HandlerMapping:处理器映射,对请求的URL进行映射为具体的处理器(如果有拦截器也包含拦截器,会将Handler和多个HandlerInterceptor封装为HandlerExecutionChain对象) HandlerAdapter:处理器适配器,适配不同类型的处理器,如Cont

Android WebView远程代码执行漏洞简析

0x00 本文参考Android WebView 远程代码执行漏洞简析.代码地址为,https://github.com/jltxgcy/AppVulnerability/tree/master/WebViewFileDemo.下面我们分析代码. 0x01 首先列出项目工程目录: MainActivity.java的代码如下: public class MainActivity extends Activity { private WebView webView; private Uri mUr