6游戏声音.docx

上传人:b****6 文档编号:7331656 上传时间:2023-01-23 格式:DOCX 页数:26 大小:202.82KB
下载 相关 举报
6游戏声音.docx_第1页
第1页 / 共26页
6游戏声音.docx_第2页
第2页 / 共26页
6游戏声音.docx_第3页
第3页 / 共26页
6游戏声音.docx_第4页
第4页 / 共26页
6游戏声音.docx_第5页
第5页 / 共26页
点击查看更多>>
下载资源
资源描述

6游戏声音.docx

《6游戏声音.docx》由会员分享,可在线阅读,更多相关《6游戏声音.docx(26页珍藏版)》请在冰豆网上搜索。

6游戏声音.docx

6游戏声音

游戏音乐与音效的播放

在Win32环境下,播放音乐音效的方法太多了,而且有一个共同点就是:

你不需要花很大的心力就可以得到你需要的东西。

游戏的配乐

  我相信很多人一定同意音乐在游戏里面所占的地位,回想一下国内RPG的经典「仙剑奇侠传」,剥掉音乐这一个层面,整个游戏将会逊色不少,尤其适当的场景搭配适当的音乐,更能让玩家融入剧情当中。

该哭的时候哭,该笑的时候笑,大概就很切中要领了。

RPG剩下的音效部份,并不特别突出,大抵上知道砍人的时候有挥剑的声音就可以了,所以在音效的表现方面,通常比较不那么注重。

而即时战斗的游戏着重在厮杀的音效表现上,一大片人马,一片混杂的声音,这其中牵涉到混音的部份,这一章,你将学习到什么时候该用什么样的代码来表现游戏的另一个生命:

音乐与音效。

一、理解数字声音

虽然不必理解数字声音的工作方式就可以在游戏中播放声音,但是我们应该对数字声音以及它与我们在真实世界里听到的物理声音之间的关系有基本的了解。

物理声音是通过空气传播的波,与海浪类似。

声波实际上是空气膨胀和压缩所产生的压力的结果。

换句话说,声波涉及空气中的一系列移动的压力变化。

我们能够听到声音是因为移动的声波最终到达我们的耳朵,耳膜处理并解释这种压力的变化。

声音的柔和或音量是由波中的能量决定的,因为声波在移动时会损失能量,所以距离越近,听到的声音越大,距离越远,声音就越柔和。

当麦克风将声波转换为电信号时,得到的信号是一个模拟信号。

而计算机是数字机器,因此必须将模拟信号转换为数字信号。

模拟/数字(A/D)转换器完成了将模拟信号转换为数字信号的任务,这种转换称为采样。

采样的频率(HZ)以及在每个样本中存储的信息量决定了数字波形与模拟波形的接近程度。

二、播放WAV声音

Windows中的数字声音称为波形声音,这是指数字声音源自于物理的声波。

在Windows中,波形声音就像位图、图标以及光标等windows资源一样,这意味着可以指定波形声音作为游戏的资源脚本中的资源,并将它们直接编译到可执行程序文件中。

Win32API提供了对播放波形声音的高级支持,所谓高级支持是指可以使用Win32API播放声音而不必关心波形声音格式的细节或者处理内存中的原始声音数据。

Win32API中的高级波形声音支持的一个缺点是,它不允许波形混合(波形混合是指混合波形声音,从而同时播放多个声音)。

这意味着在任何特定时刻都只能播放一个波形声音。

因为有时候可能需要同时播放两个或者更多的声音,所以必须确定这一点对自己的游戏的影响。

在需要解决一次只能播放一个声音的问题时,可以选择以下方法:

(1)中断当前正在播放的声音,以便播放下一个声音。

(2)允许每一个声音播放结束,并拒绝那些试图中断当前所播放声音的声音。

至于在你的游戏中到底使用哪种方式,完全取决于游戏类型。

补充:

可以使用DirectXAPI来混合波形声音。

BOOLPlaySound(LPCSTRpszSound,HMODULEhmod,DWORDfdwSound);

(1)播放文件中的波形声音

此时PlaySound()的第一个参数szSound标识了波形文件的名称,第2个参数hMod只适用于播放波形资源,因此在播放波形文件时可以对第2个参数传递NULL。

第3个参数dwSound用来确定播放波形声音的具体方式。

SND_FILENAME——是播放一个文件中的波形声音。

举例:

PlaySound(“Explosion.wav”,NULL,SND_ASYNC|SND_FILENAME)

SND_RESOURCE——波形声音是一个资源。

举例:

PlaySound((LPCSTR)IDW_EXPLOSION,g_hInstance,SND_ASYNC|SND_RESOURCE)

SND_SYNC——同步波形。

即playSound()不允许程序在完成播放之前继续操作,这在游戏中几乎不可能。

SND_ASYNC——异步波形。

允许继续操作。

SND_NOSTOP——它使一个声音更“尊重”正在播放的另一个声音。

更具体地说,如果在播放一个波形声音时指定了SND_NOSTOP标志,那么这个声音不会中断另一个已经在播放的声音。

如果要让该声音能够中断当前正在播放的声音,则不要指定SND_NOSTOP标志。

SND_LOOP——循环播放波形声音。

PlaySound((LPCSTR)IDW_EXPLOSION,g_hInstance,SND_ASYNC|SND_RESOURCE|SND_LOOP)

循环的声音会继续无休止地循环播放,直到播放另一个波形声音以停止它,或者使用对PlaySound()的另一个调用来停止循环播放的波形声音。

SND_PURGE——停止播放波形声音。

1、停止正在播放的某个波形声音

PlaySound((LPCSTR)IDW_EXPLOSION,g_hInstance,SND_PURGE|SND_RESOURCE)

2、停止播放任何声音

举例:

PlaySound(NULL,NULL,SND_PURGE)

在游戏中提供一个禁用声音的选项总是一种很好的做法。

做法很简单,如响应键盘上的S键打开或关闭声音。

举例:

Brainiac2

为以下游戏事件添加声效支持

(1)选择一个方块

(2)将两个方块配对

(3)两个方块配对错误

(4)将所有方块配对,赢得游戏胜利

voidMouseButtonDown(intx,inty,BOOLbLeft){

//确定单击了哪个方块

intiTileX=x/g_tileImgs[0]->GetWidth();

intiTileY=y/g_tileImgs[0]->GetHeight();

//确保不是点击了已经配对成功的方块

if(g_bTileStates[iTileX][iTileY]==false){

//判断是否是第一个选中方块

if(g_tile1.x==-1){

//播放第一个方块选择声音

//PlaySound((LPCTSTR)IDW_SELECT,hinstance_app,SND_ASYNC|SND_RESOURCE);

PlaySound("Res/Select.wav",NULL,SND_ASYNC|SND_FILENAME);

g_tile1.x=iTileX;g_tile1.y=iTileY;

}

else//判断是否表示第二个选中的方块{

if((iTileX!

=g_tile1.x)||(iTileY!

=g_tile1.y))//没有重复点击第一个选中方块{

if(g_tile2.x==-1){

//播放第2个方块选择声音

//PlaySound((LPCTSTR)IDW_SELECT,hinstance_app,SND_ASYNC|SND_RESOURCE);

PlaySound("Res/Select.wav",NULL,SND_ASYNC|SND_FILENAME);

g_iTries++;g_tile2.x=iTileX;g_tile2.y=iTileY;

//匹配判断

if(g_iTiles[g_tile1.x][g_tile1.y]==g_iTiles[g_tile2.x][g_tile2.y]){

//播放方块配对声音

//PlaySound((LPCTSTR)IDW_MATCH,hinstance_app,SND_ASYNC|SND_RESOURCE);

PlaySound("Res/Match.wav",NULL,SND_ASYNC|SND_FILENAME);

g_bTileStates[g_tile1.x][g_tile1.y]=true;g_bTileStates[g_tile2.x][g_tile2.y]=true;

//清空方块选择

g_tile1.x=g_tile1.y=g_tile2.x=g_tile2.y=-1;

//更新配对计数,并检查是否获胜

g_iMatches++;

if(g_iMatches==8){

//播放方块配对声音

//PlaySound((LPCTSTR)IDW_WIN,hinstance_app,SND_ASYNC|SND_RESOURCE);

PlaySound("Res/Win.wav",NULL,SND_ASYNC|SND_FILENAME);

TCHARszText[64];

wsprintf(szText,"Youwonin%dtries.",g_iTries);

MessageBox(main_window_handle,szText,TEXT("Brainiac"),MB_OK);

}

}

}

else{

//播放方块配对声音

//PlaySound((LPCTSTR)IDW_MISMATCH,hinstance_app,SND_ASYNC|SND_RESOURCE;

PlaySound("Res/Mismatch.wav",NULL,SND_ASYNC|SND_FILENAME);

g_tile1.x=g_tile1.y=g_tile2.x=g_tile2.y=-1;

}

}

}

InvalidateRect(main_window_handle,NULL,false);

}

}

三、播放MIDI音乐

MIDI(MusicalInstrumentDigitalInterface)乐器数字接口,出现于20世纪80年代初期,用来建立乐器之间的标准接口。

当时,MIDI的主要用途是允许一种专用的键盘控制一个电子合成器。

理解MIDI设备的一种方式,是在输入方面将它看作一个音符发生器,在输出方面将它看作一个声音发生器。

只要MIDI设备与一个发生或者输出音符的MIDI接口相连,它的内部工作方式并不重要。

由此,可能有人会把MIDI声音的设计对比Windows的设备无关设计:

Windows使得混合和匹配不同类型的硬件并使之协同工作成为可能。

MIDI使得连接不同类型的音乐设备并使之协同工作成为可能。

事实上,目前的声卡都包含一个与MIDI兼容的接口,MIDI设备可以通过它与计算机通信。

MIDI音乐也是存储在文件中,并具有.MID文件后缀名,与WAV波形声音不同,midi占用内存空间很小。

在WINDOW下,考量到空间的大小,MIDI格式的音乐档绝对是最佳的选择,一首五分钟的MIDI了不起十万字元的大小,这跟WAV格式一分钟占用量以MB计,简直是小巫见大巫,所以网站上的音乐,游戏的音乐,都很适合用MIDI来表现,而音乐部份我个人注重旋律,至於一首音乐本身使用到的乐器数量,我倒是很少去注意,人的耳朵听东西有一定的极限,只要不产生杂音,配合优美的旋律,大致上都可以接受。

1、理解Windows媒体控制接口

Win32API组合了MIDI音乐以及其他类型的多媒体对象,例如视频剪辑。

要想在Windows程序中播放MIDI歌曲,必须使用一个专门的多媒体API,它名为媒体控制接口(MediaControlInterface,MCI)。

MCI是一个高级API,允许开发人员控制多媒体设备,例如MIDI合成器或者视频播放器。

MCI背后的思路是,通过向多媒体设备发送命令来与之通信。

这里的命令就是执行一个特定操作的指令,例如播放、暂停、停止一首歌曲或者一个视频剪辑。

MCI实际支持两种命令:

命令消息——通过向多媒体设备发送一个消息来告诉它要做什么。

例如,如果想要播放一首歌曲,就发送一个命令消息,在其中包括歌曲文件的名称以及播放命令。

命令字符串——

MCIERRORmciSendString(

LPCTSTRlpszCommand,//MCI命令字符串

LPTSTRlpszReturnString,//存放反馈信息的缓冲区

UINTcchReturn,//缓冲区的长度

HANDLEhwndCallback//回调窗口的句柄,一般为NULL

);

函数若成功则返回0,否则返回错误码,错误码可以用如下函数分析:

BOOLmciGetErrorString(

DWORDfdwError,//错误码

LPTSTRlpszErrorText,//接收描述错误的字符串的缓冲区

UINTcchErrorText//缓冲区长度

);

举例:

charbuf[50];

MCIERRORmciError;

mciError=mciSendString("openwaveaudio",buf,strlen(buf),NULL);

if(mciError)

{

mciGetErrorString(mciError,buf,strlen(buf));

AfxMessageBox(buf);

return;

}

表1MCI设备类型

设备类型

描述

animation

动画设备

cdaudio

CD播放器

dat

数字音频磁带机

digitalvideo

某一窗口中的数字视频

other

未定义的MCI设备

overlay

重叠设备(窗口中的模拟视频)

scanner

图像扫描仪

sequencer

MIDI序列器

videodisc

视频

waveaudio

播放数字波形文件的音频设备

 

表2常用的MCI命令

命令

描述

capacility

查询设备能力

close

关闭设备

info

查询设备的信息

open

打开设备

pause

暂停设备的播放或记录

play

开始设备播放

record

开始

resume

恢复暂停播放或记录的设备

seek

改变媒体的当前位置

set

改变设置

status

查询设备状态信息

stop

停止设备的播放或记录

MCI设备可分为简单设备和复合设备两类。

cdaudio这样的不使用文件的设备为简单设备,而复合设备在播放时要用到数据文件。

例如打开一个波形音频设备:

openmysound.wavtypewaveaudio

2、使用MCI播放MIDI音乐

在游戏中播放MIDI音乐的设备是MIDI合成器,它的工作是获得音乐的音符并大声播放出来。

目前几乎每一块声卡都内置了一个MIDI合成器,因此播放MIDI音乐应该没有任何问题。

使用MCI播放MIDI音乐的很大一部分工作是建立与MIDI合成设备的联系。

(1)打开MIDI设备

(2)播放MIDI歌曲

(3)暂停MIDI歌曲

(4)关闭MIDI设备

在使用MCI处理MIDI设备时,要理解,设备是使用一个唯一的设备标识符引用的。

因此,在打开一个MIDI设备以播放MIDI音乐时,需要跟踪最初打开设备时返回的设备ID。

可以将设备ID看作呼叫设备并告诉它希望做什么所需的电话号码。

MCIERRORmciSendCommand(MCIDEVICEIDIDDevice,UINTuMsg,DWORDfdwCommand,DWORDdwParam);

(1)打开消息为MCI_OPEN,它需要一个MCI_OPEN_PARAMS的特殊数据结构,其定义如下:

typedefstruct{

DWORDdwCallback;

MCIDEVICEIDwDeviceID;//存储了设备ID(在打开设备时,将使用设备ID填写wDeviceID成员)

LPCSTRlpstrDeviceType;//打开时指定,“sequencer”,表示MIDI编曲器

LPCSTRlpstrElementName;//打开时指定,“midi文件名”(这里揭示了MCI的一个有趣之处,在打开一个设备时就必须指定一个多媒体对象。

LPCSTRlpstrAlias;

}MCI_OPEN_PARMS;

举例:

UNITuiMIDIPlayerID;

MCI_OPEN_PARAMSmciOpenParms;

mciOpenParms.lpstrDeviceType=“sequencer”;

mciOpenParms.lpstrElementName=“Music.mid”;

If(mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_TYPE|MCI_OPEN_ELEMENT,(LPDWORD)&mciOpenParms)==0)

uiMIDPlayerID=mciOpenParms.wDeviceID;

(2)播放MIDI歌曲的命令是MCI_PLAY,且需要涉及另一个数据结构MCI_PLAY_PARMS,但是从头到尾地播放一首歌曲时,可以不必初始化这个数据结构。

举例:

MCI_PLAY_PARMSmciPlayParms;

mciSendCommand(uiMIDIPlayerID,MCI_PLAY,0,(LPDWORD)&mciPlayParms);

(3)暂停MIDI歌曲使用MCI_PAUSE命令

举例:

mciSendCommand(uiMIDIPlayerID,MCI_PAUSE,0,NULL);

(4)关闭MIDI设备使用MCI_CLOSE命令

举例:

mciSendCommand(uiMIDIPlayerID,MCI_CLOSE,0,NULL);

注意:

对于播放和关闭设备,我没有阐明一点,在尝试播放一首MIDI歌曲时可能会遇到问题,这种情况下,在发出MCI_PLAY命令时,mciSendCommand()函数将返回一个值而不是0,此时应该关闭设备,所以检查返回值并查看是否成功播放了歌曲是一种很好的做法。

举例:

MCI_PLAY_PARMSmciPlayParms;

If(mciSendCommand(uiMIDIPlayerID,MCI_PLAY,0,(LPDWORD)&mciPlayParms)!

=0)

{

mciSendCommand(uiMIDIPlayerID,MCI_CLOSE,0,NULL);

uiMIDIPlayerID=0;//同时清空了设备ID,防止再向该设备发送其他任何命令。

}

3、向游戏引擎添加MIDI音乐支持

首先,需要记录MIDI编曲设备ID,并在WinMain()中初始化为0。

UINTm_uiMIDIPlayerID;//记录MIDI设备ID。

当m_uiMIDIPlayerID不为0,表示打开了设备,准备好播放音乐。

如果为0,则关闭了设备。

其次,添加MIDI相关方法。

/*

播放MIDI歌曲

szMIDIFileName=""时表示已经开始播放了一首歌曲,并且现在暂停了播放,需要继续播放歌曲bRestart表示如何播放歌曲,如果继续播放,则为false;如果从头开始播放,则为true

*/

voidPlayMIDISong(LPTSTRszMIDIFileName,BOOLbRestart){

//SeeiftheMIDIplayerneedstobeopened

if(m_uiMIDIPlayerID==0){

//OpentheMIDIplayerbyspecifyingthedeviceandfilename

MCI_OPEN_PARMSmciOpenParms;

mciOpenParms.lpstrDeviceType="sequencer";

mciOpenParms.lpstrElementName=szMIDIFileName;

if(mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_TYPE|MCI_OPEN_ELEMENT,

(DWORD)&mciOpenParms)==0)

//GettheIDfortheMIDIplayer

m_uiMIDIPlayerID=mciOpenParms.wDeviceID;

else

//Therewasaproblem,sojustreturn

return;

}

//RestarttheMIDIsong,ifnecessary

if(bRestart){

MCI_SEEK_PARMSmciSeekParms;

if(mciSendCommand(m_uiMIDIPlayerID,MCI_SEEK,MCI_SEEK_TO_START,

(DWORD)&mciSeekParms)!

=0)

//Therewasaproblem,soclosetheMIDIplayer

CloseMIDIPlayer();

}

//PlaytheMIDIsong

MCI_PLAY_PARMSmciPlayParms;

if(mciSendCommand(m_uiMIDIPlayerID,MCI_PLAY,0,(DWORD)&mciPlayParms)!

=0)

//Therewasaproblem,soclosetheMIDIplayer

CloseMIDIPlayer();

}

voidPauseMIDISong(){

//Pausethecurrentlyplayingsong,ifpossible

if(m_uiMIDIPlayerID!

=0)

mciSendCommand(m_uiMIDIPlayerID,MCI_PAUSE,0,NULL);

}

voidCloseMIDIPlayer(){

//ClosetheMIDIplayer,ifpossible

if(m_uiMIDIPlayerID!

=0){

mciSendCommand(m_uiMIDIPlayerID,MCI_CLOSE,0,NULL);

m_uiMIDIPlayerID=0;

}

}

举例:

Henway2

第一步:

voidGameStart(HDChDC)

{PlayMIDISong(TEXT("Res/Music.mid"));//打开MIDI设备}

voidGameEnd()

{CloseMIDIPlayer();//关闭MIDI设备}

第二步:

窗口停用时暂停MIDI歌曲,窗口重新激活时再次播放。

voidGameActivate(HWNDhWindow)

{PlayMIDISong(TEXT(""),FALSE);//激活窗口时,继

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 语文

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

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