游戏开发基础:游戏开发基础(7)



第 7章 游戏编程特点
节 概述:


电脑游戏在计算机发展使用中可以说扮演了个极为有趣角色方面不为很多人所赞同认为是种浪费;而另方面电脑游戏却是推动计算机各项技术迅速发展最有力力量的

可以从3d类游戏对硬件无止境需求游戏迷对游戏图像质量、游戏交互性、人机界面友好性等方面需求体现出来(当然游戏迷对游戏构思、创意要求也是苛刻且无止境但这点只有靠您自己想象力我们是爱莫能助了)

从游戏近期发展中我们从3d游戏发展可以看到从Doom到现在古墓丽影2、雷神的锤23d游戏画面从生硬单调多边形到今天柔和复杂几进乱真场景、道具、怪物敌人从只会疯狂向你冲来到今天会偷袭、会审时度势地采取合适方式思路方法向你进攻;游戏无论从硬件支持还是编程技术方面都有突飞猛进进展在游戏发展过程中很多技术也随的发展起来了例如各种图形加速卡出现和发展directx出现和各个成功游戏中采用各种优化技术都推动了计算机技术发展

游戏可以说是集合了每个时期计算机行业中最先进硬件技术和最新编程思想比如近期游戏都是采用了面向对象编程思想基于Windows软件Software大部分图象要求高游戏都要求或支持图形加速卡同时游戏编程中也有自己基本方式思路方法、结构和理论在这学习中我们将讨论这些问题
在这章中我们将讨论下面几个问题:

入口 即是游戏获取外部操作讯息得到下次刷新所需新参数手段如同SDK Windows应用入口为WINMAIN()

游戏化 包括创建标准WINDOWS所需以及游戏内部例如游戏系统化、游戏图形装入、游戏声音装入等

游戏内部循环: 游戏循环入口是WINDOWS消息循环内部游戏内部循环包括刷新游戏单位、画游戏单位两部分

刷新游戏单位: 用于每帧刷新游戏单位状态例如改变游戏单位状态、改变游戏单位位置、获取外部信息等

画游戏单位: 用于每帧往屏幕上画游戏单位图象并进行特殊处理以提高速度

计算机人工智能: 主要用于受计算机处理游戏单位行为控制算法部分位于刷新计算机游戏单位部分中

游戏内存管理: 这部分对于优质高效游戏软件Software是十分重要内存管理不当会导致游戏性能降低甚至引起死机

游戏交互设计: 交互设计是游戏可玩性关键友好交互界面和交互方式可以使游戏增色不少

游戏图象底层设计: 游戏软件Software主要处理时间花在处理图象和画图象上所以游戏图象底层设计对于游戏最终效果是十分重要

游戏多媒体设计: 主要包括图形界面设计、游戏音乐音效设计、游戏动画设计、游戏影象设计几个方面更广泛说还包括游戏所有运行过程功能设计


第 2节 入口

这个标题看起来似乎很难理解意思就是当游戏被启动时计算机从什么地方开始运行在Windows应用Win()般就是入口游戏开始后,就Win()然后再按语句顺序或所接受到消息相应

从第 3章Windows编程基础中我们了解到Win()结构、运行过程现在我们就游戏编程角度来讨论Win()编制

PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
nCmdShow )
{
MSG msg;

while( lpCmdLine[0] \'-\' || lpCmdLine[0] \'/\')
{
lpCmdLine;

switch (*lpCmdLine)
{
\'e\':
bUseEmulation = TRUE;
;
\'w\':
bFullscreen = FALSE;
;
\'f\':
bFullscreen = TRUE;
;
\'1\':
CmdLineBufferCount = 1;
;
\'2\':
\'d\':
CmdLineBufferCount = 2;
;
\'3\':
CmdLineBufferCount = 3;
;
\'s\':
bStretch = TRUE;
;
\'S\':
bWantSound = FALSE;
;
\'x\':
bStress= TRUE;
;
\'?\':
bHelp= TRUE;
bFullscreen= FALSE; // give help in windowed mode
;
}

while( IS_SPACE(*lpCmdLine) )
{
lpCmdLine;
}
}

GameMode.cx = get(&lpCmdLine, 640);
GameMode.cy = get(&lpCmdLine, 480);
GameBPP = get(&lpCmdLine, 8);

/*
* create window and other windows things
*/
( !initApplication(hInstance, nCmdShow) )
{
FALSE;
}

/*
* Give user help asked for
*
* This is ugly for now because the whole screen is black
* except for the popup box. This could be fixed with some
* work to get the window size right when it was created instead
* of delaying that work. see ddraw.c
*
*/

( bHelp )
{
MessageBox(hWndMain,
\"F12 - Quit\\n\"
\"NUMPAD 2 - crouch\\n\"
\"NUMPAD 3 - apple\\n\"
\"NUMPAD 4 - right\\n\"
\"NUMPAD 5 - stop\\n\"
\"NUMPAD 6 - left\\n\"
\"NUMPAD 7 - jump\\n\"
\"\\n\"
\"Command line parameters\\n\"
\"\\n\"
\"-e Use emulator\\n\"
\"-S No Sound\\n\"
\"-1 No backbuffer\\n\"
\"-2 _disibledevent=>
while( 1 )
{
(PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE))
{
(!GetMessage( &msg, NULL, 0, 0))
{
;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}


(!bPaused && (bIsActive || !bFullscreen))
{
ProcessFox(lastInput);
lastInput=0;
}

{
WaitMessage;
}
}

(AveFrameRateCount)
{
AveFrameRate = AveFrameRate / AveFrameRateCount;
Msg(\"Average frame rate: %d\", AveFrameRate);
}

msg.wParam;

} /* WinMain */


我们知道在消息循环的中只有个消息----WM_QUIT可以结束这个循环,退出WINDOWS所以我们要在消息循环的前完成所有工作即所有有关化这个概念在下节我们将详细讨论在我们提供例程(在光盘sample目录中)中foxbear.c里WMain()中我们可以看到在消息循环的前先运行DD()对DirectDraw进行检测命令行参数并对相关参数进行赋值和确定显示模式进行窗口检测bhelp值以确定是否显示帮助对话框进行游戏
个游戏消息循环中除了包含般Windows应用消息循环所应包含部分外还应有有关检测游戏单位状态位置、刷新游戏单位和重画新图以及有关人工智能部分在例程中消息循环部分包含了个有关检测游戏单位状态位置、刷新游戏单位和重画新图

在这些般有两种思路方法:
1.在消息循环中直接有关比如说在个RPG游戏中每个循环都检测主角位置是否发生改变若改变了则在新位置上重画主角
2.通过检测WM_TIMER消息以决定是否有关即是每隔段时间(若干个时钟周期)检测然后决定和否

在上面两种思路方法里种是现在较常用缺点是CPU资源占用相对较多但对区别机型适应性较强较稳定第 2种在些较老游戏或对速度要求不高游戏中较常见和第种相比它CPU资源占用相对较少但在区别机型中表现差异极大

在谈WinMain()编制时窗口(WINPROC)编制是必须说窗口可以说是把功能区别通过Switch-Case结构连起来组成个复杂线索基本编写思路方法在Windows编程基础中我们就已经谈到了仔细阅读例程中MainWndProc()相信对您是有相当大帮助

/*
* MainWndProc
*
* Callback for all Windows messages
*/
long FAR PASCAL MainWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
PAINTSTRUCT ps;
HDC hdc;

switch( message )
{
WM_SIZE:
WM_MOVE:
(IsIconic(hWnd))
{
Msg(\"FoxBear is minimized, pausing\");
PauseGame;
}

(bFullscreen)
{
SetRect(&rcWindow, 0, 0, GetMetrics(SM_CXSCREEN), GetMetrics(SM_CYSCREEN));
}

{
GetClientRect(hWnd, &rcWindow);
ClientToScreen(hWnd, (LPPOINT)&rcWindow);
ClientToScreen(hWnd, (LPPOINT)&rcWindow+1);
}
Msg(\"WINDOW RECT: [%d,%d,%d,%d]\", rcWindow.left, rcWindow.top, rcWindow.right, rcWindow.bottom);
;

WM_ACTIVATEAPP:
bIsActive = (BOOL)wParam && GetForegroundWindow hWnd;

(bIsActive)
Msg(\"FoxBear is active\");

Msg(\"FoxBear is not active\");

//
// while we were not-active something bad happened that caused us
// to pause, like a surface restore failing or we got a palette
// changed, now that we are active try to fix things
//
(bPaused && bIsActive)
{
(RestoreGame)
{
UnPauseGame;
}

{
(GetForegroundWindow hWnd)
{
//
// we are unable to restore, this can happen when
// the screen resolution or bitdepth has changed
// we just reload all the art again and re-create
// the front and back buffers. this is a little
// overkill we could handle a screen res change by
// just recreating the front and back buffers we dont
// need to redo the art, but this is way easier.
//
(InitGame)
{
UnPauseGame;
}
}
}
}
;

WM_QUERYNEWPALETTE:
//
// we are getting the palette focus, select our palette
//
(!bFullscreen && lpPalette && lpFrontBuffer)
{
HRESULT ddrval;

ddrval = IDirectDrawSurface_SetPalette(lpFrontBuffer,lpPalette);
( ddrval DDERR_SURFACELOST )
{
IDirectDrawSurface_Restore( lpFrontBuffer );

ddrval= IDirectDrawSurface_SetPalette(lpFrontBuffer,lpPalette);
( ddrval DDERR_SURFACELOST )
{
Msg(\" Failed to restore palette after second try\");
}
}

//
// Restore normal title palette is ours
//

( ddrval DD_OK )
{
SetWindowText( hWnd, OUR_APP_NAME );
}
}
;

WM_PALETTECHANGED:
//
// another app changed the palette we dont have full control
// of the palette. NOTE this _disibledevent=>{
( !bFullscreen )
{
( !bStress )
{
Msg(\"***** PALETTE CHANGED, PAUSING GAME\");
PauseGame;
}

{
Msg(\"Lost palette but continuing\");
SetWindowText( hWnd, OUR_APP_NAME
\" - palette changed COLORS PROBABLY WRONG\" );
}
}
}
;

WM_DISPLAYCHANGE:
;

WM_CREATE:
;

WM_SETCURSOR:
(bFullscreen && bIsActive)
{
SetCursor(NULL);
TRUE;
}
;

WM_SYSKEYUP:
switch( wParam )
{
// handle ALT+ENTER (fullscreen)
VK_RETURN:
bFullscreen = !bFullscreen;
ExitGame;
DDDisable(TRUE); // destroy DirectDraw object
GameMode.cx = 320;
GameMode.cy = 200;
InitGame;
;
}


;

WM_KEYDOWN:
switch( wParam )
{
VK_NUMPAD5:
lastInput=KEY_STOP;
;
VK_DOWN:
VK_NUMPAD2:
lastInput=KEY_DOWN;
;
VK_LEFT:
VK_NUMPAD4:
lastInput=KEY_LEFT;
;
VK_RIGHT:
VK_NUMPAD6:
lastInput=KEY_RIGHT;
;
VK_UP:
VK_NUMPAD8:
lastInput=KEY_UP;
;
VK_HOME:
VK_NUMPAD7:
lastInput=KEY_JUMP;
;
VK_NUMPAD3:
lastInput=KEY_THROW;
;
VK_F5:
bShowFrameCount = !bShowFrameCount;
( bShowFrameCount )
{
dwFrameCount = 0;
dwFrameTime = timeGetTime;
}
;

VK_F6:
{
i;
//
// find our current mode in the mode list
//
(bFullscreen)
{
for (i=0; i<NumModes; i)
{
(ModeList[i].bpp ()GameBPP &&
ModeList[i].w GameSize.cx &&
ModeList[i].h GameSize.cy)
{
;
}
}
}
{
for (i=0; i<NumModes; i)
{
(ModeList[i].w GameSize.cx &&
ModeList[i].h GameSize.cy)
{
;
}
}
}
//
// now step to the next mode, wrapping to the first _disibledevent=>{
i = 0;
}
Msg(\"ModeList %d %d\",i,NumModes);
GameMode.cx = ModeList[i].w;
GameMode.cy = ModeList[i].h;
GameBPP = ModeList[i].bpp;
bStretch = FALSE;
InitGame;
}
;
VK_F7:
GameBPP = GameBPP 8 ? 16 : 8;
InitGame;
;

VK_F8:
(bFullscreen)
{
bStretch = !bStretch;
InitGame;
}

{
RECT rc;

GetClientRect(hWnd, &rc);

bStretch = (rc.right != GameSize.cx) ||
(rc.bottom != GameSize.cy);

(bStretch = !bStretch)
SetRect(&rc, 0, 0, GameMode.cx*2, GameMode.cy*2);

SetRect(&rc, 0, 0, GameMode.cx, GameMode.cy);

AdjustWindowRectEx(&rc,
GetWindowStyle(hWnd),
GetMenu(hWnd) != NULL,
GetWindowExStyle(hWnd));

SetWindowPos(hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
}
;
VK_F9: DevIndex ;
bUseEmulation = FALSE;
(DevIndex >= MaxDevIndex)
DevIndex = 0;

ExitGame;
DDDisable(TRUE); // destroy DirectDraw object
InitGame;
;
VK_F4:
// treat F4 like ALT+ENTER (fullscreen)
PostMessage(hWnd, WM_SYSKEYUP, VK_RETURN, 0);
;

VK_F3:
bPaused = !bPaused;
;

VK_ESCAPE:
VK_F12:
PostMessage(hWnd, WM_CLOSE, 0, 0);
0;
}
;

WM_PAINT:
hdc = BeginPa( hWnd, &ps );
(bPaused)
{
char *sz = \"Game is paused, this is not a bug.\";
TextOut(ps.hdc, 0, 0, sz, lstrlen(sz));
}
EndPa( hWnd, &ps );
1;

WM_DESTROY:
hWndMain = NULL;
lastInput=0;
DestroyGame; // end of game
DDDisable(TRUE); // destroy DirectDraw object
PostQuitMessage( 0 );
;
}

DefWindowProc(hWnd, message, wParam, lParam);

} /* MainWndProc */


第 3节 游戏

游戏化包括 3部分:
1.Windows
2.游戏工具
3.游戏

在这 3部分中Windows也就是对窗口注册、定义和我们在Win- dows编程基础中已经谈过这里就不再详述了

游戏工具是指对游戏中用到工具进行对于个游戏而言我们需要针对游戏需要使用些对图形或声音管理绘制或播放以及其他功能系统这些系统就是我们所说游戏工具(有时人们也称的为游戏引擎)这些工具有时是由些游戏公司提供比如MICROSOFTDirectX5 SDK有时是自己针对游戏需要编制或使用上部作品中用过系统在本例程中是指对Directdraw和DirectSound进行您可以通过阅读DDinit()和 InitSound()以及InitGame()部分原代码以及阅读我们提供有关Directdraw和DirectSound章节来理解

DDinit()和 InitSound()以及InitGame()代码:
/*
* InitGame
*
* Initializing current game
*/
BOOL InitGame( void )
{
ExitGame;

GameSize = GameMode;

/*
* initialize sound
*/
InitSound( hWndMain );

/*
* init DirectDraw, mode, ...
* NOTE GameMode might be to 640x480 we cant get the asked for mode.
*/
( !PreInitializeGame )
{
FALSE;
}

(bStretch && bFullscreen)
{
GameSize.cx = GameMode.cx / 2;
GameSize.cy = GameMode.cy / 2;
GameRect.left = GameMode.cx - GameSize.cx;
GameRect.top = GameMode.cy - GameSize.cy;
GameRect.right = GameMode.cx;
GameRect.bottom = GameMode.cy;

(lpStretchBuffer)
Msg(\"Stretching using a system-memory stretch buffer\");

Msg(\"Stretching using a VRAM->VRAM blt\");
}

{
GameRect.left = (GameMode.cx - GameSize.cx) / 2;
GameRect.top = (GameMode.cy - GameSize.cy) / 2;
GameRect.right = GameRect.left + GameSize.cx;
GameRect.bottom = GameRect.top + GameSize.cy;
}

/*
* up our palette
*/
( GameBPP 8 )
{
lpPalette = ReadPalFile( NULL ); // create a 332 palette

( lpPalette NULL )
{


ProcessFox(lastInput);
lastInput=0;
}
语句段ProcessFox(lastInput)通过ProcessInput和NewGameFrame( )达成刷新游戏单元和重画新图功能(这 3个原代码见例程foxbear.c和gameproc.c两文件)

ProcessFox(lastInput):

/*
* ProcessFox
*/
BOOL ProcessFox(SHORT sInput)
{
((lpFrontBuffer && IDirectDrawSurface_IsLost(lpFrontBuffer) DDERR_SURFACELOST) ||
(lpBackBuffer && IDirectDrawSurface_IsLost(lpBackBuffer) DDERR_SURFACELOST))
{
(!RestoreGame)
{
PauseGame;
FALSE;
}
}


ProcessInput(sInput);
NewGameFrame;
TRUE;

} /* ProcessFox */

HFONT hFont;

DWORD dwFrameCount;
DWORD dwFrameTime;
DWORD dwFrames;
DWORD dwFramesLast;
SIZE sizeFPS;
SIZE sizeINFO;
FrameRateX;
char szFPS = \"FPS %02d\";
char szINFO = \"%dx%dx%d%s F6=mode F8=x2 ALT+ENTER=Window\";
char szINFOW = \"%dx%dx%d%s F6=mode F8=x2 ALT+ENTER=Fullscreen\";

char szFrameRate[128];
char szInfo[128];

COLORREF InfoColor = RGB(0,152,245);
COLORREF FrameRateColor = RGB(255,255,0);
COLORREF BackColor = RGB(255,255,255);

/*
* initNumSurface
*/
void initNumSurface( void )
{
HDC hdc;
RECT rc;
len;

dwFramesLast = 0;

len = wsprf(szFrameRate, szFPS, 0, 0);

( lpFrameRate && IDirectDrawSurface_GetDC(lpFrameRate, &hdc ) DD_OK )
{
SelectObject(hdc, hFont);
SetTextColor(hdc, FrameRateColor);
SetBkColor(hdc, BackColor);
SetBkMode(hdc, OPAQUE);
SetRect(&rc, 0, 0, 10000, 10000);
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, szFrameRate, len, NULL);
GetTextExtentPo(hdc, szFrameRate, 4, &sizeFPS);
FrameRateX = sizeFPS.cx;
GetTextExtentPo(hdc, szFrameRate, len, &sizeFPS);

IDirectDrawSurface_ReleaseDC(lpFrameRate, hdc);
}

(bFullscreen)
len = wsprf(szInfo, szINFO,
GameSize.cx, GameSize.cy, GameBPP,bStretch ? \" x2\" : \"\");

len = wsprf(szInfo, szINFOW,
GameSize.cx, GameSize.cy, GameBPP,bStretch ? \" x2\" : \"\");

( lpInfo && IDirectDrawSurface_GetDC(lpInfo, &hdc ) DD_OK )
{
SelectObject(hdc, hFont);
SetTextColor(hdc, InfoColor);
SetBkColor(hdc, BackColor);
SetBkMode(hdc, OPAQUE);
SetRect(&rc, 0, 0, 10000, 10000);
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, szInfo, len, NULL);
GetTextExtentPo(hdc, szInfo, len, &sizeINFO);

IDirectDrawSurface_ReleaseDC(lpInfo, hdc);
}

} /* initNumSurface */

NewGameFrame( ):

/*
* NewGameFrame
*/
NewGameFrame( void )
{

SetSpriteX( hFox, 0, P_AUTOMATIC );
SetSpriteY( hFox, 0, P_AUTOMATIC );

SetPlaneVelX( hBackground, GetSpriteVelX(hFox), P_ABSOLUTE );
SetPlaneVelX( hMidground, GetSpriteVelX(hFox), P_ABSOLUTE );
SetPlaneVelX( hForeground, GetSpriteVelX(hFox), P_ABSOLUTE );

SetPlaneX( hBackground, 0, P_AUTOMATIC );
SetPlaneX( hMidground, 0, P_AUTOMATIC );
SetPlaneX( hForeground, 0, P_AUTOMATIC );

SetSpriteX( hBear, 0, P_AUTOMATIC );
SetSpriteX( hApple, 0, P_AUTOMATIC );
SetSpriteY( hApple, 0, P_AUTOMATIC );

/*
* _disibledevent=>LONG foxSpeedX;
LONG foxSpeedY;
LONG foxX;
LONG foxY;
LONG bearX;
LONG bearY;
LONG appleX;
LONG appleY;
ACTION foxAction;
DIRECTION foxDir;
BOOL cont = TRUE;

foxSpeedX = GetSpriteVelX( hFox );
foxAction = GetSpriteAction( hFox );
foxDir = GetSpriteDirection( hFox );



( (GetSpriteActive(hFox) FALSE) && (input != 4209) )
{
input = 0;
}
switch( input )
{
KEY_DOWN:
( foxAction STOP )
{
;
}
( foxAction STILL )
{
SetSpriteAction( hFox, CROUCH, SAME );
}
( foxAction WALK )
{
SetSpriteAction( hFox, CROUCHWALK, SAME );
}
;

KEY_LEFT:
( foxAction STOP )
{
;
}
( foxSpeedX 0 )
{
( foxAction STILL )
{
( foxDir RIGHT )
{
ChangeSpriteDirection( hFox );
SetPlaneSlideX( hForeground, -C_BOUNDDIF, P_RELATIVE );
SetPlaneSlideX( hMidground, -C_BOUNDDIF, P_RELATIVE );
SetPlaneSlideX( hBackground, -C_BOUNDDIF, P_RELATIVE );
SetPlaneIncremX( hForeground, C_BOUNDINCREM, P_ABSOLUTE );
SetPlaneIncremX( hBackground, C_BOUNDINCREM, P_ABSOLUTE );
SetPlaneIncremX( hMidground, C_BOUNDINCREM, P_ABSOLUTE );
}

{
SetSpriteAction( hFox, WALK, LEFT );
SetSpriteSwitch( hFox, C_FOX_WALKSWITCH, P_ABSOLUTE );
SetSpriteVelX( hFox, -C_FOX_XMOVE, P_RELATIVE );
}
}
( foxAction CROUCH )
{
( foxDir RIGHT )
{
ChangeSpriteDirection( hFox );
SetPlaneSlideX( hForeground, -C_BOUNDDIF, P_RELATIVE );
SetPlaneSlideX( hMidground, -C_BOUNDDIF, P_RELATIVE );
SetPlaneSlideX( hBackground, -C_BOUNDDIF, P_RELATIVE );
SetPlaneIncremX( hForeground, C_BOUNDINCREM, P_ABSOLUTE );
SetPlaneIncremX( hBackground, C_BOUNDINCREM, P_ABSOLUTE );
SetPlaneIncremX( hMidground, C_BOUNDINCREM, P_ABSOLUTE );
}

{
SetSpriteAction( hFox, CROUCHWALK, LEFT );
SetSpriteSwitch( hFox, C_FOX_WALKSWITCH, P_ABSOLUTE );
SetSpriteVelX( hFox, -C_FOX_XMOVE, P_RELATIVE );
}
}

{
SetSpriteVelX( hFox, -C_FOX_XMOVE, P_RELATIVE );
}
} {
SetSpriteVelX( hFox, -C_FOX_XMOVE, P_RELATIVE );
}
;

KEY_RIGHT:
.
.
.
KEY_STOP:
( foxAction STOP )
{
;
}
( (foxAction RUN) || (foxAction BLURR) )
{
SetSpriteAction( hFox, STOP, SAME );
SetSpriteAccX( hFox, -foxSpeedX / 25, P_ABSOLUTE );
SoundPlayEffect( SOUND_STOP );
} {
SetSpriteVelX( hFox, 0, P_ABSOLUTE );
}
;

KEY_UP:
( foxAction STOP )
{
;
}
( foxAction CROUCH )
{
SetSpriteAction( hFox, STILL, SAME );
}
( foxAction CROUCHWALK )
{
SetSpriteAction( hFox, WALK, SAME );
}
;

KEY_JUMP:
( foxAction STOP )
{
;
}

( (foxAction STILL) || (foxAction WALK) ||
(foxAction RUN) || (foxAction CROUCH) ||
(foxAction CROUCHWALK) )
{
SetSpriteAction( hFox, JUMP, SAME );
SetSpriteSwitchType( hFox, TIME );
SetSpriteSwitch( hFox, C_FOX_JUMPSWITCH, P_ABSOLUTE );
SetSpriteVelY( hFox, -C_FOX_JUMPMOVE, P_ABSOLUTE );
SetSpriteAccY( hFox, C_UNIT / 2, P_ABSOLUTE );
SoundPlayEffect( SOUND_JUMP );
}
;

KEY_THROW:
( foxAction STOP )
{
;
}
( (foxAction STILL) || (foxAction WALK) ||
(foxAction RUN) || (foxAction CROUCH) ||
(foxAction CROUCHWALK) )
{
SetSpriteAction( hFox, THROW, SAME );
SetSpriteSwitch( hFox, C_FOX_THROWSWITCH, P_ABSOLUTE );
SetSpriteVelX( hFox, 0, P_ABSOLUTE );
SetSpriteSwitchType( hFox, TIME );
}
( foxAction JUMP )
{
SetSpriteAccY( hFox, 0, P_ABSOLUTE );
SetSpriteSwitch( hFox, C_FOX_THROWSWITCH, P_ABSOLUTE );
SetSpriteAction( hFox, JUMPTHROW, SAME );
SetSpriteVelY( hFox, 0, P_ABSOLUTE );
SetSpriteSwitchDone( hFox, FALSE );
SetSpriteSwitchForward( hFox, TRUE );
}
;

default:
;
}

/*
* Fox actions follow...
*/
( GetSpriteActive(hFox) FALSE )
{
goto bearActions;
}

( abs(GetSpriteVelX( hFox )) < C_FOX_XMOVE )
{
SetSpriteVelX( hFox, 0, P_ABSOLUTE );
}

foxAction = GetSpriteAction( hFox );

( GetSpriteVelY(hFox) 0 )
{
( GetSurface( hForeground, hFox ) FALSE )
{
( (foxAction WALK) || (foxAction RUN) ||
(foxAction CROUCHWALK) )
{
SetSpriteAccY( hFox, C_UNIT / 2, P_ABSOLUTE );
}
( foxAction STOP )
{
SetSpriteAccY( hFox, C_UNIT / 2, P_ABSOLUTE );
SetSpriteAccX( hFox, 0, P_ABSOLUTE );
}
}
}
( GetSpriteVelY(hFox) > 2 * C_UNIT )
{
( (foxAction WALK) || (foxAction RUN) ||
(foxAction CROUCHWALK) )
{
SetSpriteSwitchForward( hFox, FALSE );
SetSpriteAction( hFox, JUMP, SAME );
SetSpriteSwitchType( hFox, TIME );
SetSpriteSwitch( hFox, C_FOX_JUMPSWITCH, P_ABSOLUTE );
}
( foxAction STOP )
{
SetSpriteAction( hFox, STUNNED, SAME );
SetSpriteAccX( hFox, -GetSpriteVelX(hFox) / 25, P_ABSOLUTE );
SoundPlayEffect( SOUND_STUNNED );
}
}

foxSpeedX = GetSpriteVelX( hFox );
foxSpeedY = GetSpriteVelY( hFox );
foxAction = GetSpriteAction( hFox );
foxDir = GetSpriteDirection( hFox );

switch( foxAction ) {
STUNNED:
( (GetSpriteVelY(hFox) >= 0) &&
(!GetSurface( hForeground, hFox ) FALSE) )
{


SetSpriteAccY( hFox, 0, P_ABSOLUTE );
SetSpriteAction( hFox, STOP, SAME );
SetSpriteVelY( hFox, 0, P_ABSOLUTE );
SetSpriteAccX( hFox, -foxSpeedX / 25, P_ABSOLUTE );
// SetSurface( hForeground, hFox );
SoundPlayEffect( SOUND_STOP );
}
;

CROUCHWALK:
( foxSpeedX 0 )
{
SetSpriteAction( hFox, CROUCH, SAME );
}
( foxSpeedX > C_FOX_WALKMOVE )
{
SetSpriteVelX( hFox, C_FOX_WALKMOVE, P_ABSOLUTE );
}
( foxSpeedX < -C_FOX_WALKMOVE )
{
SetSpriteVelX( hFox, -C_FOX_WALKMOVE, P_ABSOLUTE );
}
;

STOP:
( foxSpeedX 0 )
{
SetSpriteAction( hFox, STILL, SAME );
SetSpriteAccX( hFox, 0, P_ABSOLUTE );
}
;

RUN:
( (foxSpeedX < C_FOX_WALKTORUN ) && (foxSpeedX > 0) )
{
SetSpriteAction( hFox, WALK, RIGHT );
SetSpriteSwitch( hFox, C_FOX_WALKSWITCH, P_ABSOLUTE );
}
( foxSpeedX > C_FOX_RUNTOBLURR )
{
SetSpriteAction( hFox, BLURR, RIGHT );
SetSpriteSwitch( hFox, C_FOX_BLURRSWITCH, P_ABSOLUTE );
}
( (foxSpeedX > -C_FOX_WALKTORUN ) && (foxSpeedX < 0) )
{
SetSpriteAction( hFox, WALK, LEFT );
SetSpriteSwitch( hFox, C_FOX_WALKSWITCH, P_ABSOLUTE );
}
( foxSpeedX < -C_FOX_RUNTOBLURR )
{
SetSpriteAction( hFox, BLURR, LEFT );
SetSpriteSwitch( hFox, C_FOX_BLURRSWITCH, P_ABSOLUTE );
}
;

WALK:
( foxSpeedX 0 )
{
SetSpriteAction( hFox, STILL, SAME );
}
( foxSpeedX > C_FOX_WALKTORUN )
{
SetSpriteAction( hFox, RUN, RIGHT );
SetSpriteSwitch( hFox, C_FOX_RUNSWITCH, P_ABSOLUTE );
}
( foxSpeedX < -C_FOX_WALKTORUN )
{
SetSpriteAction( hFox, RUN, LEFT );
SetSpriteSwitch( hFox, C_FOX_RUNSWITCH, P_ABSOLUTE );
}
;

BLURR:
( (foxSpeedX < C_FOX_RUNTOBLURR ) && (foxSpeedX > C_FOX_WALKTORUN) )
{
SetSpriteAction( hFox, RUN, RIGHT );
SetSpriteSwitch( hFox, C_FOX_RUNSWITCH, P_ABSOLUTE );
}
( (foxSpeedX > -C_FOX_RUNTOBLURR ) && (foxSpeedX < -C_FOX_WALKTORUN) )
{
SetSpriteAction( hFox, RUN, LEFT );
SetSpriteSwitch( hFox, C_FOX_RUNSWITCH, P_ABSOLUTE );
}
;

JUMPTHROW:
( !GetSpriteSwitchDone(hFox) FALSE )
{
SetSpriteSwitchForward( hFox, FALSE );
SetSpriteAction( hFox, JUMP, SAME );
SetSpriteSwitch( hFox, C_FOX_JUMPSWITCH, P_ABSOLUTE );
SetSpriteSwitchDone( hFox, FALSE );
SetSpriteAccY( hFox, C_UNIT / 2, P_ABSOLUTE );
SoundPlayEffect( SOUND_THROW );
}

( (GetSpriteBitmap(hFox) 1) &&
(GetSpriteDirection(hFox) RIGHT) )
{
SetSpriteActive( hApple, TRUE );
SetSpriteX( hApple, GetSpriteX(hFox) + 60 * C_UNIT, P_ABSOLUTE );
SetSpriteY( hApple, GetSpriteY(hFox) + 30 * C_UNIT, P_ABSOLUTE );
SetSpriteVelX( hApple, 8 * C_UNIT, P_ABSOLUTE );
SetSpriteVelY( hApple, -4 * C_UNIT, P_ABSOLUTE );
SetSpriteAccX( hApple, 0, P_ABSOLUTE );
SetSpriteAccY( hApple, C_UNIT / 4, P_ABSOLUTE );
}
( (GetSpriteBitmap(hFox) 1) &&
(GetSpriteDirection(hFox) LEFT) )
{
SetSpriteActive( hApple, TRUE );
SetSpriteX( hApple, GetSpriteX(hFox) + 15 * C_UNIT, P_ABSOLUTE );
SetSpriteY( hApple, GetSpriteY(hFox) + 30 * C_UNIT, P_ABSOLUTE );
SetSpriteVelX( hApple, -8 * C_UNIT, P_ABSOLUTE );
SetSpriteVelY( hApple, -4 * C_UNIT, P_ABSOLUTE );
SetSpriteAccX( hApple, 0, P_ABSOLUTE );
SetSpriteAccY( hApple, C_UNIT / 4, P_ABSOLUTE );
}
;

THROW:
( !GetSpriteSwitchDone(hFox) FALSE )
{
SetSpriteAction( hFox, STILL, SAME );
SetSpriteSwitchType( hFox, HOR );
SetSpriteSwitch( hFox, 0, P_ABSOLUTE );
SetSpriteSwitchDone( hFox, FALSE );
SoundPlayEffect( SOUND_THROW );
}
( (GetSpriteBitmap(hFox) 1) &&
(GetSpriteDirection(hFox) RIGHT) )
{
SetSpriteActive( hApple, TRUE );
SetSpriteX( hApple, GetSpriteX(hFox) + 60 * C_UNIT, P_ABSOLUTE );
SetSpriteY( hApple, GetSpriteY(hFox) + 50 * C_UNIT, P_ABSOLUTE );
SetSpriteVelX( hApple, 8 * C_UNIT, P_ABSOLUTE );
SetSpriteVelY( hApple, -4 * C_UNIT, P_ABSOLUTE );
SetSpriteAccX( hApple, 0, P_ABSOLUTE );
SetSpriteAccY( hApple, C_UNIT / 4, P_ABSOLUTE );
}
( (GetSpriteBitmap(hFox) 1) &&
(GetSpriteDirection(hFox) LEFT) )
{
SetSpriteActive( hApple, TRUE );
SetSpriteX( hApple, GetSpriteX(hFox) + 20 * C_UNIT, P_ABSOLUTE );
SetSpriteY( hApple, GetSpriteY(hFox) + 50 * C_UNIT, P_ABSOLUTE );
SetSpriteVelX( hApple, -8 * C_UNIT, P_ABSOLUTE );
SetSpriteVelY( hApple, -4 * C_UNIT, P_ABSOLUTE );
SetSpriteAccX( hApple, 0, P_ABSOLUTE );
SetSpriteAccY( hApple, C_UNIT / 4, P_ABSOLUTE );
}
;

JUMP:
( (foxSpeedY >= 0) && (!GetSpriteSwitchForward( hFox ) FALSE) )
{
SetSpriteSwitchForward( hFox, FALSE );
}
( GetSpriteSwitchForward( hFox ) FALSE )
{
( (!GetSurface( hForeground, hFox ) FALSE) ||
(!GetSurface( hForeground, hFox ) FALSE) )
{


通过阅读ProcessInput代码我想您定已理解了刷新游戏单元概念而从上面两个例子中您也定发现用例程思路方法很难实现这两类游戏要求我们不可能对每颗子弹个战斗单位进行操作而且我们并不知道游戏者会次发射多少颗子弹也不知道游戏者会造多少个战斗单位我们应该如何办呢?

考虑到每个战斗单位(或每颗子弹)都有相似(或相同)属性那么我们可以采用结构来储存每个战斗单位位置和状态这个办法好象可行!但是仔细想想我们又遇到了上面谈到问题我们并不知道游戏者会次发射多少颗子弹也不知道游戏者会造多少个战斗单位当然我们可以采用Age of Empire方式----限制单位数量(我并不是说Age of Empire采用是这种办法)但是这意味什么呢!意味着如果我们限定数量为50在游戏者只有个士兵时计算机却需要为这个士兵分配50倍内存!而且游戏者还不定造出50个士兵显然这并不是个好办法!

我们应该如何办呢?链表!链表能满足我们要求

Node
{
//双向链表指针
Node* Next;
Node* Pre;

//节点数据
NODE_DATA data;
...
};

链表是种结构体集合在链表中个结构体都包含了个元素或指针它指向链表中个结构体这个指针用作两个结构体的间联系这个概念和有些相似但它允许链表动态增长现在游戏中凡是遇到这种问题般都是采用链表有关链表更多信息请阅读有关资料


第 6节 画游戏单元
画游戏单位作用是在每桢往屏幕上画游戏单位图象

这就是本例程中画游戏单元:
/*
* NewGameFrame
*/
NewGameFrame( void )
{
//这里是设置游戏单元位置:
SetSpriteX( hFox, 0, P_AUTOMATIC );
SetSpriteY( hFox, 0, P_AUTOMATIC );

SetPlaneVelX( hBackground, GetSpriteVelX(hFox), P_ABSOLUTE );
SetPlaneVelX( hMidground, GetSpriteVelX(hFox), P_ABSOLUTE );
SetPlaneVelX( hForeground, GetSpriteVelX(hFox), P_ABSOLUTE );

SetPlaneX( hBackground, 0, P_AUTOMATIC );
SetPlaneX( hMidground, 0, P_AUTOMATIC );
SetPlaneX( hForeground, 0, P_AUTOMATIC );

SetSpriteX( hBear, 0, P_AUTOMATIC );
SetSpriteX( hApple, 0, P_AUTOMATIC );
SetSpriteY( hApple, 0, P_AUTOMATIC );

//将游戏单元图形贴到BackBuffer上:
( bTransDest )
{
gfxFillBack( dwColorKey );

DisplayFrameRate;

DisplaySprite( hBuffer, hApple, GetPlaneX(hForeground) );
DisplaySprite( hBuffer, hBear, GetPlaneX(hForeground) );
DisplaySprite( hBuffer, hFox, GetPlaneX(hForeground) );

DisplayPlane( hBuffer, hForeground );
DisplayPlane( hBuffer, hMidground );
DisplayPlane( hBuffer, hBackground );
}

{
DisplayPlane( hBuffer, hBackground );
DisplayPlane( hBuffer, hMidground );
DisplayPlane( hBuffer, hForeground );

DisplaySprite( hBuffer, hFox, GetPlaneX(hForeground) );
DisplaySprite( hBuffer, hBear, GetPlaneX(hForeground) );
DisplaySprite( hBuffer, hApple, GetPlaneX(hForeground) );

DisplayFrameRate;
}

//更新前景:
gfxSwapBuffers;

0;

} /* NewGameFrame */

画游戏单元顺序为:
1清BackBuffer;

这是清BackBuffer:
/*
* gfxFillBack
*/
void gfxFillBack( DWORD dwColor )
{
DDBLTFX ddbltfx;

ddbltfx.dwSize = ( ddbltfx );
ddbltfx.dwFillColor = dwColor;

IDirectDrawSurface_Blt(
lpBackBuffer, // dest surface
NULL, // dest rect
NULL, // src surface
NULL, // src rect
DDBLT_COLORFILL | DDBLT_WAIT,
&ddbltfx);

} /* gfxFillBack */

2检查游戏单元图形Surface是否丢失;

这是检查游戏单元图形Surface是否丢失:
/*
* gfxRestoreAll
*
* restore the art when _disibledevent=>
Splash;

for( curr = lpVRAM; curr != NULL; curr = curr->link)
{
(curr->lpSurface &&
(fForceRestore || IDirectDrawSurface_IsLost(curr->lpSurface) DDERR_SURFACELOST))
{
( !gfxRestore(curr) )
{
Msg( \"gfxRestoreAll: ************ Restore FAILED!\" );
FALSE;
}
}
}

DDClear;
fForceRestore = FALSE;
TRUE;

} /* gfxRestoreAll */

3将游戏单元图形画到BackBuffer中;

这是画游戏单元图形:
/*
* DisplayPlane
*/
BOOL DisplayPlane ( GFX_HBM hBuffer, HPLANE *hPlane )
{
USHORT n;
USHORT i;
USHORT j;
USHORT x1;
USHORT y1;
USHORT x2;
USHORT y2;
USHORT xmod;
USHORT ymod;
POINT src;
RECT dst;


x1 = (hPlane->x >> 16) / C_TILE_W;
y1 = (hPlane->y >> 16) / C_TILE_H;
x2 = x1 + C_SCREEN_W / C_TILE_W;
y2 = y1 + C_SCREEN_H / C_TILE_H;
xmod = (hPlane->x >> 16) % C_TILE_W;
ymod = (hPlane->y >> 16) % C_TILE_H;

for( j = y1; j < y2; j )
{
for( i = x1; i <= x2; i )
{
n = (i % hPlane->width) + j * hPlane->width;
( hPlane->hBM[n] != NULL )
{
( i x1 )
{
dst.left = 0;
dst.right = dst.left + C_TILE_W - xmod;
src.x = xmod;
}
( i x2 )
{
dst.left = (i - x1) * C_TILE_W - xmod;
dst.right = dst.left + xmod;
src.x = 0;
} {
dst.left = (i - x1) * C_TILE_W - xmod;
dst.right = dst.left + C_TILE_W;
src.x = 0;
}



( j y1 )
{
dst.top = 0;
dst.bottom = dst.top + C_TILE_H - ymod;
src.y = ymod;
}
( j y2 )
{
dst.top = (j - y1) * C_TILE_H - ymod;
dst.bottom = dst.top + ymod;
src.y = 0;
} {
dst.top = (j - y1) * C_TILE_H - ymod;
dst.bottom = dst.top + C_TILE_H;
src.y = 0;
}

gfxBlt(&dst,hPlane->hBM[n],&src);
}
}
}

TRUE;

} /* DisplayPlane */

4将BackBuffer和FrontBuffer进行翻转;

这是全屏幕模式下页面翻转:
/*
* gfxFlip
*/
BOOL gfxFlip( void )
{
HRESULT ddrval;

ddrval = IDirectDrawSurface_Flip( lpFrontBuffer, NULL, DDFLIP_WAIT );
( ddrval != DD_OK )
{
Msg( \"Flip FAILED, rc=%08lx\", ddrval );
FALSE;
}
TRUE;

} /* gfxFlip */

这是窗口模式下页面翻转:
/*
* gfxUpdateWindow
*/
BOOL gfxUpdateWindow
{
HRESULT ddrval;

ddrval = IDirectDrawSurface_Blt(
lpFrontBuffer, // dest surface
&rcWindow, // dest rect
lpBackBuffer, // src surface
NULL, // src rect (all of it)
DDBLT_WAIT,
NULL);

ddrval DD_OK;

} /* gfxUpdateWindow */


第 7节 计算机人工智能

计算机人工智能

记得吗?在第 5节刷新游戏单元中我们谈到在刷新游戏单元时说到在取得游戏单位位置后要经过些算法判断再确定游戏单位新位置包含这些算法
分就是游戏中实现人工智能部分

对于游戏中人工智能我比较赞同下面这个定义:个非游戏者控制对象在基于各种复杂原因时决策行为就象时由真正人作出这是通过使用 个决策算法来完成这个决策算法根据设计者确定规则和提供给信息进行处理

现在在大部分游戏中采用方式主要有以下几种:

检索
许多人工智能算法中都涉及到对所有可能性检索这个算法实现方式是这样首先您应让您个选项表例如个士兵到目的间所有可能路径然后再使用其他人工智能技术如排除法等来找个最优选择

排序
排序和检索都是基本人工智能技术您可以用排序来确定最佳决策次序比 如在战略游戏中计算机对手不断地根据当前环境修改行动优先级

专家系统
专家系统是指运用“ then”语句逻辑表达式来表示所有基本规则然后计算机根据这些规则作出智能决策比如在制作个足球游戏时就可以请个足球专家记下他足球经验他会介绍说明在各种情况下他采取踢球方式根据这些信息建立套规则库在游戏中计算机就可以按照这些规则作出决策

其他方式还有:机器学习和和神经网络系统这两种方式效果相当不错但是却很不容易掌握这里我们就不再详述了


第 8节 游戏内存管理

游戏内存管理

部分对于优质高效游戏软件Software是十分重要内存管理不当会导致游戏性能降低甚至引起死机现在很多游戏都使用了大量图象和复杂规则需要大量内存这就需要我们对游戏者所用机器内存进行精心分配和组织了首先我们应当调查下现在主流机型内存是多少再和达到游戏设计目标所需内存量的间权衡然后确定个粗略分配方案

这个方案般可以这样指定:

1.这个游戏从情节上可以分为几个部分在开始时将每个部分所共有资料调入然后根据情节发展将该部分不用资料所占用内存释放再调入该部分所特有资料比如说可以分为几关或者RPG游戏中“世界”地图可以分成几个场景然后在游戏者到达某关或进入某场景时再调入相应图象或相应资料

2.在每个部分中有很多并不常用而且时没有严格速度限制同时时并不需要太多时间(通常1秒左右即可完成)资料也可以在使用时比如角色从大地图上走入个城市这个城市图象和游戏规则等资料就可以在走入这个城市时调入

在完成这个方案后我们就完成了内存和硬盘的间数据交换规划了接下来就应考虑运行时内存内部管理了

在这步中主要应注意两个问题:

1.迅速释放存放无效资料内存;

例如:

描述GAMEWORLD指针temp在化时分配了内存空间
GAMEWORLD *temp= GAMEWORLD(Init value);


结束时要释放内存空间
delete temp;

2.严禁使用空指针(这样会导致系统甚至死机)这里没有什么窍门技巧只有靠您自己认真和仔细了

例如:
当在中已经释放了temp;
下面就可能导致死机:
temp->Function;

这两个问题解决思路方法为:

GAMEWORLD *temp= GAMEWORLD(Init value);
...

(temp)
delete temp;
temp=NULL;
...

(temp)
{
temp->Function;
...
}

{
提示temp为空指针
}


第 9节 游戏交互设计

游戏交互设计

交互设计实际上就是您想让游戏者如何去操纵游戏发展说简单了交互设计就是游戏者怎样去控制游戏角色行动在例程中对键盘设置——用小建盘上“456237”控制狐狸行为就是种简单交互设计说复杂了呢!就是您提供了种什么样方式让游戏者进入游戏的中成为游戏中员——他就是游戏中英勇无敌、侠肝义胆剑客他就是游戏中足智多谋、威震天下将军……这就是好游戏个重要要素——好交互性

交互性就是设计者创造个诱使人去玩游戏所拥有提供故事线索、情绪感染、真实声音和其他创造性媒介所给予特性交互设计就是让游戏者进入“幻觉状态”幻觉状态是游戏界个术语意思是指游戏者意识融入到游戏世界中这样他或她就不是在玩游戏而是在体验另个世界

怎样作到这点呢?作为编程人员应考虑是:

步考虑输入设备问题设备即是游戏者控制游戏手段也就是输入设备选择和设置问题在这步中应该考虑是选择键盘、鼠标、游戏杆还是几种结合方式或是其他类型输入设备然后是设置各种操作所代表含义(就象例程中
小键盘“4”代表左行“5”代表停止等等或是鼠标单击、双击某个区域及拖动时代表含义)这些设置主要是考虑个操作方便性问题



typedef enum enum_ACTION {
NONE,
STILL,
WALK,
RUN,
JUMP,
THROW,
CROUCH,
STOP,
STUNNED,
JUMPTHROW,
CROUCHWALK,
BLURR,
STRIKE,
MISS,
CHEW,
} ACTION;


WinMainProc中:

WM_KEYDOWN:
switch( wParam )
{
VK_NUMPAD5:
lastInput=KEY_STOP;
;
VK_DOWN:
VK_NUMPAD2:
lastInput=KEY_DOWN;
;
VK_LEFT:
VK_NUMPAD4:
lastInput=KEY_LEFT;
;
VK_RIGHT:
VK_NUMPAD6:
lastInput=KEY_RIGHT;
;
VK_UP:
VK_NUMPAD8:
lastInput=KEY_UP;
;
VK_HOME:
VK_NUMPAD7:
lastInput=KEY_JUMP;
;
VK_NUMPAD3:
lastInput=KEY_THROW;
;
VK_F5:
bShowFrameCount = !bShowFrameCount;
( bShowFrameCount )
{
dwFrameCount = 0;
dwFrameTime = timeGetTime;
}
;

第 2步考虑信息返回问题这里主要是个界面设计问题这个问题我们在
章第 6节游戏界面设计中已经讨论过了这里就不详述了


第十节 游戏图形底层设计

在游戏中计算机主要花时间在处理图象和画图象上所以我们应尽力使这些操作适合主流机型硬件水平或尽量少占用系统资源这就是游戏图形底层设计在前面讲DirectDraw和DirectX5 SDK中Direct3D都是图形底层还有ID在 QUAKE发行后提供QUAKE C也是种不错图形底层建立套游戏图形底层需要大量有关图形编程知识和很多时间精力而且效果不定好同时在市场上也有很多图形底层可供选择所以对于游戏开发者来说只要作游戏使用图象并没有使计算机不负重荷或并没有使用现有底层所不支持特性我建议还是使用现有底层

本例程图形底层十分简单采用DirectDraw提供IDirectDrawSurface_BltFast和IDirectDrawSurface_Blt:

(pbm->lpSurface)
{
( pbm->bTrans )
bltflags = bTransDest ? DDBLTFAST_DESTCOLORKEY : DDBLTFAST_SRCCOLORKEY;

bltflags = bTransDest ? DDBLTFAST_DESTCOLORKEY : DDBLTFAST_NOCOLORKEY;
ddrval = IDirectDrawSurface_BltFast(
lpBackBuffer, x, y,
pbm->lpSurface, &rc, bltflags | DDBLTFAST_WAIT);

(ddrval != DD_OK)
{
Msg(\"BltFast failed err=%d\", ddrval);
}
}

{
DDBLTFX ddbltfx;

rc.left = x;
rc.top = y;
rc.right = rc.left + dx;
rc.bottom = rc.top + dy;

ddbltfx.dwSize = ( ddbltfx );
ddbltfx.dwFillColor = pbm->dwColor;

ddrval = IDirectDrawSurface_Blt(
lpBackBuffer, // dest surface
&rc, // dest rect
NULL, // src surface
NULL, // src rect
DDBLT_COLORFILL | DDBLT_WAIT,
&ddbltfx);
}

由于DirectDraw通用性要求所以虽然它提供速度很快但是对特效支持比较少深入图形底层应包括大量高效特效处理功能所以我们应该能够直接对显存操作

DirectDrawDirectSurface提供了这个入口DDSURFACEDESC结构中变量
lpSurface就是显存映射入口指针

typedef struct _DDSURFACEDESC {
DWORD dwSize;
DWORD dwFlags;
DWORD dwHeight;
DWORD dwWidth;
union
{
LONG lPitch;
DWORD dwLinearSize;
};
DWORD dwBackBufferCount;
union
{
DWORD dwMipMapCount;
DWORD dwZBufferBitDepth;
DWORD dwRefreshRate;
};
DWORD dwAlphaBitDepth;
DWORD dwReserved;

LPVOID lpSurface;
DDCOLORKEY ddckCKDestOverlay;
DDCOLORKEY ddckCKDestBlt;
DDCOLORKEY ddckCKSrcOverlay;
DDCOLORKEY ddckCKSrcBlt;
DDPIXELFORMAT ddpfPixelFormat;
DDSCAPS ddsCaps;
} DDSURFACEDESC;

但是使用它的前必须DirectDrawSurface3::Lock将此图形内存锁住
在处理后DirectDrawSurface3::Unlock将此内存交还给系统

Tags:  网页游戏开发 网络游戏开发 游戏开发 游戏开发基础

延伸阅读

最新评论

发表评论