17 October, 2006

Screenshot and Simple Timings

It's pretty late, and I'm getting tired, so I'll keep this short. I have enough implemented to get some simple applications made and start comparing timings. There is a nice C++ library out there using Direct3D 8 for rendering 2D graphics called HGE (Haaf's Game Engine). It's a nice engine. Simple. And I thought I would use it as a comparison for how fast mine is running in Dolphin.

If you were to download HGE, it comes with a tutorials folder that contains 8 sample programs. One of those tutorials (#7) is called "Thousand of Hares". I decided to duplicate 90% of the functionality in that demo (I don't have any blending support yet in my engine), and see how it ran against the C++ version. Please note that the framerates provided are on my laptop, and should be much improved on a desktop.


The idea is simple: display randomly moving, scaling, and rotating "zazakas". Using the up and down arrow keys, you can adjust the number being rendered every frame between 100 and 2000. That's it. And to make a long story short, I was very impressed with the results (HGE framerate on the left vs. my framerate on the right):

100 sprites - 277 FPS vs. 251 FPS
500 sprites - 105 FPS vs. 97 FPS
1000 sprites - 63 FPS vs. 54 FPS
2000 sprites - 33 FPS vs. 27 FPS

A couple things to note: starting around 1000 sprites, HGE began to "skip" (every 100 frames or so the program would stutter). My version didn't skip at all (even after very, very prolonged running). This was actually very surprising to me, since I expected Dolphin to skip eventually due to a garbage collection. This never happened.

Also, it should be noted that I have a lot more optimizations left to do. I'm currently drawing every single sprite to the screen individually (this is very bad for performance in Direct3D) as opposed to batching them up and rendering them all in one shot (which HGE already does).

If I wasn't already feeling very good about how well the engine was going, I definitely would be now. I still have a lot of work to do (I was planning on having the above sample available for download, but there are still enough show-stopper bugs making that not possible), but the above sample was put together in about 10 minutes once I had the time to do it.

Cheers!

09 October, 2006

Game Engine Progress...

I've been working on my (2D) game engine now in Dolphin for a little over a month, and I must say that I'm quite impressed with how quickly it is progressing. The iteration time on code is extremely fast, and I've been able to create some very fast demos. The most frustrating work was just typing in the COM wrappers for Direct3D, DirectInput, and XACT. However, once that work was done, the rest has been pretty smooth sailing.

(e := GameEngine current)
createGameView: GameView fullscreen: false;
run.

That's about as simple as it gets right now. The GameEngine object is a singleton, which wraps up Direct3D and has two other objects inside it that make up the majority of the engine: GameControllers and GameAudioEngine (DirectInput and XACT respectively).

The GameEngine has a stack of GameScene objects, each of which can respond to varying messages:

#advance:
#render
#enter
#exit

Those are the basics. The #enter and #exit messages are sent to the scene when it is pushed onto and popped off of the scene stack (used for loading/creating objects and releasing them). The #advance: message is sent once per main loop iteration with the delta time (in seconds) since the last advance. This is where various controller inputs and game logic would progress. And, whenever needed, the #render message is sent.

It is extremely easy to test out new scenes and try out different code. What's even better, all of this is doable while the game is running! I can't stress this enough. A great example of this was when I wanted to try out a simple pause screen. I had the main menu scene setup, and every time the spacebar was pressed I wanted to enter the pause scene. So, while the game was running, I created a PauseScene object:

PauseScene>>enter

font := GameFont new.
font load: 'Arial' height: 60.

PauseScene>>render
font
draw: 'PAUSED'
center: (GameEngine current view viewportExtent) / 2.


PauseScene>>advance: deltaTime
(GameEngine current keyboard keyPressed: DIK_SPACE)
ifTrue: [
GameEngine current exitScene].

Once this was in place, all that was needed was to modify the #advance: message in the main menu object so that it was possible to get to the paused scene:

MainMenuScene>>advance: deltaTime
(GameEngine current keyboard keyDown: DIK_SPACE)
ifTrue:
[
GameEngine current enterScene: PauseScene new].

Right-click/accept, and switch back to the game and hit the spacebar. And now we're at the save game screen. I can't stress enough just how much of a time saver this will be once I actually start working on the game itself.

Also, for those that might be interested, framerate has not been an issue at all. This was something that I was worried about at the beginning of this little endeavour, too. Right now, I can blit massive numbers of quads to the screen and keep a consistent framerate well over 300 on my Thinkpad laptop. The same code on my workstation at work runs in excess of 3000 FPS. Dolphin might be interpreted bytecode, but I have to hand it to Andy and Blair, it's fast!

Something else that I've found to be an absolute dream in Smalltalk is resumeable exceptions. I'm hardly a "code it right the first time" programmer - especially when working in a new language. I don't know how many times I've had a bug, an exception is thrown, and I've fixed the code right then and there, and/or modified a variable's value and continued running the game. And I also need to thank Andy and Blair for all those little touches in Dolphin that can make all the difference (for example, if a COM object returns an HRESULT error code, the debugger will give you the text error in addition to the cryptic error code).

I can't impress enough on programmers (outside the Smalltalk community) just how wonderful it is to be able to inspect anything at runtime. Make the GameEngine a singleton object was easily the best decision made so far. While running, I can just open up a worksheet and type:

GameEngine current

And then hit Ctrl+I to inspect it. Instantly seeing what scene is running, what state everything is in. This isn't remotely the same as variable watch in C++ (which was really all I thought it was initially).

Hopefully in the next post I'll be able to throw together some screenshots and perhaps a downloadable demo. Stay tuned!