天津理工大学2010届本科毕业设计说明书
游戏启动 Active() 停止状态 (Game End) 运行状态 (Active) Game End() Destroy() 图3.1 整体游戏流程
DestroyApp() 暂停状态 (Destroyed)
游戏引擎创建,名称为Game Engine。它用于游戏程序的外部王文,使用hinstance 和
hwindow成员变量将游戏的应用程序实例和窗口句柄存储在游戏引擎中。 子画面管理器
子画面管理器集成在了gamEngine中,是一组函数,它主要负责的功能有: 1.向子画面列表中添加子画面。 2.绘制所有子画面。 3.更新子画面。 4.清楚子画面。
5.测试一个点是否在子画面之内。 6.能够响应子画面的碰撞。
子画面的碰撞体系:
3.3 数据模型
3.3.1 Sprite 类
其中如位置矩形,速度 等等变量很好理解,这里只说明 边界矩形。边界矩形一般可以认为是游戏屏幕的大小,但是有时候可能会希望它在固定的区域内移动所以在这里很有必要去限制一下。,并且此处还有值得一提的就是子画面的边界动作。本游戏中有四中便捷动作:停止,环绕,弹开和删除。
- 7 -
天津理工大学2010届本科毕业设计说明书
开始 每一个sprite调用 sprite::update()返回sprite判断sprite 是否需要销在内存中后sprite列表中删除。 删再除,然调用GameEngine::checkSpriteCollision循环列表,任何两个Sprite用 testCollision()检测是否碰撞 碰撞:全局函数 SpriteCollision(); 返回 TRUE,也就是checkSpriteCollision()返回值 为碰撞:返回FALSE,也就是checkSpriteCollision()返回值 TRUE,将还原此次循环的update,FALSE则继续前进。 结束 图3.2 碰撞流程图
Sprite类的成员函数除了各种访问函数外还有:更新(update),显示(draw)和判断一个点是否在子画面之内(isPointInside)。
- 8 -
天津理工大学2010届本科毕业设计说明书
3.3.2 TankSprite类
首先坦克是一种子画面,所以公有继承 sprite。他与sprite更加具体的主要功能是在显示时应当能更够现实大炮和底座分别显示,所以要添加大炮的总帧数和当前帧两个成员变量。
对于成员函数。构造函数和析构函数的重写是一定的,在此处构造函数只是多了一个gun位图的参数,析构函数不变。
值得注意的是:再重写draw()函数时,当显示完底座后在显示gun时需要确定,gun的位置gun的 帧数(numframes),当前帧(curframe)等等。
其中gun的中心 应当位于base的中心,而gunposition应当根据base 的 position计算。首先计算出base中心坐标,gun中心与base中心相同,然后计算gun位置。
在现实的时候利用虚函数的动态绑定,使sprite管理函数 可以调用tanksprite的draw()函数。此处的原理为:虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。
构造函数:
TankSprite::TankSprite(Bitmap* pGunBitmap,Bitmap* pBitmap, RECT& rcBounds, BOUNDSACTION baBoundsAction) {
SetRect(&m_rcGunPosition,
(m_rcPosition.left+pBitmap->GetWidth()/2) -m_pGunBitmap->GetWidth m_iGunNumFrames=1; m_iGunCurFrame=0; m_pGunBitmap=pGunBitmap;
: Sprite(pBitmap, rcBounds,baBoundsAction)
()/2,(m_rcPosition.top
+pBitmap->GetHeight()/(2*m_iNumFrames))-m_pGunBitmap->GetHeight()/(2*m_iGunNumFrames),
(m_rcPosition.left+pBitmap->GetWidth()/2) +m_pGunBitmap->GetWidth ()/2 ,
(m_rcPosition.top
+pBitmap->GetHeight()/(2*m_iNumFrames))+m_pGunBitmap->GetHeight()/(2*m_iGunNumFrames)); }
- 9 -
天津理工大学2010届本科毕业设计说明书
当程序发现虚函数名前的关键字virtual后,会自动将其作为动态联编处理,即在程序运行时动态地选择合适的成员函数。
动态联编规定,只能通过指向基类的指针或基类对象的引用来调用虚函数,其格式: 指向基类的指针变量名->虚函数名(实参表)或 基类对象的引用名. 虚函数名(实参表) 虚函数是C++多态的一种表现,在游戏中的具体体现为: void TankSprite::Draw(HDC hDC) {
if (m_pBitmap != NULL && !m_bHidden) {
if (m_iNumFrames == 1)
m_pBitmap->Draw(hDC, m_rcPosition.left, m_rcPosition.top, TRUE); else
m_pBitmap->DrawPart(hDC, m_rcPosition.left, m_rcPosition.top, 0, m_iCurFrame * GetHeight(), GetWidth(), GetHeight(), TRUE); }
m_pGunBitmap->DrawPart(hDC, m_rcGunPosition.left, m_rcGunPosition.top,
0, m_iGunCurFrame * GetGunHeight(), GetGunWidth(), GetGunHeight(), TRUE);
3.3.3 Bitmap类
此类的数据成员只有 一个位图句柄。它的任务是以各种方式显示位图,并且可以存储一void Draw(HDC hDC, int x, int y, BOOL bTrans = FALSE, COLORREF crTransColor = RGB(255, 0, 255));
void DrawPart(HDC hDC, int x, int y, int xPart, int yPart, int wPart, int hPart, BOOL bTrans = FALSE, COLORREF crTransColor = RGB(255, 0, 255));
部分显示图片利用了win32的 Bitblt()函数绘制,而整体绘制只是简单的调用部分绘制,他只是把一整张图片划分成一个部分而已。
三个构造函数,第一个负责从文件中加载位图,第二个负责从资源中加载位图,最后一个一个用迂绘制空白的位图。
些位图的信息。
- 10 -
天津理工大学2010届本科毕业设计说明书
开始 游戏循环:使用迭代器更新子画面列表。GameEngine::UpdateSprites() vector
3.3.4 游戏引擎
我们可以把游戏的引擎比作赛车的引擎,大家知道,引擎是赛车的心脏,决定着赛车的性能和稳定性,赛车的速度、操纵感这些直接与车手相关的指标都是建立在引擎的基础上的。游戏也是如此,玩家所体验到的剧情、关卡、美工、音乐、操作等内容都是由游戏的引擎直接控制的,它扮演着中场发动机的角色,把游戏中的所有元素捆绑在一起,在后台指挥它们同时、有序地工作。简单地说,引擎就是“用于控制所有游戏功能的主程序,从计算碰撞、物理系统和物体的相对位置,到接受玩家的输入,以及按照正确的音量输出声音等等。
- 11 -