📄 donuts.c
字号:
if( lpFrontBuffer != NULL )
lpFrontBuffer->lpVtbl->Release( lpFrontBuffer );
if( lpArtPalette != NULL )
lpArtPalette->lpVtbl->Release( lpArtPalette );
if( lpSplashPalette != NULL )
lpSplashPalette->lpVtbl->Release( lpSplashPalette );
if( lpDD != NULL )
lpDD->lpVtbl->Release( lpDD );
if (DL.next != NULL)
{
while( DL.next != &DL )
{
DeleteFromList( DL.next );
}
}
}
BOOL InitializeGame( void )
{
DDCAPS ddcaps;
HRESULT ddrval;
DDSURFACEDESC2 ddsd;
DDSCAPS2 ddscaps;
DDSURFACEDESC2 DDSurfDesc;
LPDIRECTDRAW pDD;
score = 0;
if( bTest )
ShowLevelCount = 1000;
// Initialize the display list to point at itself. This denotes an empty
// list. We need to do this here because if CleanupAndExit/DestroyGame
// will attempt to walk the display list and delete records.
DL.next = DL.prev = &DL;
if( bUseEmulation )
ddrval = DirectDrawCreate( (LPVOID) DDCREATE_EMULATIONONLY, &pDD, NULL );
else
ddrval = DirectDrawCreate( NULL, &pDD, NULL );
if( ddrval != DD_OK )
return CleanupAndExit(TEXT("DirectDrawCreate Failed!"));
// Fetch DirectDraw4 interface
ddrval = pDD->lpVtbl->QueryInterface( pDD, &IID_IDirectDraw4, (LPVOID*)&lpDD);
if (ddrval != DD_OK)
return CleanupAndExit(TEXT("QueryInterface Failed!"));
pDD->lpVtbl->Release(pDD);
pDD = NULL;
ddrval = lpDD->lpVtbl->SetCooperativeLevel( lpDD, hWndMain,
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
if( ddrval != DD_OK )
return CleanupAndExit(TEXT("SetCooperativeLevel Failed"));
// Get mode info.
memset(&DDSurfDesc, 0, sizeof(DDSurfDesc));
DDSurfDesc.dwSize = sizeof(DDSurfDesc);
ddrval = lpDD->lpVtbl->GetDisplayMode( lpDD, &DDSurfDesc );
if ( ddrval != DD_OK )
return CleanupAndExit(TEXT("GetDisplayMode Failed!"));
ScreenX = DDSurfDesc.dwWidth;
ScreenY = DDSurfDesc.dwHeight;
ScreenBpp = DDSurfDesc.ddpfPixelFormat.dwRGBBitCount;
// check the color key hardware capabilities
dwTransType = DDBLTFAST_SRCCOLORKEY;
ddcaps.dwSize = sizeof( ddcaps );
// Create surfaces
memset( &ddsd, 0, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
DDSCAPS_FLIP |
DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpFrontBuffer, NULL );
if (ddrval != DD_OK)
{
if (ddrval == DDERR_NOFLIPHW)
return CleanupAndExit(TEXT("******** Display driver doesn't support flipping surfaces. ********"));
return CleanupAndExit(TEXT("CreateSurface FrontBuffer Failed!"));
}
// get a pointer to the back buffer
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
ddrval = lpFrontBuffer->lpVtbl->GetAttachedSurface(
lpFrontBuffer,
&ddscaps,
&lpBackBuffer );
if( ddrval != DD_OK )
return CleanupAndExit(TEXT("GetAttachedDurface Failed!"));
ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
#ifdef DEBUG
if( bHELBlt )
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
#endif
ddsd.dwWidth = 320;
ddsd.dwHeight = 384;
ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpDonut, NULL );
if( ddrval != DD_OK )
return CleanupAndExit(TEXT("CreateSurface lpDonut Failed!"));
ddsd.dwHeight = 128;
ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpPyramid, NULL );
if( ddrval != DD_OK )
return CleanupAndExit(TEXT("CreateSurface lpPyramid Failed!"));
ddsd.dwHeight = 32;
ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpCube, NULL );
if( ddrval != DD_OK )
return CleanupAndExit(TEXT("CreateSurface lpCube Failed!"));
ddsd.dwHeight = 32;
ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpSphere, NULL );
if( ddrval != DD_OK )
return CleanupAndExit(TEXT("CreateSurface lpSphere Failed!"));
// Set the background color fill color
ddsd.dwHeight = 256;
ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpShip, NULL );
if( ddrval != DD_OK )
return CleanupAndExit(TEXT("CreateSurface lpShip Failed!"));
ddsd.dwHeight = 16;
ddrval = lpDD->lpVtbl->CreateSurface( lpDD, &ddsd, &lpNum, NULL );
if( ddrval != DD_OK )
return CleanupAndExit(TEXT("CreateSurface lpNum Failed!"));
if( !RestoreSurfaces() )
return CleanupAndExit(TEXT("RestoreSurfaces Failed!"));
DL.type = OBJ_SHIP;
DL.surf = lpShip;
lastTickCount = GetTickCount();
#ifdef USE_DSOUND
if(bWantSound)
{
InitializeSound();
}
#endif
if(bTest)
{
ProgramState = PS_ACTIVE;
setup_game();
}
else
{
ProgramState = PS_SPLASH;
}
return TRUE;
}
BOOL CleanupAndExit( TCHAR *err)
{
// Note: We're using OutputDebugString here instead of RETAILMSG to allow the user
// to read the error message, even when the sample app is running on a retail
// build of the OS. Not seeing a message in the debugger when the app mysteriously
// fails (as in the case when there is no hardware flipping support for example)
// has led to a lot of confusion.
wsprintf(DebugBuf, TEXT("%s: CleanupAndExit err = %s\n"), cszAppName, err );
OutputDebugString( DebugBuf );
DestroyGame();
return FALSE;
}
void bltSplash( void )
{
HRESULT ddrval;
HBITMAP hbm;
hbm = (HBITMAP)LoadImage( hInst, TEXT("SPLASH"), IMAGE_BITMAP, 0, 0, 0 );
if ( NULL == hbm )
return;
// if the surface is lost, DDCopyBitmap will fail and the surface will
// be restored in FlipScreen.
ddrval = DDCopyBitmap( lpBackBuffer, hbm, 0, 0, 0, 0 );
DeleteObject( hbm );
FlipScreen();
}
#ifdef USE_DSOUND
//
// play a sound, but first set the panning according to where the
// object is on the screen. fake 3D sound.
//
void playPanned(HSNDOBJ hSO, DBLNODE *object)
{
IDirectSoundBuffer *pDSB = SndObjGetFreeBuffer(hSO);
if(!bWantSound)
return; // No sound our Work is done
if (pDSB)
{
switch(ScreenX)
{
case 320:
IDirectSoundBuffer_SetPan(pDSB, (LONG)((20000.0 *
((object->dst.right + object->dst.left) / 2) / 320.0) - 10000.0));
break;
case 640:
IDirectSoundBuffer_SetPan(pDSB, (LONG)((20000.0 *
((object->dst.right + object->dst.left) / 2) / 640.0) - 10000.0));
break;
case 1024:
IDirectSoundBuffer_SetPan(pDSB, (LONG)((20000.0 *
((object->dst.right + object->dst.left) / 2) / 1024.0) - 10000.0));
break;
case 1280:
IDirectSoundBuffer_SetPan(pDSB, (LONG)((20000.0 *
((object->dst.right + object->dst.left) / 2) / 1280.0) - 10000.0));
break;
}
IDirectSoundBuffer_Play(pDSB, 0, 0, 0);
}
}
#endif
void UpdateFrame( void )
{
switch( ProgramState )
{
case PS_SPLASH:
// display the splash screen
bltSplash();
return;
case PS_ACTIVE:
UpdateDisplayList();
CheckForHits();
DrawDisplayList();
if ( isDisplayListEmpty() )
{
#ifdef USE_DSOUND
if(bWantSound)
{
SndObjStop(hsoEngineIdle);
SndObjStop(hsoEngineRev);
}
#endif
bPlayIdle = FALSE;
bPlayRev = FALSE;
lastThrust = lastShield = FALSE;
ProgramState = PS_BEGINREST;
restCount = GetTickCount();
initLevel( ++level );
}
return;
case PS_BEGINREST:
#ifdef USE_DSOUND
if(bWantSound)
{
SndObjPlay(hsoBeginLevel, 0);
}
#endif
ProgramState = PS_REST;
//
// FALLTHRU
//
case PS_REST:
if( ( GetTickCount() - restCount ) > ShowLevelCount )
{
#ifdef USE_DSOUND
if(bWantSound)
{
SndObjPlay(hsoEngineIdle, DSBPLAY_LOOPING);
}
#endif
bPlayIdle = TRUE;
lastTickCount = GetTickCount();
ProgramState = PS_ACTIVE;
}
else
{
DisplayLevel();
}
return;
}
}
void DisplayLevel( void )
{
TCHAR buf[10];
EraseScreen();
buf[0] = 10 + TEXT('0');
buf[1] = 11 + TEXT('0');
buf[2] = 12 + TEXT('0');
buf[3] = 11 + TEXT('0');
buf[4] = 10 + TEXT('0');
buf[5] = TEXT('\0');
bltScore( buf, ScreenX/2-64, ScreenY/2-8 );
buf[0] = level / 100 + TEXT('0');
buf[1] = level / 10 + TEXT('0');
buf[2] = level % 10 + TEXT('0');
buf[3] = TEXT('\0');
bltScore( buf, ScreenX/2+22, ScreenY/2-8 );
FlipScreen();
}
void bltScore( TCHAR *num, int x, int y )
{
TCHAR *c;
RECT src;
int i;
HRESULT ddrval;
for(c=num; *c != TEXT('\0'); c++)
{
while( 1 )
{
i = *c - TEXT('0');
src.left = i*16;
src.top = 0;
src.right = src.left + 16;
src.bottom = src.top + 16;
ddrval = lpBackBuffer->lpVtbl->BltFast( lpBackBuffer, x, y, lpNum, &src, dwTransType );
if( ddrval == DD_OK )
{
break;
}
if( ddrval == DDERR_SURFACELOST )
{
if( !RestoreSurfaces() )
return;
}
if( ddrval != DDERR_WASSTILLDRAWING )
{
return;
}
}
x += 16;
}
}
void CheckForHits( void )
{
LPDBLNODE bullet, target, save;
int frame, x, y, l, t;
BOOL hit;
// update screen rects
target = &DL;
do
{
frame = (DWORD)target->frame;
switch( target->type )
{
case OBJ_DONUT:
target->dst.left = (DWORD)target->posx;
target->dst.top = (DWORD)target->posy;
target->dst.right = target->dst.left + 64;
target->dst.bottom = target->dst.top + 64;
target->src.left = 64 * (frame % 5);
target->src.top = 64 * (frame /5);
target->src.right = target->src.left + 64;
target->src.bottom = target->src.top + 64;
break;
case OBJ_PYRAMID:
target->dst.left = (DWORD)target->posx;
target->dst.top = (DWORD)target->posy;
target->dst.right = target->dst.left + 32;
target->dst.bottom = target->dst.top + 32;
target->src.left = 32 * (frame % 10);
target->src.top = 32 * (frame /10);
target->src.right = target->src.left + 32;
target->src.bottom = target->src.top + 32;
break;
case OBJ_SPHERE:
target->dst.left = (DWORD)target->posx;
target->dst.top = (DWORD)target->posy;
target->dst.right = target->dst.left + 16;
target->dst.bottom = target->dst.top + 16;
target->src.left = 16 * (frame % 20);
target->src.top = 16 * (frame /20);
target->src.right = target->src.left + 16;
target->src.bottom = target->src.top + 16;
break;
case OBJ_CUBE:
target->dst.left = (DWORD)target->posx;
target->dst.top = (DWORD)target->posy;
target->dst.right = target->dst.left + 16;
target->dst.bottom = target->dst.top + 16;
target->src.left = 16 * (frame % 20);
target->src.top = 16 * (frame /20);
target->src.right = target->src.left + 16;
target->src.bottom = target->src.top + 16;
break;
case OBJ_SHIP:
target->dst.left = (DWORD)target->posx;
target->dst.top = (DWORD)target->posy;
target->dst.right = target->dst.left + 32;
target->dst.bottom = target->dst.top + 32;
if( lastShield )
target->src.top = 32 * (frame / 10) + 128;
else
target->src.top = 32 * (frame /10);
target->src.left = 32 * (frame % 10);
target->src.right = target->src.left + 32;
target->src.bottom = target->src.top + 32;
break;
case OBJ_BULLET:
frame = (DWORD)target->frame/20 % 4;
target->dst.left = (DWORD)target->posx;
target->dst.top = (DWORD)target->posy;
target->dst.right = target->dst.left + 3;
target->dst.bottom = target->dst.top + 3;
target->src.left = BULLET_X + frame*4;
target->src.top = BULLET_Y;
target->src.right = target->src.left + 3;
target->src.bottom = target->src.top + 3;
break;
}
target = target->next;
}
while( target != &DL );
bullet=&DL;
do
{
hit = FALSE;
if((bullet->type != OBJ_BULLET) && (bullet != &DL))
{
bullet = bullet->next;
continue;
}
x = (bullet->dst.left + bullet->dst.right) / 2;
y = (bullet->dst.top + bullet->dst.bottom) / 2;
for(target=DL.next; target != &DL; target = target->next)
{
if( ( target->type != OBJ_DONUT ) &&
( target->type != OBJ_PYRAMID ) &&
( target->type != OBJ_SPHERE ) &&
( target->type != OBJ_CUBE ) )
continue;
if( (x >= target->dst.left) &&
(x < target->dst.right) &&
(y >= target->dst.top) &&
(y < target->dst.bottom) )
{
if ((bullet != &DL) || !lastShield)
{
// the bullet hit the target
switch( target->type )
{
case OBJ_DONUT:
#ifdef USE_DSOUND
if(bWantSound)
{
playPanned(hsoDonutExplode, target);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -