程序是一个月前完成的,之前一直没正儿八经的来整理下这个程序,感觉比较简单,不过即使简单的东西也要跟大家分享下。
开篇
开始上代码之前我先说下我为啥写的这个程序,大三的时候学习C#接触过GDI+而发现原来做图形界面的程序也可以这么简单。之后便开始用GDI+做起动画、游戏等,其中便有一个模拟多小球碰撞的,在CSDN上有分享过(
http://pan.baidu.com/s/1qWjTkmS ),不过现在回头想想那个程序还是存在很多问题的,比如:没考虑非对心碰撞问题,或者说是球体斜碰问题,帧率低问题,碰撞检测精度不够导致小球粘连问题(使用的是球体像素整型)。说到这里想必使用过GDI+的同学都会有一个想法就是GDI+用来做游戏效率确实不行。于是呢转战C++,正好自己的毕设要写一个C++
2D游戏,所以在写游戏项目之余,便花费一天时间写了这个模拟球体“弹性斜碰”程序。至于为什么要花这么长时间,是因为大多数时间我都花在了这个“斜碰”问题上,这也是我要写这篇博客的主要原因,网上关于小球弹性斜碰的程序确实很少。不信可以百度下。
上代码
模拟小球碰撞嘛,所以小球的实体类是必须的(Ball.h)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
#pragma once #include <math.h> #include "hge.h" class
CBall
{ public :
CBall();
CBall( float
_x, float
_y, float
_speedX , float
_speedY, float
_radius , DWORD
_color, float
_density = 1.0f);
~CBall(){};
public :
bool
IsCollision(CBall *ball, float
dt); //碰撞检测
void
CollisionWith(CBall *ball); //弹性正碰
void
CollisionWith2(CBall *ball); //弹性斜碰
void
SwapColor(CBall *ball); //好玩点,加个交换颜色
void
MoveNext( float
dt, float
_width, float
_height);
//由于程序不大,方便起见所有就都public了 public :
float
x; //x轴坐标
float
y; //y轴坐标
float
speed_x; //x轴方向速度
float
speed_y; //x轴方向速度
float
radius; //球体半径
float
density; //密度
float
weight; //质量
DWORD
color; //混合颜色
}; |
从Ball的类成员定义中可以看出来,球体的大概属性基本包括全面了,不过多了个Color这个属性是用来设置球体颜色的,因为图片素材是纯白实心圆,在使用color颜色进行顶点着色时候可直接设置获得该颜色的圆。
下面依次说下各个成员方法的作用,部分有代码。
(1)构造方法CBall(float _x,float _y,float ... ,float _density = 1.0f);对成员变量初始化,需要注意,密度默认是1.0f,而质量通过体积和密度的计算求得。【球体质量
m=ρ*v , v = 4/3*π*r^3】。
(2)碰撞检测,返回当前对象时候与参数ball发生碰撞,dt是一帧的时间。
1
2
3
4
5
6
7
8
9
10
11
|
bool
CBall::IsCollision(CBall *ball, float
dt)
{ //计算的是下一刻的位置,以免发生粘连
float
disX = ( this ->x+ this ->speed_x*dt)-(ball->x+ball->speed_x*dt);
float
disY = ( this ->y+ this ->speed_y*dt)-(ball->y+ball->speed_y*dt);
float
dis = sqrt (disX*disX+disY*disY);
//判断下一刻是否 发生碰撞
if (dis < this ->radius+ball->radius)
return
true ;
return
false ;
} |
(3)弹性正碰 void CBall::CollisionWith(CBall *ball)根据动能定理和动量守恒定律得出公式
//弹性正碰撞公式
//v1‘ = [ (m1-m2)*v1 + 2*m2*v2 ] /
(m1+m2)
//v2‘
= [ (m2-m1)*v2 + 2*m1*v1 ] / (m1+m2)
碰撞后,两小球的速度,方向,会发生改变。
(4)弹性斜碰,文章的主角,由于计算比较复杂所以需要用到向量(Vector)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
void
CBall::CollisionWith2(CBall *ball)
{ //参考资料:
//球心点
float
x1 = this ->x ;
float
y1 = this ->y ;
float
x2 = ball->x ;
float
y2 = ball->y ;
//碰撞处切平面向量t,及其法向量s
hgeVector s(x2-x1, y2-y1);
s.Normalize(); //标准化矢量
hgeVector t(x2-x1, y2-y1);
t.Rotate(3.1415926f/2);
t.Normalize();
//速度向量
hgeVector v1( this ->speed_x, this ->speed_y);
hgeVector v2(ball->speed_x,ball->speed_y);
//先算v1(v1x, v1y)在s和t轴的投影值,分别设为v1s和v1t
//再算v2(v2x, v2y)在s和t轴的投影值,分别设为v2s和v2t:
float
v1s = v1.Dot(&s);
float
v1t = v1.Dot(&t);
float
v2s = v2.Dot(&s);
float
v2t = v2.Dot(&t);
//转换后于s向量上的弹性正碰撞。质量不等
//弹性正碰撞公式
//v1‘ = [ (m1-m2)*v1 + 2*m2*v2 ] / (m1+m2)
//v2‘ = [ (m2-m1)*v2 + 2*m1*v1 ] / (m1+m2)
float
m1 = this ->weight;
float
m2 = ball->weight;
float
temp_v1s = ((m1-m2)*v1s + 2*m2*v2s )/ (m1+m2);
v2s = ((m2-m1)*v2s + 2*m1*v1s )/ (m1+m2);
v1s = temp_v1s;
//首先求出v1t和v2t在t轴的向量v1t‘和v2t‘(将数值变为向量)
//再求出v1s‘和v2s‘在s轴的向量v1s‘和v2s‘(将数值变为向量)
hgeVector v1tVector = t*v1t;
hgeVector v1sVector = s*v1s;
hgeVector v2tVector = t*v2t;
hgeVector v2sVector = s*v2s;
//新速度矢量
hgeVector v1_new = v1tVector+v1sVector;
hgeVector v2_new = v2tVector+v2sVector;
//划分成x,y方向分量速度
this ->speed_x = v1_new.x;
this ->speed_y = v1_new.y;
ball->speed_x = v2_new.x;
ball->speed_y = v2_new.y;
} |
(5)交换颜色,发生碰撞后的两个小球进行颜色交换,纯属娱乐。
void CBall::SwapColor(CBall *ball)
(6)小球移动,参数 _width,_height分别是窗口的宽高,因为这个方法内包含边界碰撞的检测和反弹。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
void
CBall::MoveNext( float
dt, float
_width, float
_height)
{ float
moveX = speed_x*dt;
float
moveY = speed_y*dt;
//x方向边界
if
(x+moveX<radius||x+moveX>_width-radius)
speed_x = -speed_x;
//Y方向边界
if (y+moveY<radius||y+moveY>_height-radius)
speed_y = -speed_y;
x+=speed_x*dt;
y+=speed_y*dt;
} |
主函数,使用HGE引擎,看源文件吧这里不详细说了。
(HGE是一个小型的2D游戏引擎,基于DirectX8,相关学习资料下载:http://pan.baidu.com/s/1dDtdd2h)
结束语
大四快毕业了,现在才发现大学期间学的确实太少,玩的太多(DotAer哈哈),好多感慨,都化成两个字“时间”。回想起当初刚上大一的时候,拿着书本照着上面一字不差的敲着C程序代码,直到程序运行出来还不能理解程序是怎么个原理,怎么实现的,不过还好“时间”告诉了我。从大一学的枯燥的只能用来ACM的C/C++到大二终于见到图形界面却又笨拙而不适合图形界面开发的Java再到大三时让图形界面开发简单至极却又低效无法满足游戏开发的C#到最后又回到了最初那个高效而复杂的让人抓狂的C++,就这样走完了大学四年。同学现在有不少出去工作了的,不过给我的感觉就是大家好像都是一知半解,拿着刚好养活自己的工资,在不断地学习着,不过期待同学们都能找到自己满意的工作,也希望自己找工作能顺利。写这篇文章是还在考虑要不要参加蓝桥杯的决赛,毕竟我都大四了,而且最近的事情会好多。不好意思思路有点断篇。言归正传,毕设在做一个“仿《保卫萝卜》塔防游戏”,框架基本上搭建差不多了,还有部分需要完善的地方,在此先发个不完整版,http://pan.baidu.com/s/1dDEbK4L,框架仅供参考。毕竟我是菜鸟级的,很多东西都一知半解,所以程序有什么不妥的地方还望不吝提出。先谢谢了!