本章我们将介绍一些游戏编程中最基本的游戏物理建模技巧(匀速运动、加速运动、重力系统和摩擦力系统),以及一些最基本的物理模型(粒子系统)。
1.1 基础物理建模初步
我们可以毫不夸张的说,在当今的任意一款成功的3D 游戏中,物理建模都是非常核心的部分。
而物理引擎也在最近这些年自立门户,成为了游戏引擎这个大概念中的一个分支。目前较为有名的物理引擎有PhysX 和Havok 等等,如下图所示。
在任何一款成功的游戏中,有关物理的代码都占着一定的比重,所以在开发游戏过程中,进行优秀的物理建模是非常必要的。
为了设计出立足实际,联系现实的游戏,为了研发出能有与现实物理现象大体相同的游戏效果,给玩家一个逼真的、身临其境的游戏体验,我们必须进行合适的物理建模。
1.1.1 匀速与加速运动模拟
1 . 匀速运动分析
通常情况下, 一个移动着的物体都是具有“速度”的,这个速度我们可以进行正交分解,看作各个方向上“速度分量”的合成。
这里我们设一个物体的移动速度为V, x 方向的速度分量为Vx, y 方向上的速度分量为Vy.
匀速运动实际上就是Vx 与Vy 保持恒定不变。关于匀速运动的路程计算,我们知道有这个公式:
路程St = S0+ V · t
然后我们把它正交分解分解到X 和Y 两个方向,于是就有:
Sx = Sx0 Vx * t
Sy = Sy0 Vy * t
设时间间隔t = 1 ,那么我们可以推算出匀速运动下,物体下一刻所在的位置:
Sx = Sx0+ Vx
Sy = Sy0 Vy
将这两个公式运用到我们的代码里面就可以实现匀速运动的模拟了。
所以,我们可以总结出,在设计2D 平面上物体的匀速运动中,每次画面更新时,利用物体速度分量Vx 与Vy 的值来计算下次物体出现的位置,产生物体移动的效果, 这样的原理实现方式我们可以表示为:
- 下次X 轴坐标=当前X 轴坐标+X 轴上的速度分量
- 下次Y 轴坐标= 当前Y 轴坐标+Y 轴上的速度分量
2 . 加速运动
加速运动就是具有加速度的运动,它的速度会随着时间而改变。
求末速度Vt 的公式我们可以表示如下:
Vx =V0 + a · t
这是高中物理运动学里最基本的匀变速运动公式。其中, V 为当前速度, V0为初速度, a 为加速度,t 为物体从速度为V0时记起的时间。那么同样将此速度分解,我们得到:
Vx = Vx0 ax ·t
这些知识都是非常基础的, 实现方式也非常简单。这里,我们点到为止,高中物理知识就暂时告一段落。
接下来, 好玩的内容来了, 我们要亲手写一个愤怒的小鸟弹球小游戏。
3 . 示例程序GDldemo12
本节的示例程序是一个匀速运动, 碰到窗口边缘时就进行反弹的“愤怒的小鸟” 小游戏,学完本节内容后,大家就可以自己实现Win7 里的那个“多彩气泡”的屏幕保护程序;
我们先来看看游戏素材图,如下图:
程序代码片段一,全局变量声明:
-
-
-
- HDC g_hdc=NULL,g_mdc=NULL,g_bufdc=NULL;
- HBITMAP g_hAngrybird=NULL,g_hBackGround=NULL;
- DWORD g_tPre=0,g_tNow=0;
- int g_iX=0,g_iY=0,g_iXSpeed=0,g_iYSpeed=0;
- RECT g_rect;
程序代码片段二, Game_Init()函数:-
-
-
- BOOL Game_Init( HWND hwnd )
- {
- HBITMAP bmp;
-
- g_hdc = GetDC(hwnd);
- g_mdc = CreateCompatibleDC(g_hdc);
- g_bufdc = CreateCompatibleDC(g_hdc);
- bmp = CreateCompatibleBitmap(g_hdc,WINDOW_WIDTH,WINDOW_HEIGHT);
-
- SelectObject(g_mdc,bmp);
-
-
- g_hBackGround = (HBITMAP)LoadImage(NULL,L"bg.bmp",IMAGE_BITMAP,WINDOW_WIDTH,WINDOW_HEIGHT,LR_LOADFROMFILE);
- g_hAngrybird = (HBITMAP)LoadImage(NULL,L"angrybird.bmp",IMAGE_BITMAP,120,60,LR_LOADFROMFILE);
-
- GetClientRect(hwnd,&g_rect);
-
-
- g_iX=50;
- g_iY=50;
- g_iXSpeed=20;
- g_iYSpeed=20;
-
- Game_Paint(hwnd);
- return TRUE;
- }
第2-25 行代码精析:设置小鸟的横纵坐标上的初始速度都为20 个像素单位, 初始位置在(50,50)处。程序代码片段三, Game_Paint() 函数:
-
-
-
- VOID Game_Paint( HWND hwnd )
- {
-
-
- SelectObject(g_bufdc,g_hBackGround);
- BitBlt(g_mdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_bufdc,0,0,SRCCOPY);
-
-
- SelectObject(g_bufdc,g_hAngrybird);
- BitBlt(g_mdc,g_iX,g_iY,60,60,g_bufdc,60,0,SRCAND);
- BitBlt(g_mdc,g_iX,g_iY,60,60,g_bufdc,0,0,SRCPAINT);
-
-
- BitBlt(g_hdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_mdc,0,0,SRCCOPY);
-
-
- g_iX = g_iXSpeed;
-
- if(g_iX <= 0)
- {
- g_iX = 0;
- g_iXSpeed = -g_iXSpeed;
- }
- else if(g_iX >= g_rect.right-60)
- {
- g_iX = g_rect.right - 60;
- g_iXSpeed = -g_iXSpeed;
- }
-
-
- g_iY = g_iYSpeed;
-
- if(g_iY<=0)
- {
- g_iY = 0;
- g_iYSpeed = -g_iYSpeed;
- }
- else if(g_iY >= g_rect.bottom-60)
- {
- g_iY = g_rect.bottom - 60;
- g_iYSpeed = -g_iYSpeed;
- }
-
- g_tPre = GetTickCount();
- }
第19-45 行代码精析: 这一段代码是我们这一节的核心知识点所凝聚而成的。首先它分为两段,分别在对X 轴和Y 轴进行处理,我们只用看一半。另外一半对仗着来写就行了。我们就拿19~31行关于X 轴方向上的小鸟速度和坐标的代码来开刀。20 行中g_iX += g_iXSpeed 这句代码最为关键,即g_iX = g_iX+g_iXSpeed ,这不就是我们运动学公式的代码实现吗?
Sx = Sxo Vx
接着36-40 行,对碰到边缘后的速度进行反向。41 ~46 行,也是这样,对碰到另一边边缘后的速度进行反向。这样,这段代码就很好理解了。
最后依然是看下运行截图:
1.1.2 重力系统模拟
1 . 思路分析
重力模拟实现起来其实非常简单,我们都知道, 重力的表现形式其实就是一个大小约等于9.8米每二次方秒, 方向垂直地面指向地心的加速度。且由于X 轴方向的速度不受重力影响,所以我们只要将物体的速度进行正交分解,处理竖直向下的Y 轴方向的速度即可。
下面我们用本小节的示例程序中的实现重力模拟的代码来具体说明,这里着重讨论重力,所以演示时暂时先忽略下坠时的空气阻力与触地时的摩擦力。
这是一个平抛运动,小鸟将具有水平方向的初速度,且受到向下的重力, 即小鸟具有向下的加速度, 若碰到地面就会进行反弹,速度反向。
首先我们定义下坠物体的初始坐标与初始速度,初始横坐标x=0 , 初始纵坐标y=100, 初始水平方向速度Vx=3,初始竖直方向速度Vy=0,重力加速度Gy=3 (这里为了方便演示, 我们设置为3),即:copy -
- g_iX=0;
- g_iY=100;
- g_iXSpeed=3;
- g_iYSpeed=0;
- g_iYGravity=3;
然后我们在Game_Paint()函数中实现具体的重力环境模拟:
-
- g_iX = g_iXSpeed;
-
- g_iYSpeed = g_iYSpeed g_iYGravity;
- g_iY = g_iYSpeed;
-
-
- if(g_iY >= g_rect.bottom-60)
- {
- g_iY= g_rect.bottom - 60;
- g_iYSpeed= -g_iYSpeed;
- }
最后的7~11行,判断小鸟是否触地,如果触碰到窗口边界,g_iYSpeed 调整为相反方向,其中的g_rect.bottom 为窗口的高度,这里为600 。然后小鸟的尺寸为60 ,于是g_iY = g_rect.bottom-60就是临界窗口位置了。
2. 示例程序GDldemo13
这个示例程序中,做了重力系统的模拟,在无摩擦力的环境下将愤怒的小鸟平抛出去。
图片素材基本上和上一节讲匀速运动时的demo 差不多,就不贴出来了,我们直接来看一下代码。
程序代码片段一, 全局变量声明:
-
-
-
- HDC g_hdc=NULL,g_mdc=NULL,g_bufdc=NULL;
- HBITMAP g_hAngrybird=NULL,g_hBackGround=NULL;
- DWORD g_tPre=0,g_tNow=0;
- int g_iX=0,g_iY=0,g_iXSpeed=0,g_iYSpeed=0,g_iYGravity=0;
- RECT g_rect;
程序代码片段二, Game_Init()函数:
-
-
-
- BOOL Game_Init( HWND hwnd )
- {
- HBITMAP bmp;
-
- g_hdc = GetDC(hwnd);
- g_mdc = CreateCompatibleDC(g_hdc);
- g_bufdc = CreateCompatibleDC(g_hdc);
- bmp = CreateCompatibleBitmap(g_hdc,WINDOW_WIDTH,WINDOW_HEIGHT);
-
- SelectObject(g_mdc,bmp);
-
-
- g_hBackGround = (HBITMAP)LoadImage(NULL,L"bg.bmp",IMAGE_BITMAP,WINDOW_WIDTH,WINDOW_HEIGHT,LR_LOADFROMFILE);
- g_hAngrybird = (HBITMAP)LoadImage(NULL,L"angrybird.bmp",IMAGE_BITMAP,120,60,LR_LOADFROMFILE);
-
- GetClientRect(hwnd,&g_rect);
-
-
- g_iX=0;
- g_iY=100;
- g_iXSpeed=3;
- g_iYSpeed=0;
- g_iYGravity=3;
-
- Game_Paint(hwnd);
- return TRUE;
- }
程序代码片段三, Gam e_Paint()函数:
-
-
-
- VOID Game_Paint( HWND hwnd )
- {
-
-
- SelectObject(g_bufdc,g_hBackGround);
- BitBlt(g_mdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_bufdc,0,0,SRCCOPY);
-
-
- SelectObject(g_bufdc,g_hAngrybird);
- BitBlt(g_mdc,g_iX,g_iY,60,60,g_bufdc,60,0,SRCAND);
- BitBlt(g_mdc,g_iX,g_iY,60,60,g_bufdc,0,0,SRCPAINT);
-
-
- BitBlt(g_hdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_mdc,0,0,SRCCOPY);
-
-
- g_iX = g_iXSpeed;
-
- g_iYSpeed = g_iYSpeed g_iYGravity;
- g_iY = g_iYSpeed;
-
-
- if(g_iY >= g_rect.bottom-60)
- {
- g_iY= g_rect.bottom - 60;
- g_iYSpeed= -g_iYSpeed;
- }
-
- g_tPre = GetTickCount();
- }
小鸟每次碰撞地面后从地面上弹起,但是由于受到重力的影响,每次弹起的高度都会降低。最后Y 方向上的速度耗尽,就变成X 方向上沿地面的滚动了。
1.1.3 摩擦力系统模拟
1 . 思路分析
摩擦力是两个表面接触的物体相互运动时互相施加的一种物理力。广义地讲,物体在液体和气体中运动时也受到摩擦力。摩擦力可谓无处不在,为了模拟出与现实生活相符的游戏场景, 游戏或者游戏引擎中, 用相关代码实现摩擦力的真实效果是十分必要的。
上一小节的范例中并没有考虑小鸟下坠与弹跳时的摩擦力影响效果,本小节里面我们将其考虑进来,加入了使小鸟运动速度减慢的负向加速度,但忽略小鸟与空气之间的阻力。下面看看如何实现这样一个比较符合真实状况的小鸟下落与弹跳的效果:
小鸟从高处下落触及地面进行反弹,且存在落地时的摩擦力,使得小鸟在落地弹跳后速度减慢,最后呈现静止的状态,停在窗口边缘。
2. 示例程序GDldemo14
程序代码片段一,全局变量声明:
-
-
-
- HDC g_hdc=NULL,g_mdc=NULL,g_bufdc=NULL;
- HBITMAP g_hAngrybird=NULL,g_hBackGround=NULL;
- DWORD g_tPre=0,g_tNow=0;
- int g_iX,g_iY,g_iXSpeed,g_iYSpeed;
- int g_iYGravity=0,g_iXFriction=0,g_iYFriction=0;
- RECT g_rect;
程序代码片段二, Gam e_Init()函数:
-
-
-
- BOOL Game_Init( HWND hwnd )
- {
- HBITMAP bmp;
-
- g_hdc = GetDC(hwnd);
- g_mdc = CreateCompatibleDC(g_hdc);
- g_bufdc = CreateCompatibleDC(g_hdc);
- bmp = CreateCompatibleBitmap(g_hdc,WINDOW_WIDTH,WINDOW_HEIGHT);
-
- SelectObject(g_mdc,bmp);
-
- g_hBackGround = (HBITMAP)LoadImage(NULL,L"bg.bmp",IMAGE_BITMAP,WINDOW_WIDTH,WINDOW_HEIGHT,LR_LOADFROMFILE);
- g_hAngrybird = (HBITMAP)LoadImage(NULL,L"angrybird.bmp",IMAGE_BITMAP,140,70,LR_LOADFROMFILE);
-
- GetClientRect(hwnd,&g_rect);
-
-
- g_iX=0;
- g_iY=100;
- g_iXSpeed=8;
- g_iYSpeed=0;
- g_iYGravity=3;
- g_iXFriction=-1;
- g_iYFriction=-4;
-
- Game_Paint(hwnd);
- return TRUE;
- }
程序代码片段三, Game_Paint()函数:
-
-
-
- VOID Game_Paint( HWND hwnd )
- {
-
-
- SelectObject(g_bufdc,g_hBackGround);
- BitBlt(g_mdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_bufdc,0,0,SRCCOPY);
-
-
- SelectObject(g_bufdc,g_hAngrybird);
- BitBlt(g_mdc,g_iX,g_iY,70,70,g_bufdc,70,0,SRCAND);
- BitBlt(g_mdc,g_iX,g_iY,70,70,g_bufdc,0,0,SRCPAINT);
-
-
- BitBlt(g_hdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_mdc,0,0,SRCCOPY);
-
-
- g_iX = g_iXSpeed;
- g_iYSpeed = g_iYSpeed g_iYGravity;
- g_iY = g_iYSpeed;
-
-
- if(g_iY >= g_rect.bottom-70)
- {
- g_iY= g_rect.bottom - 70;
-
-
- g_iXSpeed = g_iXFriction;
- if(g_iXSpeed < 0)
- g_iXSpeed = 0;
-
-
- g_iYSpeed = g_iYFriction;
- if(g_iYSpeed < 0)
- g_iYSpeed = 0;
-
- g_iYSpeed= -g_iYSpeed;
- }
-
- g_tPre = GetTickCount();
- }
可以发现,小鸟经过几次与地面的接触, 最终会停在窗口的边缘。
经过3 个愤怒的小鸟示例小游戏,匀速和加速运动、重力、摩擦力这样简单的物理建模就被我们掌握了。
1.2 粒子系统初步
1.2.1 基本概念
粒子是一种微小的物体,在数学上通常用点来表示其模型。我们可以把粒子想象成颗粒状的物体, 如雪花、雨滴、沙尘、烟雾等特殊的事物。又比如游戏中的怪物、晶体、材料, 在需要的时候,也可以通过粒子来实现。在C/C++中想要定义一个粒子是非常容易的。基本功扎实的朋友们肯定马上就可以想到,“ 结构体” 是用来定义粒子类型的绝佳武器。原则上用“类” 也可以实现,但是在这里采用“结构体”将更加合适。
如下面的这个结构体snow 便是用来定义“雪花”粒子的:
- struct SNOW
- {
- int x;
- int y;
- BOOL exist;
- };
定义完之后,就可以在这个粒子数组的基础上,用代码进行相关功能的实现了。
8.2.2 雪花飞舞示例程序
在这个示例程序中,我就是采用简单的粒子系统思想来模拟出下雪的唯美景象。程序运行后,会不断地在窗口场景中落下飞舞的雪花, 直到现有雪花数量到达上限时(我们设的数量为80 )才不会再增加。如果雪花落到窗口底部,便让它以随机的X 坐标出现在窗口顶部,这样就可以产生源源不断地落雪的唯美景象了。
我们先来看一看所用的素材图:
程序代码片段一,全局变量声明:-
-
-
- #define WINDOW_WIDTH 800 //为窗口宽度定义的宏,以方便在此处修改窗口宽度
- #define WINDOW_HEIGHT 600 //为窗口高度定义的宏,以方便在此处修改窗口高度
- #define WINDOW_TITLE L"【致我们永不熄灭的游戏开发梦想】粒子系统初步之 雪花飞舞demo" //为窗口标题定义的宏
- #define PARTICLE_NUMBER 80 //表示粒子数量的宏,以方便修改粒子数量
-
-
-
-
- struct SNOW
- {
- int x;
- int y;
- BOOL exist;
- };
-
-
-
-
-
- HDC g_hdc=NULL,g_mdc=NULL,g_bufdc=NULL;
- HBITMAP g_hSnow=NULL,g_hBackGround=NULL;
- DWORD g_tPre=0,g_tNow=0;
- RECT g_rect;
- SNOW SnowFlowers[PARTICLE_NUMBER];
- int g_SnowNum=0;
程序代码片段二, Garne_Init()函数:-
-
-
- BOOL Game_Init( HWND hwnd )
- {
- srand((unsigned)time(NULL));
-
- HBITMAP bmp;
-
- g_hdc = GetDC(hwnd);
- g_mdc = CreateCompatibleDC(g_hdc);
- g_bufdc = CreateCompatibleDC(g_hdc);
- bmp = CreateCompatibleBitmap(g_hdc,WINDOW_WIDTH,WINDOW_HEIGHT);
-
- SelectObject(g_mdc,bmp);
-
-
- g_hBackGround = (HBITMAP)LoadImage(NULL,L"bg.bmp",IMAGE_BITMAP,WINDOW_WIDTH,WINDOW_HEIGHT,LR_LOADFROMFILE);
- g_hSnow = (HBITMAP)LoadImage(NULL,L"snow.bmp",IMAGE_BITMAP,30,30,LR_LOADFROMFILE);
-
- GetClientRect(hwnd,&g_rect);
-
- Game_Paint(hwnd);
- return TRUE;
- }
程序代码片段三, Game_Paint()函数:-
-
-
- VOID Game_Paint( HWND hwnd )
- {
-
-
- SelectObject(g_bufdc,g_hBackGround);
- BitBlt(g_mdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_bufdc,0,0,SRCCOPY);
-
-
- if(g_SnowNum< PARTICLE_NUMBER)
- {
- SnowFlowers[g_SnowNum].x = rand()%g_rect.right;
- SnowFlowers[g_SnowNum].y = 0;
- SnowFlowers[g_SnowNum].exist = true;
- g_SnowNum ;
- }
-
-
-
- for(int i=0;i<PARTICLE_NUMBER;i )
- {
- if(SnowFlowers[i].exist)
- {
-
- SelectObject(g_bufdc,g_hSnow);
- TransparentBlt(g_mdc,SnowFlowers[i].x,SnowFlowers[i].y,30,30,g_bufdc,0,0,30,30,RGB(0,0,0));
-
-
- if(rand()%2==0)
- SnowFlowers[i].x =rand()%6;
- else
- SnowFlowers[i].x-=rand()%6;
-
- SnowFlowers[i].y =10;
-
- if(SnowFlowers[i].y > g_rect.bottom)
- {
- SnowFlowers[i].x = rand()%g_rect.right;
- SnowFlowers[i].y = 0;
- }
- }
-
- }
-
- BitBlt(g_hdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_mdc,0,0,SRCCOPY);
-
- g_tPre = GetTickCount();
- }
最后我们一起看一下运行截图:
1.2.3 星光绽放示例程序
本小节我们再来看一个星光绽放的示例程序,它相当于是一个模拟爆炸(或者说是烟花)特效的demo ,这个特效拿出来讲解很有必要性。这个demo 之中,绽放(爆炸)点为在窗口中由随机数产生的一个位置,绽放(爆炸〉后,会出现很多星光以不同的速度向四方飞散而去,当粒子飞出窗口后或者超出时间后便会消失。每一次爆炸所出现的粒子全部消失后,便会重新出现绽放(爆炸)的画面,以产生不断绽放星光的效果。
接着来看一下所用的图片素材:
然后, 我们详细讲解一下代码。
程序代码片段一, 全局变量声明:
-
-
-
- #define WINDOW_WIDTH 932 //为窗口宽度定义的宏,以方便在此处修改窗口宽度
- #define WINDOW_HEIGHT 700 //为窗口高度定义的宏,以方便在此处修改窗口高度
- #define WINDOW_TITLE L"【致我们永不熄灭的游戏开发梦想】粒子系统初步之 星光绽放demo" //为窗口标题定义的宏
- #define FLYSTAR_NUMBER 100 //表示粒子数量的宏,以方便修改粒子数量
- #define FLYSTAR_LASTED_FRAME 60 //表示粒子持续帧数的宏,以方便修改每次星光绽放持续的时间
-
-
-
-
-
- struct FLYSTAR
- {
- int x;
- int y;
- int vx;
- int vy;
- int lasted;
- BOOL exist;
- };
-
-
-
-
-
- HDC g_hdc=NULL,g_mdc=NULL,g_bufdc=NULL;
- HBITMAP g_hStar=NULL,g_hBackGround=NULL;
- DWORD g_tPre=0,g_tNow=0;
- RECT g_rect;
- FLYSTAR FlyStars[FLYSTAR_NUMBER];
- int g_StarNum=0;
程序代码片段二, Game Init()函数:
-
-
-
- BOOL Game_Init( HWND hwnd )
- {
-
- srand((unsigned)time(NULL));
- HBITMAP bmp;
-
- g_hdc = GetDC(hwnd);
- g_mdc = CreateCompatibleDC(g_hdc);
- g_bufdc = CreateCompatibleDC(g_hdc);
- bmp = CreateCompatibleBitmap(g_hdc,WINDOW_WIDTH,WINDOW_HEIGHT);
-
- SelectObject(g_mdc,bmp);
-
-
- g_hBackGround = (HBITMAP)LoadImage(NULL,L"bg.bmp",IMAGE_BITMAP,WINDOW_WIDTH,WINDOW_HEIGHT,LR_LOADFROMFILE);
- g_hStar = (HBITMAP)LoadImage(NULL,L"star.bmp",IMAGE_BITMAP,30,30,LR_LOADFROMFILE);
-
- GetClientRect(hwnd,&g_rect);
-
- Game_Paint(hwnd);
- return TRUE;
- }
以上这段代码也就是初始化了随机时间种子,创建了几个兼容DC ,载入了位图资源,与之前示例程序的做法差不多。
程序代码片段三, Game_Paint()函数:
-
-
-
- VOID Game_Paint( HWND hwnd )
- {
-
-
- SelectObject(g_bufdc,g_hBackGround);
- BitBlt(g_mdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_bufdc,0,0,SRCCOPY);
-
-
- if(g_StarNum == 0)
- {
- int x=rand()%g_rect.right;
- int y=rand()%g_rect.bottom;
-
- for(int i=0;i<FLYSTAR_NUMBER;i )
- {
- FlyStars[i].x = x;
- FlyStars[i].y = y;
- FlyStars[i].lasted = 0;
-
- if(i%4==0)
- {
- FlyStars[i].vx = -(1 rand());
- FlyStars[i].vy = -(1 rand());
- }
- if(i%4==1)
- {
- FlyStars[i].vx = 1 rand();
- FlyStars[i].vy = 1 rand();
- }
- if(i%4==2)
- {
- FlyStars[i].vx = -(1 rand());
- FlyStars[i].vy = 1 rand();
- }
- if(i%4==3)
- {
- FlyStars[i].vx = 1 rand();
- FlyStars[i].vy = -(1 rand());
- }
- FlyStars[i].exist = true;
- }
- g_StarNum = FLYSTAR_NUMBER;
- }
-
-
-
- for(int i=0;i<FLYSTAR_NUMBER;i )
- {
- if(FlyStars[i].exist)
- {
- SelectObject(g_bufdc,g_hStar);
- TransparentBlt(g_mdc,FlyStars[i].x,FlyStars[i].y,30,30,g_bufdc,0,0,30,30,RGB(0,0,0));
-
-
- FlyStars[i].x =FlyStars[i].vx;
- FlyStars[i].y =FlyStars[i].vy;
-
-
- FlyStars[i].lasted ;
-
- if(FlyStars[i].x<=-10 || FlyStars[i].x>g_rect.right || FlyStars[i].y<=-10 || FlyStars[i].y>g_rect.bottom || FlyStars[i].lasted>FLYSTAR_LASTED_FRAME)
- {
- FlyStars[i].exist = false;
- g_StarNum--;
- }
- }
- }
-
-
- BitBlt(g_hdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_mdc,0,0,SRCCOPY);
-
- g_tPre = GetTickCount();
- }
最后看一下运行截图:
1.3 章节小憩
嗯,根据最基础的物理知识写出来的小游戏场景demo 还是具有一定的启发意义的吧。虽然是用GDI 来实现的,画面在当今这个时代肯定算不上优秀, 但是毕竟基本的思想都在那里。