Latest news
For latest news on this project, please visit http://www.danpeverill.com/. Feel free to
e-mail me at dan@danpeverill.com with
any questions or comments that you may have.
Introduction
I made this project with a single goal in mind; to create a
reusable Managed DirectX class library that can be used as a foundation for
basic 2D games. I hope that I have succeeded. As a fellow game hobbyist, I
present the
GameUtil
class library to you, so you too can benefit
from its code. You can use it in any way you so desire; start your own 2D game,
extend and/or alter the code for your own needs, or just browse the source code
for learning purposes.
For your convenience and as a mini-tutorial, I've included a demo project
that shows how easy it is to get a basic 2D game engine built, using the
GameUtil
class library.
Requirements
Aside from
.NET
1.0/1.1 (which you should have already), you'll need to have the latest
version of
Managed
DirectX SDK (DirectX 9.0 SDK Update Summer 2003 as of this writing). Yes,
even the demo project requires it.
Features
DDGameSurface
This class can be used as your game surface, which can be attached to any
.NET control. It's been made flexible to allow both window (whether it be a
Form
or Control
) and pseudo full screen modes. It
handles everything for you, including the backbuffer work and restoring lost
surfaces.
Creating and displaying a DDGameSurface
couldn't be any simpler;
DDGameSurface gameSurface = new DDGameSurface(control);
gameSurface.Clear(Color.White);
gameSurface.DrawText(0, 0, "Hello!", false);
gameSurface.Display();
gameSurface.Dispose();
DDGraphic
The DDGraphic
class is derived from the Surface
class and provides a much more game friendly functionality, which includes
setting frames, frame sizes, and retrieving frame areas to draw. This is perfect
for animation. But don't worry, you aren't required to actually set any of these
details if your graphic doesn't have any frames.
Here's an extension of the above example, which shows how to create and
display a DDGameGraphic
;
DDGraphic playerGraphic = new DDGraphic("player.bmp",
new SurfaceDescription(), gameSurface);
playerGraphic.SetTransparency(0x00111111);
playerGraphic.FrameSize = new Size(32, 32);
if (gameSurface.CanDraw) {
gameSurface.Clear(Color.White);
gameSurface.DrawTransparent(0, 0, playerGraphic,
playerGraphic.GetFrameArea(0));
}
gameSurface.Display();
playerGraphic.Dispose();
DDGameGraphics
Normally you wouldn't create a DDGraphic
directly, instead
you'll probably want this class handle all that dirty work. The
DDGameGraphics
class acts as a lookup table for your game graphics,
which you can change on the fly with some simple XML editing skills. This way,
you can load all of your game graphics (or graphics for a particular map) with a
simple object instantiation. Another thing that this class provides is
flexibility. No longer will you need to hardcore all of those nasty constants to
where your graphics are located, instead you can use the
DDGameGraphics
class which loads them for you, using information
provided by an XML document. And yes, there is support for embedded graphics.
Here's a taste, further expanding the code above;
<GameGraphcs>
<graphic key="player" path="Namespace.player.bmp"
frameWidth="32" frameHeight="32" transColor="00111111"
embedded="true"/>
<graphic key="enemy" path="Namespace.enemy.bmp"
frameWidth="32" frameHeight="32" transColor="00111111"
embedded="true"/>
</GameGraphics>
// Game code...
DDGameGraphics graphics = new DDGameGraphics("graphics.xml", gameSurface);
DDGraphic playerGraphic = graphics["player"];
DDGraphic enemyGraphic = graphics["enemy"];
// Draw graphics.
// No need to dispose our DDGraphics, DDGameGraphics does that for us.
graphics.Dispose();
DIMouse
The DIMouse
class may seem a bit odd to work with at first. This
is because a DIMouse
object will only update its internal state
when the Update()
method is called. Everything else however, is a
breeze to understand and use. The DIMouse
class encapsulates pretty
much everything you'd expect to get from a mouse, including cursor coordinates,
button clicks (even wheel clicks), and wheel movement. Unlike a
DDGameSurface
however, a DIMouse
must be created for a
Form
.
Here's a quick example;
DIMouse mouse = new DIMouse(form);
mouse.Update();
if (mouse.LeftClick) {
Console.Writeline("Left click at coordinates: " + mouse.Location);
}
mouse.Dispose();
DIKeyboard
DIKeyboard
works identically to the way DIMouse
does, except that it has a different interface for accessing keyboard
information.
DIKeyboard
in action:
DIKeyboard keyboard = new DIKeyboard(form);
if (keyboard[Key.A]) {
Console.Writeline("The A key is pressed!");
}
keyboard.Dispose();
QPTimer
What game would be complete without some sort of high performance timer? The
QPTimer
class encapsulates the Query Performance Counter and
Frequency for you, so all you have to do is work with its simplistic interface.
And don't worry, the ticks per second is a floating point number. As a side
note, there isn't a property that returns the ticks per millisecond, but that's
easy enough to solve on your own - just multiply the TicksPerSecond
property by 1000.
A game loop example showing off the QPTimer
:
QPTimer timer = new QPTimer();
timer.Start(QPTimer.Counter);
while (gameRunning) {
timer.Record();
Console.Writeline("FPS: " + 1.0F/timer.TicksPerSecond);
timer.Start(timer.RecordTime);
}
GameUtil
Demo
Just giving you a class library without
actually showing how it's used to create a game engine would be quite pointless.
So I've gone ahead and created a demo which shows how to put most of the
GameUtil
class library's features to work. Heck, if you really
wanted to, you could use the demo as a template for creating your own 2D game.
At the very least, it'd make a good tutorial on how to get started.
I would like to point out a note or two; The FPS shown in the demo are slower
then what you'd expect in an actual game, simply because the demo engine is
doing some reflection work and also updating .NET controls at the same time (I
was more interested in showing features than making it efficient). Despite this,
the demo can draw about 2,500+ graphics and still get a steady ~30 FPS (my
computer is an 800mhz Athlon, with 250mb of PC133 RAM and a Geforce 2 MX, so
your mileage may vary).
Closing Comments
Thanks for reading, and I hope you find this class library useful.