赛车游戏的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++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

c++中的set容器介绍及操作大全

《c++中的set容器介绍及操作大全》:本文主要介绍c++中的set容器介绍及操作大全,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录​​一、核心特性​​️ ​​二、基本操作​​​​1. 初始化与赋值​​​​2. 增删查操作​​​​3. 遍历方

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

C++11委托构造函数和继承构造函数的实现

《C++11委托构造函数和继承构造函数的实现》C++引入了委托构造函数和继承构造函数这两个重要的特性,本文主要介绍了C++11委托构造函数和继承构造函数的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、委托构造函数1.1 委托构造函数的定义与作用1.2 委托构造函数的语法1.3 委托构造函

C++11作用域枚举(Scoped Enums)的实现示例

《C++11作用域枚举(ScopedEnums)的实现示例》枚举类型是一种非常实用的工具,C++11标准引入了作用域枚举,也称为强类型枚举,本文主要介绍了C++11作用域枚举(ScopedEnums... 目录一、引言二、传统枚举类型的局限性2.1 命名空间污染2.2 整型提升问题2.3 类型转换问题三、C

C++链表的虚拟头节点实现细节及注意事项

《C++链表的虚拟头节点实现细节及注意事项》虚拟头节点是链表操作中极为实用的设计技巧,它通过在链表真实头部前添加一个特殊节点,有效简化边界条件处理,:本文主要介绍C++链表的虚拟头节点实现细节及注... 目录C++链表虚拟头节点(Dummy Head)一、虚拟头节点的本质与核心作用1. 定义2. 核心价值二

C++ 检测文件大小和文件传输的方法示例详解

《C++检测文件大小和文件传输的方法示例详解》文章介绍了在C/C++中获取文件大小的三种方法,推荐使用stat()函数,并详细说明了如何设计一次性发送压缩包的结构体及传输流程,包含CRC校验和自动解... 目录检测文件的大小✅ 方法一:使用 stat() 函数(推荐)✅ 用法示例:✅ 方法二:使用 fsee