赛车游戏的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++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra

C++构造函数中explicit详解

《C++构造函数中explicit详解》explicit关键字用于修饰单参数构造函数或可以看作单参数的构造函数,阻止编译器进行隐式类型转换或拷贝初始化,本文就来介绍explicit的使用,感兴趣的可以... 目录1. 什么是explicit2. 隐式转换的问题3.explicit的使用示例基本用法多参数构造

C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解

《C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解》:本文主要介绍C++,C#,Rust,Go,Java,Python,JavaScript性能对比全面... 目录编程语言性能对比、核心优势与最佳使用场景性能对比表格C++C#RustGoJavapythonjav

C++打印 vector的几种方法小结

《C++打印vector的几种方法小结》本文介绍了C++中遍历vector的几种方法,包括使用迭代器、auto关键字、typedef、计数器以及C++11引入的范围基础循环,具有一定的参考价值,感兴... 目录1. 使用迭代器2. 使用 auto (C++11) / typedef / type alias

C++ scoped_ptr 和 unique_ptr对比分析

《C++scoped_ptr和unique_ptr对比分析》本文介绍了C++中的`scoped_ptr`和`unique_ptr`,详细比较了它们的特性、使用场景以及现代C++推荐的使用`uni... 目录1. scoped_ptr基本特性主要特点2. unique_ptr基本用法3. 主要区别对比4. u

C++11中的包装器实战案例

《C++11中的包装器实战案例》本文给大家介绍C++11中的包装器实战案例,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录引言1.std::function1.1.什么是std::function1.2.核心用法1.2.1.包装普通函数1.2.

C++多线程开发环境配置方法

《C++多线程开发环境配置方法》文章详细介绍了如何在Windows上安装MinGW-w64和VSCode,并配置环境变量和编译任务,使用VSCode创建一个C++多线程测试项目,并通过配置tasks.... 目录下载安装 MinGW-w64下载安装VS code创建测试项目配置编译任务创建 tasks.js

C++ 多态性实战之何时使用 virtual 和 override的问题解析

《C++多态性实战之何时使用virtual和override的问题解析》在面向对象编程中,多态是一个核心概念,很多开发者在遇到override编译错误时,不清楚是否需要将基类函数声明为virt... 目录C++ 多态性实战:何时使用 virtual 和 override?引言问题场景判断是否需要多态的三个关

C++简单日志系统实现代码示例

《C++简单日志系统实现代码示例》日志系统是成熟软件中的一个重要组成部分,其记录软件的使用和运行行为,方便事后进行故障分析、数据统计等,:本文主要介绍C++简单日志系统实现的相关资料,文中通过代码... 目录前言Util.hppLevel.hppLogMsg.hppFormat.hppSink.hppBuf