赛车游戏的2D 编程(VC++)

2024-05-03 21:48
文章标签 c++ 编程 游戏 赛车 2d

本文主要是介绍赛车游戏的2D 编程(VC++),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

                          赛车游戏的2D 编程

转载请注明出处

本文章的下载地址,请单击此链接

 

         赛车是一个简单的游戏,可是麻雀虽小,五脏具全。它用DDraw实现了精灵的绘制,用DSound

实现游戏音效,用DInput 实现了键盘和鼠标接口,用DPlay实现了联网。

游戏运行的初始界面如图3.18 所示,游戏的竞赛场面如图3.19 所示。

这个游戏使用基础库cMain.libcMain.lib库是打包的DirectX库。在编译这个工程前,要确保自

己的计算机上安装了DirectX SDK 8.0或者9.0(注意是DirectX SDK,不是运行库)。如果已经安装了

SDK,编译仍有问题,那么请检查一下DXincludelibrary路径是否已经包括在VC++Option

列表中。

 

                                                  图3.18赛车游戏初始运行图

  

 

                                                   图3.19赛车游戏运行图

 

3.8.1 cMain 游戏库

打开工程文件(.dsw)的时候会发现该工程中包括了两个项目。一个项目是运行程序,它调用了

cMain 库。而另一个项目是就DirectX的打包库cMain,这个打包库几乎包括了游戏可能需要的所有功

能。这个库包含了14 个类。下面就来介绍这些类。

_ cApplication

classcApplication

{

protected:

LPSTRm_lpszAppName;

LPSTRm_lpszwndClassName;

DWORDm_ColorDepth;

DWORDm_ScreenHeight;

DWORDm_ScreenWidth;

public:

BOOLm_bActive;

voidPreventFlip();

boolm_bDontFlip;

HWNDGetMainWnd();

LPDIRECTDRAW7GetDirectDraw();

LPDIRECTDRAW7m_pDD;

LPDIRECTDRAWSURFACE7m_pFrontBuffer;

LPDIRECTDRAWSURFACE7m_pBackBuffer;

cApplication();

~cApplication();

staticHINSTANCE m_hInst;

staticHINSTANCE GetInstHandle() { return m_hInst; };

BOOLInitApplication();

BOOLRunApplication();

BOOLInitDirectX();

virtualvoid ExitApp();

virtualvoid DoIdle();

virtualvoid AppInitialized();

private:

cWindowm_pWindow;

};

cApplication 类是一个简单的Win 32程序框架的封装。既然要用DirectX,那么这个类就负责为

DirectDraw 创建基本的框架。在cMain库中,会发现一个全局函数CreateApplication(),它就负责这项工

作。CreateApplication()是一个虚函数,它需要在游戏自身的项目中创建而且需要返回应用程序的实例。

在游戏创建过程中,cApplication 类中有3 个很重要的虚函数,它们是AppInitializedExitApp

DoIdle 函数。

当应用程序开始启动的时候需要调用AppInitialized函数。当退出游戏的时候,需要调用ExitApp

它负责销毁AppInitialized 创建时分配的内存和其他资源。当没有任何窗口消息需要处理的时候,

cApplication 类将调用DoIdle虚函数,从而允许用户处理自己的游戏。

_ cWindow

如果注意cApplication 类的声明,会看到它定义了一个cWindow 类成员变量。cWindow类负责在

游戏中创建主窗口。这个类只在库内部使用,所以没有必要去修改它的属性。

_ cInputDevicecKeyboardcMouse

cInputDevice 类代码如下所示:

classcInputDevice

{

private:

staticint m_iRefCount;

protected:

staticLPDIRECTINPUT8 m_lpDI;

public:

cInputDevice();

virtual~cInputDevice();

BOOLCreate()

{

HRESULThRet;

if(!m_lpDI)

{

hRet=DirectInput8Create(GetMainApp()->GetInstHandle(),DIRECTINPUT_VERSION,

IID_IDirectInput8,(void**)&m_lpDI, NULL);

ifFAILED(hRet)

returnFALSE;

}

//引用计数递增

m_iRefCount++;

returnTRUE;

}

voidDestroy()

{

142 Visual C++游戏开发技术与实例

m_iRefCount--;

if(m_iRefCount== 0)

{

if(m_lpDI!= NULL){

m_lpDI->Release();

m_lpDI= NULL;

}

}

}

};

cKeyboard 类代码如下所示:

classcKeyboard : cInputDevice

{

private:

staticLPDIRECTINPUTDEVICE8 m_lpDIKeyboard;

staticchar* m_KbdBuffer;

public:

BOOLCheckKey(const int cKey);

voidProcess();

voidDestroy();

BOOLCreate();

cKeyboard();

virtual~cKeyboard();

};

cMouse 类代码如下所示:

classcMouse : cInputDevice

{

public:

cMouse();

virtual~cMouse();

private:

longm_lXPos;

longm_lYPos;

DWORDm_bButton0;

DWORDm_bButton1;

staticLPDIRECTINPUTDEVICE8 m_lpDIMouse;

HANDLEm_hMouseEvent;

public:

DWORDGetX() { return m_lXPos; };

DWORDGetY() { return m_lYPos; };

BOOLGetRightButton() { return m_bButton1; };

BOOLGetLeftButton() { return m_bButton0; };

voidProcess();

voidDestroy();

BOOLCreate();

};

3 个类主要处理用户在游戏中的输入信息。既然鼠标和键盘的处理依赖于DirectInput框架,所

第3 章2D 游戏开发143

以需要一个类用来初始化DirectInput 主对象,这就是cInputDevice 类。

cInputDevice 类中有一个指向DirectInput接口的指针和引用计数。引用计数用来确定当前使用

DirectInput 主接口的类有多少个。注意引用计数和接口指针都是静态变量。cMouse类和cKeyboard

都是从cInputDevice 类继承而来,使用同样的DirectInput 主对象。

cKeyboard 类关心键盘的输入。它有一个静态的变量,用来缓冲每个键值的状态。由于这个缓冲

是静态的,它允许在代码中任意一个地方创建cKeyboard对象,而使用同一块buffer

cMouse 类关心鼠标的输入,它的工作原理和cKeyboard类类似。每次调用Process()函数的时候,

它改变内部变量从而反映鼠标在当前屏幕的位置和状态。

_ cSurface 类和cSprite

cSurface 类声明如下:

struct SURFACE_SOURCE_INFO

{

HINSTANCE m_hInstance;

UINT m_nResource;

int m_iX;

int m_iY;

int m_iWidth;

int m_iHeight;

};

class cSurface

{

public:

SURFACE_SOURCE_INFO m_srcInfo;

void Restore();

LPDIRECTDRAWSURFACE7 GetSurface();

UINT Width();

UINT Height();

void Destroy();

COLORREF m_ColorKey;

BOOL Draw(LPDIRECTDRAWSURFACE7 lpDest, int iDestX= 0, int iDestY = 0, int iSrcX

= 0, int iSrcY = 0, int nWidth = 0, int nHeight =0);

BOOL Create(int nWidth, int nHeight, COLORREFdwColorKey = -1);

BOOL LoadBitmap(HINSTANCE hInst, UINT nRes, intnX = 0, int nY = 0, int nWidth =

0, int nHeight = 0);

cSurface(HINSTANCE hInst, UINT nResource, intnWidth, int nHeight, COLORREF

dwColorKey = -1);

cSurface();

virtual ~cSurface();

protected:

UINT m_Height;

UINT m_Width;

LPDIRECTDRAWSURFACE7 m_pSurface;

};

cSprite 类声明如下:

class cSprite

144 Visual C++游戏开发技术与实例

{

public:

void Rewind();

BOOL IsBegin();

BOOL IsEnd();

int m_iSpriteHeight;

int m_iSpriteWidth;

void Previous();

void Next();

int m_iRows;

int m_iCols;

int m_iAbsolutePosition;

BOOL Create(HINSTANCE hInst, UINT nResource, intiTileWidth, int iTileHeight,

COLORREF dwColorKey, int iSpriteWidth,intiSpriteHeight);

BOOL Draw(LPDIRECTDRAWSURFACE7 lpDest, intiDestX, int iDestY, BOOL bAdvance = TRUE,

int iSrcX=0, int iSrcY=0, int iWidth = -1, intiHeight = -1);

void Destroy();

cSurface m_surfTile;

cSprite();

virtual ~cSprite();

};

页面类cSurface DirectX页面对象的打包。cSurface是一个结构,在显存中它拥有游戏中所用到

的图形,这样在游戏的每次循环中都可以轻松地重新绘制屏幕。

cSprite 类是处理精灵的打包类。它拥有一个cSurface类的成员变量和相关精灵的信息。通过这个

类,可以自动的使精灵走动,而不用担心源页面的位置和大小。

_ cSoundInterfacecSoundcWavFile

cSoundInterface 类声明如下:

class cSoundInterface

{

protected:

static LPDIRECTSOUND8 m_pDS;

static LPDIRECTSOUNDBUFFER m_pDSBPrimary;

public:

void SetListernerPosition(float fX, float fY,float fZ);

void Destroy();

LPDIRECTSOUND8 GetDirectSound();

cSoundInterface();

HRESULT Initialize( HWND hWnd, DWORD dwCoopLevel,DWORD dwPrimaryChannels = 2,

DWORD dwPrimaryFreq = 22050, DWORDdwPrimaryBitRate = 16);

HRESULT SetPrimaryBufferFormat(DWORDdwPrimaryChannels, DWORD dwPrimaryFreq, DWORD

dwPrimaryBitRate );

virtual ~cSoundInterface();

};

cSound 类声明如下:

class cSound

{

private:

第3 章2D 游戏开发145

DWORD m_dwDSBufferSize;

cWavFile* m_pWaveFile;

public:

void Destroy();

void SetVelocity(float fX, float fY, float fZ);

void SetPosition(float fX, float fY, float fZ);

LPTSTR m_sFileName;

HRESULT Stop(BOOL bOverride = FALSE);

BOOL m_bIsPlaying;

LPDIRECTSOUND3DBUFFER Get3DInterface();

HRESULT RestoreBuffer(BOOL *bRestored);

HRESULT Play(DWORD dwPriority = 0, DWORD dwFlags= 0);

LPDIRECTSOUNDBUFFER m_pSoundBuffer;

LPDIRECTSOUND3DBUFFER m_p3DInterface;

HRESULT Create(LPTSTR lpszFileName,DWORDdwCreationFlags,GUID guid3DAlgorithm);

cSound();

virtual ~cSound();

protected:

HRESULT FillBuffer();

};

cWavFile 类声明如下:

class cWavFile

{

public:

WAVEFORMATEX* m_pwfx; // Pointer to WAVEFORMATEXstructure

HMMIO m_hmmio; // MM I/O handle for the WAVE

MMCKINFO m_ck; // Multimedia RIFF chunk

MMCKINFO m_ckRiff; // Use in opening a WAVE file

DWORD m_dwSize; // The size of the wave file

MMIOINFO m_mmioinfoOut;

DWORD m_dwFlags;

BOOL m_bIsReadingFromMemory;

BYTE* m_pbData;

BYTE* m_pbDataCur;

ULONG m_ulDataSize;

CHAR* m_pResourceBuffer;

protected:

HRESULT ReadMMIO();

HRESULT WriteMMIO( WAVEFORMATEX *pwfxDest );

public:

cWavFile();

~cWavFile();

HRESULT Open( LPTSTR strFileName, WAVEFORMATEX*pwfx, DWORD dwFlags );

HRESULT OpenFromMemory( BYTE* pbData, ULONGulDataSize, WAVEFORMATEX* pwfx, DWORD

dwFlags );

HRESULT Close();

146 Visual C++游戏开发技术与实例

HRESULT Read( BYTE* pBuffer, DWORD dwSizeToRead,DWORD* pdwSizeRead );

HRESULT Write( UINT nSizeToWrite, BYTE* pbData,UINT* pnSizeWrote );

DWORD GetSize();

HRESULT ResetFile();

WAVEFORMATEX* GetFormat() { return m_pwfx; };

};

3 个类主要负责游戏中声音的处理。cSoundInterface创建DirectSound主对象,从而创建了游戏

中的声音缓冲。推荐在cApplication 类中的AppInitializad 虚函数中初始化这个类,这样就可以在游戏

开始之前初始化声音接口。

cSound 类拥有游戏中声音缓冲。它兼容了DirectSound缓冲的所有普通属性,例如频率、3D声音

和重复。cSound 类使用cWavFile对象从资源或从文件中导入声音。这是一个波形文件的导入类。

_ cMultiplayer cMessageHandler

cMultiplayer 类声明如下:

这篇关于赛车游戏的2D 编程(VC++)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/957721

相关文章

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

如何高效移除C++关联容器中的元素

《如何高效移除C++关联容器中的元素》关联容器和顺序容器有着很大不同,关联容器中的元素是按照关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的,本文介绍了如何高效移除C+... 目录一、简介二、移除给定位置的元素三、移除与特定键值等价的元素四、移除满足特android定条件的元

Python获取C++中返回的char*字段的两种思路

《Python获取C++中返回的char*字段的两种思路》有时候需要获取C++函数中返回来的不定长的char*字符串,本文小编为大家找到了两种解决问题的思路,感兴趣的小伙伴可以跟随小编一起学习一下... 有时候需要获取C++函数中返回来的不定长的char*字符串,目前我找到两种解决问题的思路,具体实现如下:

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++