ImageVerifierCode 换一换
格式:DOCX , 页数:32 ,大小:41.74KB ,
资源ID:6204842      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6204842.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(网络游戏客户端编程第15章.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

网络游戏客户端编程第15章.docx

1、网络游戏客户端编程第15章第十五章 游戏开发其他知识游戏是一个非常复杂的软件,它包括很多技术,在之前的章节我们介绍的网络游戏客户端编程中的UI编程、图形渲染、网络编程、物理模拟等技术。然而游戏客户端还有很多重要的技术,本章就将介绍常用的几种技术,当然这些技术大都是以第三方库的形式直接提供,读者只要明白其原理,懂得应用方法就可以了。目标 理解和掌握游戏程序接受用户输入的方法 理解和掌握DirectX Audio实现声音的方法 了解图片解码的相关知识 了解字体库FreeType的使用方法 了解资源打包相关的概念15.1 DirectX Input 入门输入相对于图形和声音而言从未成为游戏开发中的非

2、常重要的论题。读取键盘按键、鼠标移动和游戏杆位置似乎并没有什么困难,但随着新输入设备对市场的强烈冲击以及DirectX的发行,这一问题变得日益重要了。这里我们将介绍DirectInput的基本应用。DirectInput和Direct3D一样也是DirectX中的一个组件,DirectInput支持通过常用的输入设备获取用户输入信息,常用的输入设备如键盘、鼠标、游戏杆。DirectInput相关的接口在头文件dinput.h中定义,所以使用DirectInput需要包含dinput.h。当我们需要使用DirectInput的时候需要创建DirectInput实例,使用下面语句就可以简单的创建D

3、irectInput实例。if( FAILED( hr = DirectInput8Create( GetModuleHandle( NULL ), DIRECTINPUT_VERSION, IID_IDirectInput8, ( VOID* )&g_pDI, NULL ) ) ) return hr;其中DirectInput8Create函数原型是: HRESULT WINAPI DirectInput8Create(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter)

4、;参数定义: hinst是使用DirectInput的程序的实例; dwVersion是DirectInput的版本号; riidltf是需要创建实例的接口的ID; ppvOut用于返回DirectInput实例的地址; punkOuter是用于返回IUnKnown接口,一般情况设置为NULL。当我们需要从什么设备上获取输入信息的时候,我们需要创建设备接口。通过设备接口,我们可以通过设备接口来获取输入信息。下面就是使用DirectInput实例的CreateDevice方法创建设备接口的代码。if( FAILED( g_pDI-CreateDevice( GUID_SysMouse, &g_p

5、Mouse, NULL ) ) ) MessageBox( NULL, TEXT( Mouse not found. The sample will now exit. ), TEXT( DirectInput Sample ), MB_ICONERROR | MB_OK ); EndDialog( hDlg, 0 ); return S_OK;其中CreateDevice函数原型是:HRESULT CreateDevice( REFGUID rguid,LPDIRECTINPUTDEVICE *lplpDirectInputDevice,LPUNKNOWN pUnkOuter);参数定义:

6、rguid是用来指定需要创建的设备的类型ID,如GUID_SysMouse; lplpDirectInputDevice用于返回设备接口的地址; pUnkOuter是用于返回IUnKnown接口,一般情况设置为NULL。 从设备获取数据之前,必须先设置其数据格式。这只是一个在设备的状态改变后获取数据包并与已知结构进行匹配的问题。例如,从游戏杆得到的数据包显然和从鼠标那里得来的不一样:格式的大小不同,并且按照按钮和轴组合的不同有不同格式大小的值。设置数据格式可以使用下面代码。if( FAILED( hr = g_pMouse-SetDataFormat( &g_dfMouse ) ) )retu

7、rn hr;这里g_dfMouse是我们预先定义的DIDATAFORMAT类型变量。变量定义如下:DIDATAFORMAT g_dfMouse = sizeof( DIDATAFORMAT ), sizeof( DIOBJECTDATAFORMAT ), DIDF_ABSAXIS, sizeof( MouseState ), numMouseObjects, g_aObjectFormats;上述的MouseState结构体是我们自定义的结构体,它用来存放输入设备的输入信息。MouseState的定义如下:struct MouseState LONG lAxisX; LONG lAxisY;

8、BYTE abButtons3; BYTE bPadding; ;上述的DIOBJECTDATAFORMAT结构体是定义设备中的输入信息与我们自己定义的输入信息结构体中相应变量相对应的映射表。其定义如下:DIOBJECTDATAFORMAT g_aObjectFormats = &GUID_XAxis, FIELD_OFFSET( MouseState, lAxisX ), / X axis DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 , &GUID_YAxis, FIELD_OFFSET( MouseState, lAxisY ), / Y axis DIDFT_AX

9、IS | DIDFT_ANYINSTANCE, 0 , 0, FIELD_OFFSET( MouseState, abButtons0 ), / Button 0 DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 , 0, FIELD_OFFSET( MouseState, abButtons1 ), / Button 1 (optional) DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 , 0, FIELD_OFFSET( MouseState, abButtons2 ), / Button 2 (optio

10、nal) DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 ;上述的numMouseObjects用来标识输入信息的个数,其定义如下:#define numMouseObjects (sizeof(g_aObjectFormats) /sizeof(DIOBJECTDATAFORMAT)通常设备会被其他程序占有,这时本程序是否能访问输入设备,需要通过设置协作级别来标识,设置协作级别可以使用函数IDirectInputDevice8:SetCooperativeLevel。 如下面语句。if( FAILED( hr = g_pMouse-S

11、etCooperativeLevel( hDlg, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND ) ) )return hr;参数定义: 第一个参数是用来指定将要接受输入的设备; 第二个参数是指定协作级别,这里的协作级别是表示其他设备可以获得输入设备,当前程序只有在位于前台的时候才可以访问输入数据。接下来就是读取输入信息的时候了。当我们需要获取信息的时候,首先需要调用IDirectInputDevice8 接口的Poll函数来使设备接口读取当前输入设备的信息。然后我们就可以使用下列语句读取输入设备信息了。if( FAILED( hr = g_pMouse-Get

12、DeviceState( sizeof( MouseState ), &ms ) ) )return hr;GetDeviceState是IDirectInputDevice8的函数,用来获取输入信息,其中第一个参数是设备状态信息结构体的大小,第二个参数是用来存放设备状态信息的结构体变量的地址。15.2 DirectX Audio入门15.2.1 声音播放概述在游戏中添加声音是必不可少的,通常声音文件的格式有很多,不同的声音文件格式需要用不同的方法来播放,在程序中播放声音有很多种方式,DirectX提供了一套与播放声音相关的接口,其中包括DirectSound、DirectMusic等,当前新

13、的DirectX版本中新增了XACT、XAudio2、X3DAudio、XAPO、XAPOFX。 这里我们主要讨论当前游戏中用得非常成熟并且比较容易学习的DirectSound编程。下面我们看看DirectSound到底能帮我们做些什么。 1 播放WAVE格式的音频文件或者资源。 2 可以同时播放多个音频。 3 给硬件缓冲送数据 4 播放3D立体声音 5 在声音中添加特技效果,比如回声,动态的改变特技的参数等 6 将麦克风或者其他音频输入设备的声音录制成wave格式的文件15.2.2 实现播放声音的过程要使用DirectSound首先需要包含相关的头文件。下面就是需要包含的头文件。#inclu

14、de #include #include #include 当然添加的dsound.lib库文件是必须的。下面我们简单的来学习一下如果通过Directsound的API播放声音第一步,创建一个设备对象。在你的代码中你可以通过调用DirectSoundCreat8函数来创建一个支持IDirectSound8接口的对象,这个对象通常代表缺省的播放设备。当然你可以枚举可用的设备,然后将设备的GUID传递给DirectSoundCreat8函数。 注意,Directsound虽然基于COM,但是你并不需要初始化com库,这些Directsound都帮你做好了,当然,如果你使用DMOs特技,你就要自己初

15、始化com库了,切记。 第二步,创建一个辅助Buffer,也叫后备缓冲区你可以通过IDirectS -ound8:CreateSoundBuffer来创建buffer对象,这个对象主要用来获取处理数据,这种buffer称作辅助缓冲区,以和主缓冲区区别开来,Direcsound通过把几个后备缓冲区的声音混合到主缓冲区中,然后输出到声音输出设备上,达到混音的效果。 第三步,获取PCM类型的数据 将WAV文件或者其他资源的数据读取到缓冲区中。 第四步,将数据读取到缓冲区 你可以通过 IDirectSoundBuffer8:Lock.方法来准备一个辅助缓冲区来进行写操作,通常这个方法返回一个内存地址,

16、见数据从你的私人buffer中复制到这个地址中,然后调用IDirectSoundBuffer8:Unlock。 第五步,播放缓冲区中的数据 你可以通过IDirectSoundBuffer8:Play方法来播放缓冲区中的音频数据,你可以通过IDirectSoundBuffer8:Stop来暂停播放数据,你可以反复的莱停止,播放,音频数据,如果你同时创建了几个buffer,那么你就可以同时来播放这些数据,这些声音会自动进行混音的。15.2.3 创建DirectSound在进行这部分之前,我们首先学习一下Directsound中常用的几个对象。见下表: 表15-1对象数量作用主要接口设备每个应用程序

17、只有一个设备对象用来管理设备,创建辅助缓冲区IDirectSound8辅助缓冲区每一个声音对应一个辅助缓冲区用来管理一个静态的或者动态的声音流,然后在主缓冲区中混音IDirectSoundBuffer8, IDirectSound3DBuffer8, IDirectSoundNotify8主缓冲区一个应用程序只有一个主缓冲区将辅助缓冲区的数据进行混音,并且控制3D参数.IDirectSoundBuffer, IDirectSound3DListener8特技可以没有,也可以有很多来辅助缓冲的声音数据进行处理IDirectSoundFXChorus8等接下来我们来介绍如何使用DirectSoun

18、d。首先,要创建一个设备对象,然后通过设备对象创建buffer对象。辅助缓冲区由应用程序创建和管理,DirectSound会自动地创建和管理主缓冲区,一般来说,应用程序即使没有获取这个对象的接口也可以播放音频数据,但是,如果应用程序要想得到IDirectSound3DListener8接口,就必须要自己创建一个主缓冲区。我们可以将短小的声音文件全部读取到辅助缓冲区中,然后通过一个简单的命令来播放。如果声音文件很长,就必须采用数据流了。(1)枚举系统声音输出设备当我们要创建声音设备的时候,首先我们需要查看系统的声音设备,这就是枚举系统输出声音设备,我们可以使用下面语句实现。/定义一个回调函数,用

19、来处理枚举到的信息BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext ) HWND hCombo = (HWND)lpContext; LPGUID lpTemp = NULL; if (lpGUID != NULL) / NULL only for Primary Sound Driver. if (lpTemp = (LPGUID)malloc(sizeof(GUID) = NULL) return(TRUE); memcpy(lpTemp, lpGU

20、ID, sizeof(GUID); ComboBox_AddString(hCombo, lpszDesc); ComboBox_SetItemData(hCombo,ComboBox_FindString(hCombo, 0, lpszDesc),lpTemp ); free(lpTemp); return(TRUE);/注册枚举函数和combox句柄if (FAILED(DirectSoundEnumerate(LPDSENUMCALLBACK)DSEnumProc, (VOID*)&hCombo) EndDialog(hDlg, TRUE); return(TRUE);枚举设备之后我再看

21、如何真正的创建设备对象(2)创建设备对象创建设备对象最简单的方法就是通过DirectSoundCreate8函数,这个函数的第一个参数指定了和这个对象邦定的设备的GUID,你可以通过枚举设备来获取这个设备的GUID,你可以传递一个下面的参数来指定一个缺省的设备 DSDEVID_DefaultPlayback 缺省的系统的声音输出设备,这个参数也可以为NULL SDEVID_DefaultVoicePlayback,缺省的声音输出设备,通常指第二缺省设备,例如USB耳机麦克风 如果没有声音输出设备,这个函数就返回error,或者,在VXD驱动程序下,如果声音输出设备正被某个应用程序通过wavef

22、orm格式的api函数所控制,该函数也返回error, 下面是创建对象的代码:LPDIRECTSOUND8 lpds; HRESULT hr = DirectSoundCreate8(NULL, &lpds, NULL); (3)设置协作级别因为Windows是一个多任务操作环境,在同一个时刻有可能多个应用程序共用同一个设备,通过协作水平,DirectX就可以保证这些应用程序在访问设备的时候不会冲突,每个Directsound应用程序都有一个协作度,用来确定来接近设备的程度,当你创建完设备对象后,一定要调用IDirectSound8:SetCooperativeLevel来设置协作度,否则,你

23、不会听到声音的,设置协作度的代码如下:HRESULT hr = lpDirectSound-SetCooperativeLevel(hwnd, DSSCL_PRIORITY);if (FAILED(hr) ErrorHandler(hr); / Add error-handling here. 上面的hwnd参数代表了应用程序的窗口。DirectSound定义了三种水平,DSSCL_NORMAL, DSSCL_PRIORITY, DSSCL_WRITEPRIMARY。在NORMAL水平的协作度下,应用程序不能设置主缓冲区的格式,也不能对主缓冲区进行写操作,所有在这个层次的应用程序使用的媒体格式

24、都是22kHZ,立体声,采样精度8位,所以,设备可以在各个应用程序中任意的切换。 在Priority层次的协作度下,应用程序可以有优先权使用硬件资源,比如使用硬件进行混音,当然也可以设置主缓冲区的媒体格式,游戏程序应该采用这个层次的协作度,这个层次的协作度在允许应用程序控制采用频率和位深度的同时,也给应用程序很大的权力,这个层次的协作度允许其他应用程序的声音和游戏的音频同时被听到,不影响。 最高层次的协作度就是Write_primary,当采用这个层次的协作度来使用一个dsound设备时,在非WDM模式驱动下,你的应用程序可以直接操作主缓冲区,在这个模式下,应用程序必须直接的操作主缓冲区。如果

25、你想直接把音频数据直接写入到主缓冲区,你就要将你的协作度模式设置为writeprimary,如果你的应用程序没有设置到这个层次,那么所有的对主缓冲区的IDirectSoundBuffer:Lock都会失败。当你的应用程序的协作度设置为wirte_primary水平时,并且你的应用程序位于前台,那么其他应用程序的辅助缓冲区就会停止,并且标示为lost(丢失设备),当你的应用程序转到后台,那么它的主缓冲区就会标示为lost(丢失设备),当它再次回到前台的时候会恢复到原来的状态,如果你的设备没有出现在你的系统中,那么你就没法设置wirte_primary协作度了,所以,在设置协作度之前,可以通过ID

26、irectSound8:GetCaps方法来查询一下设备是否可用。(4)设置声音设备 在windowos98或者2000系统中,用户可以通过控制面板来设置扬声器的属性,应用程序可以通过IDirectSound8:GetSpeakerConfig.函数来获取这些属性,我们不建议应用程序通过IDirectSound8:SetSpeakerConfig函授来设置扬声器的属性,因为这些设置的改动会影响到其他用户或者应用程序。(5)查询输出设备的性能 当你调用DirectSoundCreate8创建一个设备对象后,你的应用程序就可以通过IDirectSound8:GetCaps函数来获取设备的性能属性。

27、下面的代码的功能就是查询设备性能: DSCAPS dscaps;dscaps.dwSize = sizeof(DSCAPS);HRESULT hr = lpDirectSound-GetCaps(&dscaps);if (FAILED(hr) ErrorHandler(hr); / Add error-handling here. 通过 DSCAPS结构,该函数就给我返回硬件设备的一些性能,但是在调用这个函数之前一定要初始化这个结构的dwSize成员。如果你的应用程序能够操作硬件设备,比如你的协作度是Write_primory级别的,那么你在硬件设备上分配内存的时候,就要调用IDirectSo

28、udn8:GetCaps来查看一下硬件的资源是否满足你的要求。15.2.4 DirectSound声音缓冲区辅助缓冲区在存储和播放几个音频流的时候,你的应用程序要给每一个音频流都要创建一个辅助缓冲区(buffer)对象。辅助缓冲区可以和应用程的生命期一样的长,也可以在不需要的时候销毁。辅助缓冲区可以是一个包含了整个声音数据的静态缓冲区,也是可以只包含声音数据的一部份,然后再播放时不断更新数据的流缓冲区。为了限制内存开销,在播放比较长的声音文件时要采用流缓冲区,这些缓冲区只包含几秒钟的数据量。我们可以通过同时播放几个辅助缓冲区中的声音来对他们进行混音,至于同时可以播放几个辅助缓冲区则有硬件设备的

29、性能决定。辅助缓冲区的格式并不完全一样,一般用来描述缓冲格式的参数如下Format,缓冲区的format必须要所播放音频的waveformat一致。 Controls,不同的缓冲区的控制参数的值可以不一样,比如音量,频率,以及在不同方向的移动,当创建buffer时,你就要指定你需要的控制参数的值,例如,不要为一个不支持3D的音频创建一个3D缓冲区 Location,你创建的缓冲区可以在硬件管理的内存中,也可以在软件管理的内存中,当然,硬件缓冲区比软件缓冲区速度要快。你可以调用IDirectSound8:CreateSoundBuffer函数来创建一个缓冲区(buffer)对象。这个函数返回一个

30、指向IDrectSoundBuffer接口的指针,通过这个接口,应用程序可以获取 IDirectSoundBuffer8 interface。下面的一段代码演示了如何创建一个辅助缓冲区,并且返回一个IDirectSoundBuffer8接口。HRESULT CreateBasicBuffer(LPDIRECTSOUND8 lpDirectSound, LPDIRECTSOUNDBUFFER8* ppDsb8) WAVEFORMATEX wfx; DSBUFFERDESC dsbdesc; LPDIRECTSOUNDBUFFER pDsb = NULL; HRESULT hr; / Set up

31、 WAV format structure. memset(&wfx, 0, sizeof(WAVEFORMATEX); wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.nChannels = 2; wfx.nSamplesPerSec = 22050; wfx.nBlockAlign = 4; wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; wfx.wBitsPerSample = 16; / Set up DSBUFFERDESC structure. memset(&dsbdesc, 0, sizeof(

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1