赛车游戏的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++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo

C#反射编程之GetConstructor()方法解读

《C#反射编程之GetConstructor()方法解读》C#中Type类的GetConstructor()方法用于获取指定类型的构造函数,该方法有多个重载版本,可以根据不同的参数获取不同特性的构造函... 目录C# GetConstructor()方法有4个重载以GetConstructor(Type[]

C++11的函数包装器std::function使用示例

《C++11的函数包装器std::function使用示例》C++11引入的std::function是最常用的函数包装器,它可以存储任何可调用对象并提供统一的调用接口,以下是关于函数包装器的详细讲解... 目录一、std::function 的基本用法1. 基本语法二、如何使用 std::function

Python开发围棋游戏的实例代码(实现全部功能)

《Python开发围棋游戏的实例代码(实现全部功能)》围棋是一种古老而复杂的策略棋类游戏,起源于中国,已有超过2500年的历史,本文介绍了如何用Python开发一个简单的围棋游戏,实例代码涵盖了游戏的... 目录1. 围棋游戏概述1.1 游戏规则1.2 游戏设计思路2. 环境准备3. 创建棋盘3.1 棋盘类

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor