Game Programming – Part 02
typedef TScene inherited;
private:
Classes::TList* FSpriteList;
protected:
__fastcall virtual ~TSpriteScene(void);
virtual void __fastcall SetupSurfaces(System::TObject* Sender);
public:
__fastcall virtual TSpriteScene(Classes::TComponent* AOwner);
virtual void __fastcall DestroyObjects(void);
void __fastcall AddSprite(TSprite* Sprite);
virtual void __fastcall DrawScene(void);
virtual long __fastcall RestoreSurfaces(void);
__property Classes::TList* SpriteList = {read=FSpriteList, write=FSpriteList,nodefault};
__published:
__property TransparentColor;
};
////////////////////////////////////////
// TSceneEditor ////////////////////////
////////////////////////////////////////
class TSceneEditor: public TComponentEditor
{
protected:
virtual __fastcall void Edit(void);
public:
virtual __fastcall TSceneEditor(TComponent *AOwner, TFormDesigner *Designer)
: TComponentEditor(AOwner, Designer) {}
};
//-- var, const, procedure --------------------------------------------------
#define Timer1 (Byte)(1)
extern void __fastcall Register(void);
}/* namespace Mercury1 */
#if !defined(NO_IMPLICIT_NAMESPACE_USE)
using namespace Mercury2;
#endif
//-- end unit ---------------------------------------------------------------- #endif
// Mercury2 Listing
28.14. The main source file for the Mercury2
module.
///////////////////////////////////////
// Mercury2.cpp
// DirectX Graphics
// Copyright (c) 1997 by Charlie Calvert
// Thanks to John Thomas, Stuart Fullmar and Jeff Cottingham
///////////////////////////////////////
#include <vcl\vcl.h>
#pragma hdrstop
#include "Mercury2.h"
#include "errors1.h"
#include "SceneEditor1.h"
#pragma link "Errors1.obj"
#pragma link "SceneEditor1.obj"
/*{ ------------------------ }
{ --- THermes ------------ }
{ ------------------------ } */
THermes *AHermes;
void Timer2Timer(HWND H, UINT Msg, UINT Event, DWORD Time)
{
if (AHermes->Active)
AHermes->Flip();
}
namespace Mercury2
{
// Slightly modified version of code from DDUtils.cpp
HRESULT DDCopyBitmap(IDirectDrawSurface *pdds,
HBITMAP hbm, int x, int y, int dx, int dy)
{
HDC hdcImage;
HDC hdc;
BITMAP bm;
DDSURFACEDESC ddsd;
HRESULT hr;
if (hbm == NULL || pdds == NULL)
return E_FAIL;
//
// make sure this surface is restored.
//
pdds->Restore();
//
// select bitmap into a memoryDC so we can use it.
//
hdcImage = CreateCompatibleDC(NULL);
if (!hdcImage)
OutputDebugString("createcompatible dc failed\n");
SelectObject(hdcImage, hbm);
//
// get size of the bitmap
//
GetObject(hbm, sizeof(bm), &bm); // get size of bitmap
dx = dx == 0 ? bm.bmWidth : dx; // use the passed size, unless zero
dy = dy == 0 ? bm.bmHeight : dy;
//
// get size of surface.
//
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
pdds->GetSurfaceDesc(&ddsd);
if ((hr = pdds->GetDC(&hdc)) == DD_OK)
{
StretchBlt(hdc, 0, 0, ddsd.dwWidth, ddsd.dwHeight, hdcImage, x, y, dx, dy, SRCCOPY);
pdds->ReleaseDC(hdc);
}
DeleteDC(hdcImage);
return hr;
}
// Slightly modified version of code from DDUtils.cpp
void DDReloadBitmapLib(HANDLE Lib, IDirectDrawSurface *Surface,
const AnsiString BitmapName)
{
HBITMAP Bitmap;
if (Lib)
Bitmap = LoadImage(Lib, BitmapName.c_str(),
IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
else
Bitmap = LoadImage(GetModuleHandle(NULL), BitmapName.c_str(),
IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
if (!Bitmap)
Bitmap = LoadImage(0, BitmapName.c_str(), IMAGE_BITMAP,
0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
if (!Bitmap)
throw Exception("Unable to load bitmap %s",
OPENARRAY(TVarRec, (BitmapName)));
DDCopyBitmap(Surface, Bitmap, 0, 0, 0, 0);
DeleteObject(Bitmap);
}
// Slightly modified version of code from DDUtils.cpp
IDirectDrawSurface *DDCreateSurface(IDirectDraw *DD, DWORD Width, DWORD Height,
bool SysMem, bool Trans, DWORD dwColorKey)
{
DDSURFACEDESC SurfaceDesc;
HRESULT hr;
DDCOLORKEY ColorKey;
IDirectDrawSurface *Surface;
// fill in surface desc
memset(&SurfaceDesc, 0, sizeof(DDSURFACEDESC));
SurfaceDesc.dwSize = sizeof(SurfaceDesc);
SurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
SurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
SurfaceDesc.dwHeight = Height;
SurfaceDesc.dwWidth = Width;
hr = DD->CreateSurface(&SurfaceDesc, &Surface, NULL);
// set the color key for this bitmap
if (hr == DD_OK)
{
if (Trans)
{
ColorKey.dwColorSpaceLowValue = dwColorKey;
ColorKey.dwColorSpaceHighValue = dwColorKey;
Surface->SetColorKey(DDCKEY_SRCBLT, &ColorKey);
}
}
else
throw EDDError("CreateSurface Failed in DDCreateSurface");
return Surface;
} // DDCreateSurface
IDirectDrawClipper *CreateClipper(IDirectDraw *DD, HWND Handle)
{
HRESULT hr;
IDirectDrawClipper *lpClipper;
hr = DD->CreateClipper(0, &lpClipper, NULL);
if (hr != DD_OK)
{
throw EDDError("No Clipper");
}
hr = lpClipper->SetHWnd(0, Handle);
if (hr != DD_OK)
{
throw EDDError("Can''t set clipper window handle");
}
return lpClipper;
}
}
__fastcall THermes::THermes(TComponent* AOwner)
:TComponent(AOwner)
{
FHandle = ((TWinControl *)(AOwner))->Handle;
FFirstTime = true;
}// THermes
void __fastcall THermes::EndExclusive()
{
FDirectDraw->FlipToGDISurface();
if (FExclusive)
FDirectDraw->SetCooperativeLevel(FHandle, DDSCL_NORMAL);
}// EndExclusive
void __fastcall THermes::ErrorEvent(String S)
{
FActive = false;
EndExclusive();
throw EDDError(S);
}// ErrorEvent
void __fastcall THermes::Run()
{
InitObjects();
Flip();
}// Run
void __fastcall THermes::DDTest(long hr, System::AnsiString S)
{
if (!Windows::Succeeded(hr))
throw EDDError("DDTest Error: %s $%x %s",
OPENARRAY(TVarRec, (S, int(hr), AnsiString(GetOleError(hr)))));
}// DDTest
/////////////////////////////////////////////////
// Create the primary surface
/////////////////////////////////////////////////
bool __fastcall THermes::CreatePrimary(void)
{
DDSURFACEDESC SurfaceDesc;
HResult hr;
bool Result = true;
memset(&SurfaceDesc, 0, sizeof(SurfaceDesc));
SurfaceDesc.dwSize = sizeof(SurfaceDesc);
if (!FExclusive){
SurfaceDesc.dwFlags = DDSD_CAPS;
SurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
}
else{
SurfaceDesc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
SurfaceDesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
DDSCAPS_FLIP |
DDSCAPS_COMPLEX;
SurfaceDesc.dwBackBufferCount = 1;
};
hr = FDirectDraw->CreateSurface(&SurfaceDesc, &FPrimarySurface, NULL);
if (hr != DD_OK)
throw EDDError("THermes.CreatePrimary: %d %s",
OPENARRAY(TVarRec, (int(hr), GetOleError(hr))));
else
return Result;
}// CreatePrimary
void __fastcall THermes::SetScene(TScene *Scene)
{
if (Scene)
Scene->DestroyObjects();
FScene = Scene;
}// SetScene
bool __fastcall THermes::SetUpBack(void)
{
bool Result = false;
HResult hr;
DDSCAPS DDSCaps;
if (!FExclusive)
{
FBackSurface =
Mercury2::DDCreateSurface(FDirectDraw, 640, 480, false, false, 0);
if (FBackSurface == NULL)
throw EDDError("Can''t set up back surface");
FClipper = Mercury2::CreateClipper(FDirectDraw, FHandle);
hr = FPrimarySurface->SetClipper(FClipper);
if( hr != DD_OK )
throw EDDError("Can''t attach clipper to front buffer");
}
else
{
memset(&DDSCaps, 0, sizeof(DDSCaps));
DDSCaps.dwCaps = DDSCAPS_BACKBUFFER;
hr = FPrimarySurface->GetAttachedSurface(&DDSCaps, &FBackSurface);
if (hr != DD_OK)
throw EDDError("TSpeedDraw.SetUpBack: %d %s",
OPENARRAY(TVarRec, (int(hr), GetOleError(hr))));
else
Result = true;
};
return Result;
}// SetUpBack
void __fastcall THermes::InitBaseObjects()
{
DWORD Flags;
HResult hr;
DDTest(DirectDrawCreate(NULL, &FDirectDraw, NULL), "InitObjects1");
if (!FExclusive)
Flags = DDSCL_NORMAL;
else
Flags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
DDTest(FDirectDraw->SetCooperativeLevel(FHandle, Flags),"SetCooperativeLevel");
if (FExclusive)
{
hr = FDirectDraw->SetDisplayMode(640, 480, 8);
if(hr != DD_OK)
throw EDDError("TSpeedDraw.InitObjects: %d %s",
OPENARRAY(TVarRec, (int(hr), GetOleError(hr))));
};
CreatePrimary();
SetUpBack();
if (FCreatureList != NULL) FCreatureList->ReadFiles();
}// InitBaseObjects
/* Here are the steps in the initialization:
Create DirectDraw Object
SetCooperativeLevel
if Exclusive then SetDisplayMode
CreatePrimary
SetupBack
Create the work surface
Set Active to true */
void __stdcall THermes::InitObjects(void)
{
AHermes = this;
if (FFirstTime)
{
InitBaseObjects();
FFirstTime = false;
};
if ((Scene) && (Scene->FBackgroundBitmap != ""))
Scene->SetupSurfaces(this);
if (FUseTimer)
SetTimer(FHandle, Timer1, FTimerInterval, (FARPROC)Timer2Timer);
FActive = true;
}// InitObjects
void __fastcall THermes::DrawBitmaps()
{
if (Scene) Scene->DrawScene();
}
bool __fastcall THermes::MakeItSo(HResult DDResult)
{
bool Result;
switch(DDResult)
{
case DD_OK:
Result = true;
break;
case DDERR_SURFACELOST:
Result = (RestoreSurfaces() == DD_OK);
break;
default:
Result = DDResult != DDERR_WASSTILLDRAWING;
break;
};
return Result;
} // MakeItSo
long __fastcall THermes::RestoreSurfaces()
{
HRESULT Result;
Result = FPrimarySurface->Restore();
if ((Result == DD_OK) && (Scene))
Result = Scene->RestoreSurfaces();
return Result;
}// RestoreSurfaces
void __fastcall THermes::Flip(void)
{
RECT R1, R;
FTimerOdd = !FTimerOdd;
if (!FActive)
return;
if (!FExclusive)
{
try
{
DrawBitmaps();
GetWindowRect(FHandle, &R);
R1 = Rect(0, 0, 640, 480);
DDTest(FPrimarySurface->Blt(&R, FBackSurface, &R1, 0, NULL), "Flip");
}
catch(Exception &E)
{
ErrorEvent("Flipping");
};
}
else
{
try
{
if (FActive)
{
do
{
Application->ProcessMessages();
} while(!MakeItSo(FPrimarySurface->Flip(NULL, DDFLIP_WAIT)));
DrawBitmaps();
}
}
catch(...)
{
ErrorEvent("Flipping");
}
}
}// Flip
///////////////////////////////////////
// TDraw //////////////////////////////
///////////////////////////////////////
__fastcall TDraw::TDraw(Classes::TComponent* AOwner)
: TComponent(AOwner)
{
}
__fastcall TDraw::~TDraw(void)
{
if (FLib != NULL)
FreeLibrary(FLib);
}
bool __fastcall TDraw::CreateDDSurface(IDirectDrawSurface* &DDS,
System::AnsiString BitmapName, bool UsePalette)
{
bool Result;
DDCOLORKEY ColorKey;
HRESULT hr;
HANDLE Dib;
if (UsePalette)
{
FPalette = LoadPalette(FLib, BitmapName.c_str());
if (!FPalette)
throw EDDError("LoadPalette Failed");
FHermes->FPrimarySurface->SetPalette(FPalette);
}
Dib = GetDib(FLib, BitmapName);
DDS = CreateSurface(Dib);
if (!DDS)
throw EDDError("CreateSurface Failed");
ColorKey.dwColorSpaceLowValue = FTransparentColor;
ColorKey.dwColorSpaceHighValue = FTransparentColor;
hr = DDS->SetColorKey(DDCKEY_SRCBLT, &ColorKey);
if (hr != DD_OK)
throw EDDError("TSpeedDraw.CreateDDSurface: %d %s",
OPENARRAY(TVarRec, (int(hr), GetOleError(hr))));
else
Result = True;
return Result;
}
IDirectDrawSurface* __fastcall TDraw::CreateSurface(HANDLE Bitmap)
{
DDSURFACEDESC SurfaceDesc;
Windows::TBitmap BM;
IDirectDrawSurface *Result;
if (Bitmap == 0)
throw Exception("No Bitmap in CreateSurface");
try
{
GetObject(Bitmap, sizeof(BM), &BM);
memset(&SurfaceDesc, 0, sizeof(SurfaceDesc));
SurfaceDesc.dwSize = sizeof(SurfaceDesc);
SurfaceDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
SurfaceDesc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
SurfaceDesc.dwWidth = BM.bmWidth;
SurfaceDesc.dwHeight = BM.bmHeight;
if (FHermes->FDirectDraw->CreateSurface(&SurfaceDesc, &Result, NULL) != DD_OK)
throw Exception("CreateSurface failed");
DDCopyBitmap(Result, Bitmap, 0, 0, 0, 0);
}
catch(Exception &E)
{
FHermes->ErrorEvent("TSpeedDraw.CreateSurface: " + E.Message);
}
return Result;
}
HANDLE __fastcall TDraw::GetDib(HANDLE Instance, System::AnsiString S)
{
HANDLE Result;
UINT Flags;
if (Instance != 0)
Flags = LR_CREATEDIBSECTION;
else
Flags = LR_LOADFROMFILE | LR_CREATEDIBSECTION;
Result = LoadImage((HANDLE)Instance, S.c_str(), IMAGE_BITMAP,
0, 0, Flags);
if (Result == 0)
FHermes->ErrorEvent("TSpeedDraw.GetDib: Could not load bitmap");
return Result;
}
IDirectDrawPalette* __fastcall TDraw::LoadPalette(HANDLE Instance,
const System::AnsiString BitmapName)
{
IDirectDrawPalette* ddpal;
int i;
int n;
int fh;
HRSRC h;
LPBITMAPINFO BitmapInfo;
PALETTEENTRY ape[256];
RGBQUAD * RGBQuad;
//
// build a 332 palette as the default.
//
for (i=0; i<256; i++)
{
ape[i].peRed = (BYTE)(((i >> 5) & 0x07) * 255 / 7);
ape[i].peGreen = (BYTE)(((i >> 2) & 0x07) * 255 / 7);
ape[i].peBlue = (BYTE)(((i >> 0) & 0x03) * 255 / 3);
ape[i].peFlags = (BYTE)0;
}
if (BitmapName == "")
FHermes->ErrorEvent("No bitmapname in LoadPalette");
//
// get a pointer to the bitmap resource.
//
if (Instance)
{
h = FindResource(Instance, BitmapName.c_str(), RT_BITMAP);
if (h)
{
BitmapInfo = (LPBITMAPINFO)LockResource(LoadResource(Instance, h));
if (!BitmapInfo)
throw EDDError("No LockResouce: " + this->ClassName());
RGBQuad = (RGBQUAD*)BitmapInfo->bmiColors;
if (BitmapInfo == NULL || BitmapInfo->bmiHeader.biSize <sizeof(BITMAPINFOHEADER))
n = 0;
else if (BitmapInfo->bmiHeader.biBitCount > 8)
n = 0;
else if (BitmapInfo->bmiHeader.biClrUsed == 0)
n = 1 << BitmapInfo->bmiHeader.biBitCount;
else
n = BitmapInfo->bmiHeader.biClrUsed;
//
// a DIB color table has its colors stored BGR not RGB
// so flip them around.
//
for(i=0; i<n; i++ )
{
ape[i].peRed = RGBQuad[i].rgbRed;
ape[i].peGreen = RGBQuad[i].rgbGreen;
ape[i].peBlue = RGBQuad[i].rgbBlue;
ape[i].peFlags = 0;
}
}
}
else
{
fh = _lopen(BitmapName.c_str(), OF_READ);
if (fh != -1)
{
BITMAPFILEHEADER bf;
BITMAPINFOHEADER bi;
_lread(fh, &bf, sizeof(bf));
_lread(fh, &bi, sizeof(bi));
_lread(fh, ape, sizeof(ape));
_lclose(fh);
if (bi.biSize != sizeof(BITMAPINFOHEADER))
n = 0;
else if (bi.biBitCount > 8)
n = 0;
else if (bi.biClrUsed == 0)
n = 1 << bi.biBitCount;
else
n = bi.biClrUsed;
//
// a DIB color table has its colors stored BGR not RGB
// so flip them around.
//
for(i=0; i<n; i++ )
{
BYTE r = ape[i].peRed;
ape[i].peRed = ape[i].peBlue;
ape[i].peBlue = r;
}
}
}
FHermes->FDirectDraw->CreatePalette(DDPCAPS_8BIT, ape, &ddpal, NULL);
return ddpal;
}
void __fastcall TDraw::WriteXY(int X, int Y, System::AnsiString S)
{
HDC DC;
FHermes->BackSurface->GetDC(&DC);
SetBkMode(DC, TRANSPARENT);
TextOut(DC, X, Y, S.c_str(), S.Length());
FHermes->BackSurface->ReleaseDC(DC);
}
// ------------------------
// -- TScene --------------
// ------------------------
__fastcall TScene::TScene(TComponent *AOwner) : TDraw(AOwner)
{
ShowBitmap = true;
}
void __fastcall TScene::DestroyObjects(void)
{
if(FWorkSurface != NULL)
FWorkSurface->Release();
FWorkSurface = NULL;
}
long _fastcall TScene::RestoreSurfaces(void)
{
long Result;
Result = FWorkSurface->Restore();
if(Result == DD_OK)
DDReloadBitmapLib(FLib, FWorkSurface, FBackgroundBitmap);
return(Result);
}
void __fastcall TScene::SetupSurfaces(System::TObject *Sender)
{
AnsiString ErrStr = "TSpeedDraw.SetupWorkSurface: No Surface Desc %d %s";
DDSURFACEDESC SurfaceDesc;
HRESULT hr;
FHermes = dynamic_cast <THermes *>(Sender);
if(FDLLName != "")
{
if(!FLib)
FLib = LoadLibrary(FDLLName.c_str());
if(int(FLib) < 32)
throw EDDError("No Library");
}
if(!CreateDDSurface(FWorkSurface, FBackgroundBitmap, True))
throw EDDError("TSpeedDraw.SetupWorkSurface: No WorkSurface: " +
FBackgroundBitmap);
else
{
SurfaceDesc.dwSize = sizeof(SurfaceDesc);
hr = FWorkSurface->GetSurfaceDesc(&SurfaceDesc);
if(hr != DD_OK)
throw EDDError(ErrStr, OPENARRAY(TVarRec, (int(hr), GetOleError(hr))));
FBackRect = Rect(0, 0, SurfaceDesc.dwWidth, SurfaceDesc.dwHeight);
}
if(FOnSetupSurfaces)
FOnSetupSurfaces(this);
}
void _fastcall TScene::DrawScene()
{
AnsiString ErrStr = "TSpeedDraw.BackGroundBlits: $%x \r %s \r %s";
HRESULT hr;
HDC DC;
HBRUSH OldBrush, Brush;
if (FBlankScene)
{
FHermes->BackSurface->GetDC(&DC); // Don't step through!!
Brush = CreateSolidBrush(FBackColor);
OldBrush = SelectObject(DC, Brush);
Rectangle(DC, 0, 0, 640, 480);
SelectObject(DC, OldBrush);
DeleteObject(Brush);
FHermes->BackSurface->ReleaseDC(DC);
}
if (FShowBitmap)
{
hr = AHermes->BackSurface->BltFast(FBackOrigin.x, FBackOrigin.y,
FWorkSurface, &FBackRect,
DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY);
if (!Windows::Succeeded(hr))
throw EDDError(ErrStr, OPENARRAY(TVarRec,
(int(hr), GetOleError(hr), "Check BackRect, BackOrigin???")));
}
if (FOnDrawScene)
FOnDrawScene(this);
}
///////////////////////////////////////
// THermesTiler ///////////////////////
///////////////////////////////////////
__fastcall THermesTiler::THermesTiler(Classes::TComponent* AOwner)
:TScene(AOwner)
{
FBitmapWidth = 32;
FBitmapHeight = 32;
FMaxMapRows = 12;
FMaxMapCols = 20;
}
__fastcall THermesTiler::~THermesTiler(void)
{
DestroyObjects();
}
void __fastcall THermesTiler::DrawScene(void)
{
TScene::DrawScene();
int i, j, k;
TSpecialRect SpR;
if (FTileSurface == NULL)
return;
k = 1;
for (j = 1; j <= FMaxMapRows; j++)
for (i = 1; i <= FMaxMapCols; i++)
{
SpR = GetRect(i + FHermes->CreatureList->MapCol, j + FHermes->CreatureList->MapRow);
FHermes->BackSurface->BltFast(FBitmapWidth * (k - 1),
FBitmapHeight * (j - 1), FTileSurface, &SpR.R1, DDBLTFAST_SRCCOLORKEY);
if (SpR.IsCreature) // There's a character or building here
FHermes->BackSurface->BltFast(FBitmapWidth * (k - 1),
FBitmapHeight * (j - 1), FTileSurface, &SpR.R2, DDBLTFAST_SRCCOLORKEY);
if ((i % 20) == 0)
k = 1;
else
k++;
}
}
void __fastcall THermesTiler::SetupSurfaces(System::TObject* Sender)
{
TScene::SetupSurfaces(Sender);
if (FTileMap != "")
if (!CreateDDSurface(FTileSurface, FTileMap, True))
throw Exception("THermesTiler.InitObjects");
}
void __fastcall THermesTiler::DestroyObjects(void)
{
if (FTileMap != "")
if (FTileSurface != NULL)
FTileSurface->Release();
FTileSurface = NULL;
}
Windows::TRect __fastcall THermesTiler::MapTypeToTileRect(int MapType)
{
int X, Y = 0;
if ((MapType > 19) && (MapType < 41))
{
Y = FBitmapHeight;
X = (MapType - 21) * FBitmapWidth;
}
else if (MapType > 39)
{
Y = 64;
X = (MapType - 41) * FBitmapWidth;
}
else
{
X = MapType * FBitmapWidth;
}
return Rect(X, Y, X + FBitmapWidth, FBitmapHeight + Y);
}
long __fastcall THermesTiler::RestoreSurfaces(void)
{
long Result = TScene::RestoreSurfaces();
if (Result == DD_OK)
{
Result = FTileSurface->Restore();
if (Result == DD_OK)
if (FTileMap != "")
DDReloadBitmapLib(FLib, FTileSurface, FTileMap);
}
return Result;
}
///////////////////////////////////////
// THermesChart ///////////////////////
///////////////////////////////////////
bool __fastcall THermesChart::CheckHeroPos(Creatures1::TCreatureList* HeroList,
int Col, int Row)
{
int NewPosType;
TPoint NewPos;
bool MoveOk = True;
if (OnHeroMove != NULL)
{
NewPos.x = FHero->TrueCol + Col;
NewPos.y = FHero->TrueRow + Row;
NewPosType = HeroList->GetMapType(NewPos.x, NewPos.y);
OnHeroMove(this, NewPos, NewPosType, MoveOk);
}
return MoveOk;
}
Windows::TRect __fastcall THermesChart::MapTypeToCreature(int Col, int Row)
{
TCreature *Creature = FHermes->CreatureList->CreatureFromLocation(Col, Row);
if (Creature->TypeStr == "Hero")
return MapTypeToTileRect(3);
else
return MapTypeToTileRect(StrToInt(Creature->ID));
}
TSpecialRect __fastcall THermesChart::GetRect(int Col, int Row)
{
Byte MapType;
TSpecialRect Result;
MapType = FHermes->CreatureList->Map[Col][Row];
if ((FHermes->FTimerOdd == True) && (MapType == 1 /*mtWater*/))
MapType = 4; // mtWater2;
if (BitOn(7, MapType))
{
Result.IsCreature = True;
SetBit(7, 0, MapType);
Result.R1 = MapTypeToTileRect(MapType);
Result.R2 = MapTypeToCreature(Col, Row);
}
else
{
Result.IsCreature = False;
Result.R1 = MapTypeToTileRect(MapType);
}
return Result;
}
bool __fastcall THermesChart::MoveGrid(int Col, int Row, bool CallFlip)
{
TPoint P;
if (CheckHeroPos(FHermes->CreatureList, Col, Row))
{
P.x = FHermes->CreatureList->MapCol + Col;
P.y = FHermes->CreatureList->MapRow + Row;
if ((P.x < 0) ||
(P.x > (FHermes->CreatureList->MaxCols - FMaxMapCols)) ||
(P.y < 0) ||
(P.y > (FHermes->CreatureList->MaxRows - FMaxMapRows)))
return False;
FHermes->CreatureList->MapCol = P.x;
FHermes->CreatureList->MapRow = P.y;
FHermes->CreatureList->MoveCreature(FHero, Col, Row);
FHermes->Flip();
return True;
}
return False;
}
__fastcall THermesChart::~THermesChart(void)
{
}
void __fastcall THermesChart::MoveHero(int NewCol, int NewRow)
{
TPoint P;
if (!CheckHeroPos(FHermes->CreatureList, NewCol, NewRow))
return;
P.x = FHero->ScreenCol + NewCol;
P.y = FHero->ScreenRow + NewRow;
if ((P.x <= 0) || (P.x > (FMaxMapCols)) ||
(P.y <= 1) || (P.y > FMaxMapRows))
return;
FHero->ScreenCol = P.x;
FHero->ScreenRow = P.y;
FHermes->CreatureList->MoveCreature(FHero, NewCol, NewRow);
FHermes->Flip();
}
void __fastcall THermesChart::SetupSurfaces(System::TObject* Sender)
{
THermesTiler::SetupSurfaces(Sender);
if (FHermes->CreatureList == NULL)
throw EDDError("CreatureList cannot be blank.");
FHeroActive = True;
FHero = FHermes->CreatureList->CreatureFromName("Hero");
}
void __fastcall THermesChart::Move(int Value)
{
if (Value == VK_INSERT)
HeroActive = !HeroActive;
else if (HeroActive)
switch (Value)
{
case VK_RIGHT: MoveHero(1, 0); break;
case VK_LEFT: MoveHero(-1, 0); break;
case VK_DOWN: MoveHero(0, 1); break;
case VK_UP: MoveHero(0, -1); break;
}
else
switch(Value)
{
case VK_RIGHT: MoveGrid(1, 0, False); break;
case VK_LEFT: MoveGrid(-1, 0, False); break;
case VK_DOWN: MoveGrid(0, 1, False); break;
case VK_UP: MoveGrid(0, -1, False); break;
}
}
/* ------------------------ */
/* -- TSprite ------------- */
/* ------------------------ */
bool __fastcall TSprite::IsHit(int X, int Y)
{
X = X - XPos;
Y = Y - YPos;
if ((X >= 0) && (Y >= 0) && (X <= Rect.right) && (Y <= Rect.bottom))
return true;
else
return false;
}
/* ------------------------ */
/* -- TSpriteScene -------- */
/* ------------------------ */
__fastcall TSpriteScene::TSpriteScene(TComponent *AOwner)
: TScene(AOwner)
{
FSpriteList = new TList();
}
__fastcall TSpriteScene::~TSpriteScene()
{
DestroyObjects();
delete FSpriteList;
}
void __fastcall TSpriteScene::DestroyObjects(void)
{
if(FSpriteList != NULL)
{
for(int i = 0; i < FSpriteList->Count; i++)
((TSprite*)(FSpriteList->Items[i]))->Surface->Release();
FSpriteList->Clear();
}
}
void __fastcall TSpriteScene::AddSprite(TSprite *Sprite)
{
SpriteList->Add(Sprite);
}
void __fastcall TSpriteScene::DrawScene(void)
{
const char ErrStr[] = "TSpriteScene.DrawScene";
HResult hr;
TSprite *Sprite;
TScene::DrawScene();
for(int i = 0; i < FSpriteList->Count; i++)
{
Sprite = (TSprite *)FSpriteList->Items[i];
hr = FHermes->BackSurface->BltFast(Sprite->XPos, Sprite->YPos,
Sprite->Surface, &Sprite->FRect, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY);
if(!Windows::Succeeded(hr))
throw(EDDError(ErrStr, OPENARRAY(TVarRec, (int(hr), GetOleError(hr),
"Check BackRect, BackOrigin???"))));
}
}
long __fastcall TSpriteScene::RestoreSurfaces(void)
{
TSprite *Sprite;
HRESULT Result;
Result = TScene::RestoreSurfaces();
if(Result == DD_OK)
{
for(int i = 0; i < FSpriteList->Count; i++)
{
Sprite = (TSprite *)FSpriteList->Items[i];
Result = Sprite->Surface->Restore();
if(Result == DD_OK)
DDReloadBitmapLib(FLib, Sprite->Surface, Sprite->Bitmap);
else
break; // Exit on error
}
}
return((long)Result);
}
void __fastcall TSpriteScene::SetupSurfaces(TObject *Sender)
{
IDirectDrawSurface *Surface;
TSprite *Sprite;
DDSURFACEDESC SurfaceDesc;
HRESULT hr;
TScene::SetupSurfaces(Sender);
if(SpriteList == NULL)
return;
for(int i = 0; i < SpriteList->Count; i++)
{
Sprite = (TSprite *)SpriteList->Items[i];
if(!CreateDDSurface(Surface, Sprite->Bitmap, False))
throw EDDError("Could not create surface");
SurfaceDesc.dwSize = sizeof(SurfaceDesc);
hr = Surface->GetSurfaceDesc(&SurfaceDesc);
if(hr == DD_OK)
Sprite->Rect = Rect(0, 0, SurfaceDesc.dwWidth, SurfaceDesc.dwHeight);
else
throw EDDError("No SurfaceDesc");
Sprite->Surface = Surface;
}
}
void __fastcall TSceneEditor::Edit(void)
{
RunSceneEditorDlg((TScene *)Component);
}
namespace Mercury2
{
void __fastcall Register()
{
TComponentClass classes[5] = {__classid(THermes), __classid(TScene),
__classid(THermesChart), __classid(TSpriteScene), __classid(TSprite)};
RegisterComponents("Unleash", classes, 4);
RegisterComponentEditor(__classid(TScene), __classid(TSceneEditor));
}
} Summary
In this chapter, you learned how to create a simple graphics engine that gives you access to DirectX. In particular, you learned how to do the following:
In the next chapter, I add a simple
game engine to this graphics engine and then give a simple example of how to
use these tools to create the elements of a strategy game.
VMS Desenvolvimentos
Diversas Dicas, Apostilas, Arquivos Fontes, Tutoriais,
Vídeo Aula, Download de Arquivos Relacionado a
Programação em C++ Builder. |
|