📄 ch28.htm
字号:
<P><FONT
COLOR="#0066FF"><TT>};</TT></FONT>
<H4><FONT COLOR="#000077">Listing 28.8. The header for the SpriteTest1 program.</FONT></H4>
<PRE><FONT COLOR="#0066FF">
///////////////////////////////////////
// Main.h
// Project: SpriteTest1
// Copyright (c)
1997 by Charlie Calvert
//
#ifndef MainH
#define MainH
#include <vcl\Classes.hpp>
#include <vcl\Controls.hpp>
#include <vcl\StdCtrls.hpp>
#include <vcl\Forms.hpp>
#include <vcl\Menus.hpp>
#include
"Mercury2.h"
class TForm1 : public TForm
{
__published:
THermes *Hermes1;
TSpriteScene *SpriteScene1;
TSprite *Sprite1;
TSprite *Sprite2;
TMainMenu *MainMenu1;
TMenuItem *Run1;
void __fastcall
SpriteScene1SetupSurfaces(TObject *Sender);
void __fastcall Run1Click(TObject *Sender);
void __fastcall FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift);
private:
public:
__fastcall TForm1(TComponent* Owner);
};
extern
TForm1 *Form1;</FONT></PRE>
<P><FONT COLOR="#0066FF"><TT>#endif</TT></FONT>
<H4><FONT COLOR="#000077">Listing 28.9. The main form for the TestSprite1 program.</FONT></H4>
<PRE><FONT COLOR="#0066FF">
///////////////////////////////////////
//
Main.cpp
// Project: SpriteTest1
// Copyright (c) 1997 by Charlie Calvert
//
#include <vcl\vcl.h>
#pragma hdrstop
#include "Main.h"
#pragma link "Mercury2"
#pragma resource "*.dfm"
TForm1 *Form1;
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
void __fastcall TForm1::SpriteScene1SetupSurfaces(TObject *Sender)
{
SpriteScene1->SpriteList->Add(Sprite1);
SpriteScene1->SpriteList->Add(Sprite2);
}
void
__fastcall TForm1::Run1Click(TObject *Sender)
{
Hermes1->Run();
}
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key,
TShiftState Shift)
{
if ((Shift.Contains(ssAlt)) && (Key == `X'))
Close();
}
</FONT></PRE>
<P>Don't forget that when using this program, you will probably have to explicitly
add <TT>Creatures1.pas</TT> to your project:</P>
<PRE><FONT COLOR="#0066FF">
//--------------------------------------------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop
//--------------------------------------------------------------------------
USEFORM("Main.cpp", Form1);
USERES("SpriteTest1.res");
USEUNIT("..\..\Units\creatures1.pas");
//--------------------------------------------------------------------------
WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
try
{
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);
Application->Run();
}
catch (Exception &exception)
{
Application->ShowException(&exception);
}
return 0;
}
</FONT></PRE>
<P>Figure 28.3 shows the TestSpriteScene program in action. In this program, I make
no
attempt to animate the sprites. To do so, you can merely change the x- and y-coordinates
at which they are shown and then wait for the screen to be updated automatically
by the timer.</P>
<P><A HREF="28ebu03.jpg" tppabs="http://pbs.mcp.com/ebooks/0672310228/art/28/28ebu03.jpg">Figure 28.3.</A><B> </B><I>The
TestSpriteScene program
shows a background bitmap with two sprites placed on it.</I></P>
<P>To work with the <TT>TSpriteScene</TT> object, you should drop a <TT>THermes</TT>,
a <TT>TSpriteScene</TT>, and one or more <TT>TSprite</TT> objects on a form.
Connect
the <TT>THermes</TT> object to the sprite scene. Pick a background bitmap and a transparent
color for the sprite scene. In the sample program, I use <TT>BackGrd2.bmp</TT> for
the background and <TT>254</TT> for the transparent color.</P>
<P>For the bitmaps that ship in the <TT>Chap28/Media</TT> directory, I assume that
the background color is the <TT>254</TT> element in the palette of the background
bitmap. This color is a robin's egg blue, which means that this particular shade
of
blue cannot be used in any of the bitmaps except for areas that you want to be
transparent. Don't forget that if a particular RGB pattern such as <TT>255, 0, 255</TT>
is designated as the transparent color, you can change any one value to get a nearby
color that is not going to appear as transparent. For example, you can choose <TT>255,
1, 255</TT>, which is virtually identical in shade to <TT>255, 0, 255</TT>, but it
will not be transparent to the user and can be shown in your bitmaps.</P>
<P>Connect the <TT>TSprite</TT> objects to a bitmap. I connect the first sprite to
<TT>Queen2.bmp</TT> and the second sprite to <TT>Monk2.bmp</TT>.
<BLOCKQUOTE>
<DL>
<DD>
<HR>
<FONT COLOR="#000077"><B>NOTE: </B></FONT>These graphical figures were
created by
Kari Marcussen and, like all the artwork in this book, are copyrighted and cannot
be used in your own programs. You can, of course, use the art in the "privacy
of your own home," but you cannot distribute programs of any kind,
even free
programs, that contain this art.
<HR>
</DL>
</BLOCKQUOTE>
<P>The <TT>XPos</TT> and <TT>YPos</TT> positions for the first sprite are 100x200,
whereas the second sprite is 400x200. You don't have to be concerned with the size
of the
sprite itself, as the components will calculate the size automatically at
runtime.</P>
<P>You need to have some way of telling the <TT>TSpriteScene</TT> object about the
sprites that it owns. I use a simple event handler of <TT>TSpriteScene</TT>
called
<TT>OnSetupSurface</TT> for this purpose:</P>
<PRE><FONT COLOR="#0066FF">
void __fastcall TForm1::SpriteScene1SetupSurfaces(TObject *Sender)
{
SpriteScene1->SpriteList->Add(Sprite1);
SpriteScene1->SpriteList->Add(Sprite2);
}
</FONT></PRE>
<P><TT>SpriteList</TT> is a simple <TT>TList</TT> descendant. Keeping all the child
sprites in a list allows for easy deallocation of memory:</P>
<PRE><FONT COLOR="#0066FF">
void __fastcall TSpriteScene::DestroyObjects(void)
{
if(FSpriteList != NULL)
{
for(int i = 0; i < FSpriteList->Count; i++)
((TSprite*)(FSpriteList->Items[i]))->Surface->Release();
FSpriteList->Clear();
}
}
</FONT></PRE>
<P>This kind of routine is important
because you might want to switch between numerous
<TT>TScene</TT> descendants during the course of a program. In other words, your
game may have more than one scene in it. I will explain this process in more depth
later in the chapter. However, the
quick overview is that you can simply write code
that looks like this:</P>
<PRE><FONT COLOR="#0066FF">
Hermes1->Scene = Scene1;
... // Code omitted here.
Hermes1->Scene = Scene2;
</FONT></PRE>
<P>In this case, the program starts by showing
<TT>Scene1</TT> and then at some later
point switches to <TT>Scene2</TT>. When you switch scenes, the <TT>DestroyObjects</TT>
method for the previous scene is called, thereby deallocating all the memory associated
with background and sprite bitmaps.
At the same time, new memory is allocated for
the bitmaps used in <TT>Scene2</TT>.</P>
<P>The <TT>SpriteList</TT> also is important when you switch away from a program
in Exclusive mode and then press Alt+Tab to move back to it. At those times, the
following routine is called:</P>
<PRE><FONT COLOR="#0066FF">
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
}
</FONT></PRE>
<PRE><FONT COLOR="#0066FF"> }
</FONT></PRE>
<P>This routine iterates through all the bitmaps in the <TT>SpriteList</TT> and restores
each surface. This process occurs so quickly that the
user simply sees the scene
being restored all at once and is not aware that a list of objects is being re-created.</P>
<P>You can now run the program, trying it first in windowed mode, where the output
will appear a bit muddy because the transparent
color probably won't work correctly.
After you're sure everything is running correctly, you can try the program in Exclusive
mode. When in Exclusive mode, you can press Alt+Tab to move away from the main game
window and view some other program such as
the Windows Explorer. You can then press
Alt+Tab to go back to the game window. This capability is one of the key features
of DirectX.</P>
<P>If you're concerned about the <TT>TransparentColor</TT> not working right in windowed
mode, you can try using
a common color such as black for your <TT>TransparentColor</TT>.
It might work correctly, or you can play with the Windows palette system to make
sure the right palette is selected when your program appears in a window. For now,
however, my graphics
engine assumes that you want to run your program in Exclusive
mode, and support for windowed mode is available only so that you can easily debug
your programs. After all, DirectX doesn't really provide many advantages over GDI
in windowed mode. The
whole point of this process is to switch into Exclusive mode
where you can get the following:
<UL>
<LI>High performance
<P>
<LI>Control over the size of the palette
<P>
<LI>Control over the dimensions of the screen
</UL>
<P>When I say that
DirectX offers high performance, I mean that in Exclusive mode
you can write directly to the video buffer, thereby obtaining the same kind of performance
you would expect from a DOS program. The actual degree of performance improvement
you get is
dependent on the amount of RAM on your video card and on the bus between
RAM and your video card. The ideal situation is to have a video card with enough
RAM in it to hold all the bitmaps used by any one scene. Therefore, 2MB of memory
on your video
card is pretty much a minimum, and a strong argument can be made in
favor of having 4MB. The code that ships
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -