vc++游戏编程指南 联系客服

发布时间 : 星期日 文章vc++游戏编程指南更新完毕开始阅读479513671ed9ad51f01df2a1

第八章 支撑游戏的基石 1

第七章 我没有想好名字

如果你只靠上面几章所讲述的知识编了个游戏,喜欢的人恐怕会不多?,为什么?因为没有人会玩一个控制不流畅而且声音效果不佳的游戏。为了在游戏中更好地管理各种输入设备,我们需要使用DirectInput。而通过使用DirectX Audio可以在游戏中实现各种更逼真的音乐效果。它们都是DirectX的重要组成部分。使用DirectInput前我们需要#include 并在工程中加入dinput8.lib和dxguid.lib,而使用DirectX Audio前我们需要#include 并在工程中加入dsound.lib和dxguid.lib。

7.1 读取键盘数据

首先,我们必须创建一个DirectInput8对象(DirectX 9.0并没有对DInput和DAudio做多大改动),就像这样:

LPDIRECTINPUT8 pInput;

DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&pInput, NULL);

然后,我们需要创建一个DirectInput设备:

LPDIRECTINPUTDEVICE8 pDev;

pInput->CreateDevice(GUID_SysKeyboard, &pDev, NULL);

设置好它的数据格式:

pDev->SetDataFormat(&c_dfDIKeyboard);

设置它的协作级,这里设为独占设备+前台:

pDev->SetCooperativeLevel(hwnd,DISCL_EXCLUSIVE|DISCL_FOREGROUND);

获取设备:

pDev->Acquire();

像上面那样初始化后,我们就已经把Windows对键盘的控制权剥夺了,以后的键盘消息将不会被送入消息循环,我们可以把消息循环中处理键盘消息的语句拿掉了。当然,这时我们需要在程序的适当地方,比如说在刷新游戏时,加入对键盘数据进行读取和处理的语句,就像下面的一段程序:

第八章 支撑游戏的基石 2

#define KEYDOWN(key) (buffer[key] & 0x80) //定义一个宏,方便处理键盘数据 char buffer[256]; //键盘数据

pDev->GetDeviceState(sizeof(buffer),(LPVOID)&buffer); //得到键盘数据 if (KEYDOWN(DIK_XXX)) //如果XXX键被按下…(请参阅附录二) { }

哈哈,真是挺方便的。有时候真的有点怀疑DirectX是不是一种回到遥远的可爱的DOS时…… //处理其它键

…… //处理之

代的“倒退”。因为无论是DirectInput还是DirectDraw都是太像DOS下的做法了。

7.2 读取鼠标数据

读取鼠标数据和读取键盘数据的步骤差不多,首先也是要创建设备:

pInput->CreateDevice(GUID_SysMouse, &pDev, NULL); pDev->SetDataFormat(&c_dfDIMouse);

设置数据格式:

设置协作级:

pDev->SetCooperativeLevel(hwnd,DISCL_EXCLUSIVE | DISCL_FOREGROUND);

获取设备:

pDev->Acquire();

那么怎样读取鼠标数据呢?如果要取得鼠标的当前状态,这样即可: DIMOUSESTATE mouse_stat; //鼠标状态 //得到鼠标状态

pDev->GetDeviceState(sizeof(DIMOUSESTATE),(LPVOID)&mouse_stat); 得到的mouse_stat是一个DIMOUSESTATE类型的结构,它有四个成员:lX,lY,lZ和rgbButtons[4]。其中lX、lY和lZ分别是自上次调用此函数以来鼠标在X轴、Y轴和Z轴(滚轮)方向上移动的距离,而不是鼠标此时的坐标;其距离单位不是像素,但你完全可以把它看做以像素为单位。所以,我们需要定义两个变量mousex=0和mousey=0,然后把lX和lY累加上去即可。这样做的好处是鼠标坐标不再受屏幕的制约,而且屏幕中心的mousex和mousey值可以永远是0,不随屏幕分辨率而改变。rgbButtons是一个存储哪些鼠标键被按下的数组,我们可以这样做来读取它:

//定义一个宏,方便处理鼠标数据

第八章 支撑游戏的基石 3

#define MOUSEBUTTONDOWN(b) (mouse_stat.rgbButtons[b]&0x80)

if (MOUSEBUTTONDOWN(0)) //如果左键被按下… { }

…… //处理右键(1)和中键(2)

…… //处理之

7.3 恢复和关闭DirectInput

7.3.1 恢复DirectInput设备

就像在DirectDraw中那样,使用DirectInput的程序被最小化时DirectInput设备会出现\丢失\现象。恢复的办法很干脆:先关闭DirectInput再重新初始化即可。

7.3.2 关闭DirectInput

关闭DirectInput也是非常简单的(SAFE_RELEASE的定义在4.8节): pDev->Unacquire( ); SAFE_RELEASE(pDev); SAFE_RELEASE(pInput);

7.4 初始化和关闭DirectX Audio

7.4.1 初始化DirectX Audio

使用DirectX Audio前,按规矩还是要先初始化。在下面的这段初始化程序中要用到三个DXAudio提供的对象:IDirectMusicLoader8、IDirectMusicPerformance8和IDirectMusicSegment8。IDirectMusicLoader8顾名思义是用来调入音乐的,IDirectMusicPerformance8可以认为是音频设备,而IDirectMusicSegment8就是代表音乐。

#include IDirectMusicLoader8*

pLoader= NULL;

pPerf = NULL; pSeg = NULL;

IDirectMusicPerformance8* IDirectMusicSegment8*

CoInitialize(NULL); //初始化COM

第八章 支撑游戏的基石 4

CoCreateInstance(CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC, IID_IDirectMusicLoader8, (void**)&pLoader); //创建pLoader对象

CoCreateInstance(CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC, IID_IDirectMusicPerformance8, (void**)&pPerf ); //创建pPerf对象 pPerf->InitAudio(

NULL, //这里可以是一个指向IDirectMusic*对象的指针 NULL, //这里可以是一个指向IDirectSound*对象的指针 hwnd, //窗口句柄

DMUS_APATH_SHARED_STEREOPLUSREVERB, //AudioPath类型

//这里打开了立体声及混响,效果很不错

64, //音乐通道数

DMUS_AUDIOF_ALL, //使用声卡的所有特性

NULL //可以指向一个DMUS_AUDIOPARAMS对象,更详细地说明各种参数 );

7.4.2 关闭DirectX Audio

关闭DXAudio还是老思路,先按7.5.3节的办法停止音乐,然后Release即可:

pPerf->CloseDown(); //关闭

SAFE_RELEASE(pLoader); //释放对象 SAFE_RELEASE(pPerf); SAFE_RELEASE(pSeg);

CoUninitialize(); //停止使用COM

7.5 播放MIDI和WAV音乐

MIDI音乐和WAV音乐在游戏编程中经常用到。其中前者一般是用作背景音乐,而后者多是用在各种音效方面,如发射导弹等等。虽然我们可以用3.4.4节的方法,但使用DXAudio可以更充分地利用硬件资源,从而实现更少的CPU占用率。方法如下: