📄 chapter8.txt
字号:
return TRUE;
}
if (lpDS != NULL)
{
Msg( "DSEnable, already enabled" );
return TRUE;
}
检测选择是否成功和声音是否已被初始化。然后是
dsrval = DirectSoundCreate(NULL, &lpDS, NULL);
if (dsrval != DS_OK)
{
Msg("DirectSoundCreate FAILED");
return FALSE;
}
dsrval = IDirectSound_SetCooperativeLevel(lpDS, hwnd, DSSCL_NORMAL);
if (dsrval != DS_OK)
{
DSDisable();
Msg("SetCooperativeLevel FAILED");
return FALSE;
}
用于创建DirectSound的对象并检测创建是否成功和设置合作层并检测设置是否成功。在这里为默认设备创建了一个对象,将合作层设置为普通(DSSCL_NORMAL)即使用声卡的应用程序可以顺序地进行切换。
调用DSEnable()之后用语句:
for( idx = 0; idx < NUM_SOUND_EFFECTS; idx++ )
{
if (SoundLoadEffect((EFFECT)idx))
{
DSBCAPS caps;
caps.dwSize = sizeof(caps);
IDirectSoundBuffer_GetCaps(lpSoundEffects[idx], &caps);
if (caps.dwFlags & DSBCAPS_LOCHARDWARE)
Msg( "Sound effect %s in hardware", szSoundEffects[idx]);
else
Msg( "Sound effect %s in software", szSoundEffects[idx]);
}
else
{
Msg( "cant load sound effect %s", szSoundEffects[idx]);
}
}
将音效调入(利用函数SoundLoadEffect((EFFECT)idx))和检测设备的特性并将之存放在结构caps中的成员dwsize里(利用函数IDirectSoundBuffer_GetCaps(lpSoundEffects[idx], &caps)。
最后是一部分是播放,这部分主要是设定dsBD.dwFlags为DSBCAPS_PRIMARYBUFFER确定可对主缓冲区进行操作,使用语句if (SUCCEEDED(IDirectSound_CreateSoundBuffer(lpDS, &dsBD, &lpPrimary, NULL)))来创建副缓冲区并检测成功与否,使用语句 if (!SUCCEEDED(IDirectSoundBuffer_Play(lpPrimary, 0, 0, DSBPLAY_LOOPING)))播放并检测成功与否。
第八节DirectDraw的设置
这个部分完成了对DirectDraw的设置工作和游戏开始时初始化画面的显示。它的运行过程如下:
if( !PreInitializeGame() )
{
return FALSE;
}
在PreInitializeGame()函数中只有语句return InitBuffer( &hBuffer)。该语句调用了InitBuffer( &hBuffer)函数又只调用了gfxBegin()函数,并在调用失败后结束程序。函数gfxBegin()完成了对显示模式的设置工作(通过对DDEnable( void )函数的调用)、创建表面的工作(通过调用函数DDCreateFlippingSurface( void )、初始化画面的显示(通过调用函数Splash())。
函数DDEnable( void )的运行过程如下:
1.获取系统信息(运用GetProfileInt()函数)和决定是否使用软件模拟(应用DirectDrawCreate() 为该驱动方式建立一个对象再用DirectDraw_QueryInterface()查询该对象是否被支持)。
2.检测显示模式。首先判断是否使用全屏模式,若是则使用IDirectDraw_SetCooperativeLevel(( lpdd, hWndMain,DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE |DDSCL_FULLSCREEN )创建一个对显示设备能够进行最大化控制的合作层,然后用IDirectDraw_EnumDisplayModes(lpdd, DDEDM_STANDARDVGAMODES, NULL, 0, EnumDisplayModesCallback)枚举VGA模式下的显示模式。如果枚举失败,则调用IDirectDraw_EnumDisplayModes(lpdd, 0, NULL, 0, EnumDisplayModesCallback)(枚举所有的显示模式)。若不使用全屏模式,则调用 ddrval = IDirectDraw_SetCooperativeLevel( lpdd, hWndMain,DDSCL_NORMAL )(创建一个DDSCL_NORMAL 模式下的合作层即使用一般Windows应用程序的方式)。随后将设定的显示模式放入结构数组ModeList[]中。若合作层创建失败则返回错误信息并结束游戏。
接下来是选择显示模式部分。首先判断是否使用全屏模式,若是则判断使用哪种显示大小和颜色数。若没选用全屏模式则获取系统当前的设备及所采用的颜色数,设定窗口模式下的窗口的属性及判断是否使用拉伸算法并根据判断结果设定用户区的大小(利用SetRect(&rc, 0, 0, GameMode.cx*2, GameMode.cy*2)及SetRect(&rc, 0, 0, GameMode.cx, GameMode.cy)),然后根据用户区的大小和窗口风格的窗口属性设定窗口的大小,并由SetWindowPos()确定窗口在多窗口的情况下的位置。
利用IDirectDraw_GetCaps( lpdd, &ddcaps, NULL )函数获取设备所支持的特性,并确定那些特征由软件模拟,那些特征由硬件支持。由nBufferCount的值确定缓冲区的数量。最后由设备所支持的特性确定最大显示模式。
函数DDCreateFlippingSurface( void )的运行过程:
首先取得硬件支持的特性(应用IDirectDraw_GetCaps( lpDD, &ddcaps, NULL ) )。再将缓冲区中全部填上0。在全屏模式下和缓冲区数大于1时,创建一个以DD_CAPS为标志的表面功能区及一个以DDSD_BACKBUFFERCOUNT为标志的后备缓冲记数区,并给表面功能区分配DDSCAPS_PRIMARYSURFACE、DDSCAPS_FLIP和DDSCAPS_COMPLEX三个标志(关于这三个标志,请详细阅读DirectDraw深入篇)。接下来用 ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
ddrval = IDirectDrawSurface_GetAttachedSurface(
lpFrontBuffer,
&ddscaps,
&lpBackBuffer );
取得后备缓冲区的指针。如果使用了拉伸算法或ddcaps.dwCaps的标志为DDCAPS_BANKSWITCHED时则创建再一个用于拉伸算法的缓冲区(在您详细阅读函数DDCreateSurface(DWORD width,DWORD height,BOOL sysmem,BOOL trans )后会发现该缓冲区的创建方法与上面谈到的缓冲区的创建是差不多的,只不过少了后备缓冲记数区而多了两个关于高度和宽度的缓冲区,并使用了系统内存,请注意这个技巧)。下面是在全屏模式和有一个缓冲区的情况下,如何进行创建表面的工作。在这一步中可以看到程序只创建了一个表面功能区而无后备缓冲记数区,同时取得后备缓冲区的指针的部分被
IDirectDrawSurface_AddRef(lpFrontBuffer);
lpBackBuffer = lpFrontBuffer;
替代。然后是在窗口模式下的缓冲区的设置,首先创建一个表面功能区(在VRAM中)
然后用lpBackBuffer = DDCreateSurface( GameSize.cx, GameSize.cy, FALSE, FALSE )创建一个后备缓冲区(在系统内存中)。接下来是对剪切板的设置,先创建一个剪切板(ddrval = IDirectDraw_CreateClipper(lpDD, 0, &lpClipper, NULL)),再取得剪切板的指针( ddrval = IDirectDrawClipper_SetHWnd(lpClipper, 0, hWndMain)),最后将剪切板连接到表面上( ddrval = IDirectDrawSurface_SetClipper(lpFrontBuffer, lpClipper))。下面是对颜色的操作,首先使用IDirectDrawSurface_GetPixelFormat(lpFrontBuffer, &ddpf)取得表面的像素格式,然后设置ColorKey,若是8位色则ColorKey为256反之则取16位色。
第九节用户区尺寸及调色板设置
1.用户区尺寸设置
在这部分中首先是对全屏模式或使用拉伸算法的情况下的用户区的大小设置,然后是在窗口模式下的设置。在这些设置工作中可能需要解释的是 GameRect.left为什么等于GameMode.cx - GameSize.cx,这是由于GameRect.left(或GameRect.right)是指用户区的左上角(右下角)的横坐标长度,而GameMode.cx是指整个用户区的宽度(全屏)而且GameSize.cx= GameMode.cx / 2 。所以GameRect.left=GameMode.cx - GameSize.cx。其他的比如GameRect.top、GameRect.right和GameRect.bottom的计算式的含义都和GameRect.left的计算方法差不多。
2调色板设置
这一部分程序的功能主要是由函数ReadPalFile()完成的,这个函数的功能是引入一个调色板文件,如果找不到指定的文件则使用默认的调色板,而这个默认的调色板的建立是使用了下面的语句:
for( i=0; i<256; i++ )
{
pal.ape[i].peRed = (BYTE)(((i >> 5) & 0x07) * 255 / 7);
pal.ape[i].peGreen = (BYTE)(((i >> 2) & 0x07) * 255 / 7);
pal.ape[i].peBlue = (BYTE)(((i >> 0) & 0x03) * 255 / 3);
pal.ape[i].peFlags = (BYTE)0;
}/*在结构数组pal.ape[i]中存放256组由四个数值组成的颜色值*/
和函数 ddrval = IDirectDraw_CreatePalette(lpDD,DDPCAPS_8BIT,pal.ape,&ppal,NULL )。从这些语句中我们可以看到建立了一个256色的调色板(8位色)。
在调用调色板之后用IDirectDrawSurface_SetPalette()将调色板连接到表面上。
第十节调入图象
这个部分是通过调用InitializeGame()函数实现的。InitializeGame()函数的运行过程为:首先调用 Splash()函数,该函数的作用是将后备缓冲区全部写为蓝色并测试全部缓冲区(用DDClear()函数)和向屏幕输出FoxBear is loading...... Device。然后用LoadBitmaps( void )函数从foxbear.art文件中将所有的位图读出并存入结构数组hBitmapList[]中。接着是:
InitTiles( &hTileList, hBitmapList, C_TILETOTAL );
InitPlane( &hForeground, &hForePosList, "FORELIST", C_FORE_W, C_FORE_H, C_FORE_DENOM );
TilePlane( hForeground, hTileList, hForePosList );
InitPlane( &hMidground, &hMidPosList, "MIDLIST", C_MID_W, C_MID_H, C_MID_DENOM );
TilePlane( hMidground, hTileList, hMidPosList );
InitPlane( &hBackground, &hBackPosList, "BACKLIST", C_BACK_W, C_BACK_H, C_BACK_DENOM );
TilePlane( hBackground, hTileList, hBackPosList );
InitSurface( &hSurfaceList, "SURFLIST", C_FORE_W, C_FORE_H );
SurfacePlane( hForeground, hSurfaceList );
InitFox( &hFox, hBitmapList );
InitBear( &hBear, hBitmapList );
InitApple( &hApple, hBitmapList );
这些语句将 hBitmapList[]中的位图分类存入相应的列表中并建立各自的内存区。如:InitPlane( &hForeground, &hForePosList, "FORELIST", C_FORE_W, C_FORE _H, C_FORE_DENOM )在主缓冲区建立了一个存放前景的区域和一个存放前景的位图的区域(第一帧)。
TilePlane( hForeground, hTileList, hForePosList )在主缓冲区建立一个存放前景中其他位图的区域。
最后用DDClear()将所有后备缓冲区清空。
第十一节输出设备信息
在游戏的过程中会显示出当前的FPS值及显示模式和“ALT+ENTER=WINDOWS”的信息。这部分的功能就是输出这些信息。
这一功能的是通过函数makeFontStuff()的调用而实现的。makeFontStuff()的实现过程为:删除已有的字体句柄,创建一个新的字体,调用initNumSurface( )为FPS及FPS的值和显示模式及字符串“ALT+ENTER=WINDOWS”设定输出字体的大小、颜色、在用户区的位置等等属性。然后各为FPS 和显示模式等的信息创建一个内存区域以存放它们。然后用
if( bTransDest )
BackColor = RGB(255,255,255);
else
BackColor = RGB(128,64,255);
ddck.dwColorSpaceLowValue = DDColorMatch(lpInfo, BackColor);
ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue;
IDirectDrawSurface_SetColorKey( lpInfo, DDCKEY_SRCBLT, &ddck);
IDirectDrawSurface_SetColorKey( lpFrameRate, DDCKEY_SRCBLT, &ddck);
来设定FPS信息和显示模式信息显示的色彩键码。
最后,再次调用initNumSurface( )显示这些信息。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -