28 December, 2006

Asteroids Screenshot

I've had a few emails wondering on the progress of the little Asteroids game. To be honest, there isn't much to see at the moment; there's only a couple scenes: the main menu with instructions on how to play and the game scene where all the action takes place. A hearty thanks goes out to Ari Feldman for creating his SpriteLib graphics. I would hate to think just how bad the visuals of this clone would be without his work.

There's audio including some background music from a great site: Shockwave-Sound. I'm not very good at taking screenshots (at least not interesting ones), and there's a lot I'd like to add to this clone. Actually, each day it turns out to be less and less of a clone as I change the input scheme. In fact, I actually enjoy playing it while programming it - always the mark of something good to come. :-)

If there's one thing that this prototype of a game has done, it's shown the shortcomings of the engine I need to work on, where the engine shines (the actual game itself is very, very little code), and how much of a dream Smalltalk is to work with. I don't think - outside of work - I've even touched C/C++ in about 3 months. I think that, in and of itself, is a testament to just how good and complete Dolphin Smalltalk is.

Next I'll be adding a particle system to the mix and some simple particle emitters. That should add a whole extra layer of visuals to the engine very easily. As for the game, I need a nice starfield moving in the background, some shields still, and currently there's no way to die. The ship doesn't actually collide with the asteroids yet.

I'll post more screenshots later as more features are added. I'm hoping soon to actually have something downloadable for people to try on their machines.

22 December, 2006

Adding More Functionality

Work has been occupying most of my time of late, but over Christmas I've had some time off and been able to add more support for a few things.

At the end of the day, I very much want to not make use of Microsoft's D3DX library. While it is useful, Microsoft reenabled "DLL hell" with it, meaning that any user of an end-game would need a specific version of the DLL installed on their machine. In order to get rid of this library, I need to implement fonts and textures myself.

For bitmapped fonts, I'm making use of the Bitmap Font Generator. It's very good, and free. Just download it, create some bitmapped fonts with it and away you go. The code is almost exactly the same, and in many ways it's easier. To parse the .FNT file, I'm currently using Vassili's regular expression parser (ported by Chris Uppal). This has a few known issues with Dolphin, but I'm not using it for anything but simple expressions. In the end, I'll actually write my own parser, but for now, it works great.

Some nice benefits to having my own bitmapped font system is being able to calculate width, height, kerning, and render text in a meriad of ways (left, right, centered, boxed, etc), all very easily. It will also be significantly faster once I get batched rendering of quads in place, as right now each letter is rendering a single quad at a time. Inefficient, but very little text is ever actually rendered in a 2D game.

I haven't yet worked out my own texture loading and surface creation, but it's on my list of things to do. Microsoft's D3DX library supports an entire host of image formats. Most likely whatever I do will only support BMP and TGA files, but that's plenty. Perhaps PNG as well, but I don't want to rely on a 3rd party library for image loading.

XACT is a dream on the Xbox 360, but the PC version is behind the 360. This and other frustrations make it less than ideal for my game engine. So, I'm stripping it out. In its place I've been using the BASS Audio Library. It's a simple, and very well written audio library. It's shareware, and I'm sure many users of my engine won't want to purchase it, but it is free to use in non-commercial applications.

As for my previous post on the resource management, I've been putting together my prototype game for the engine (an Asteroids clone) and it was obvious very quickly that the current method of resource management would not scale at all; I knew that from the start, but I was hoping it would scale a little, but now it's apparent that it doesn't.

Tejon had a good idea, though, that I built on a little. I think there are a few kinks to work out still, but overall it's pretty good. In the GameResource class is a class instance variable that holds all the resources that have been loaded of that type. There is a class method #get: that will return the resource if it's already been loaded, or load it fresh and add it to the lookup table for that class.

It's definitely a lot more scaleable (as it's very much like every other resource system in existence). The kinks that need worked through? Currently each resource type's load method is #load:usingLocator:. I'd rather not pass the #get: method a FileLocator as well. My current solution is to set a locator in the GameEngine that all resources will use. So far I like this a lot. But what about resources that will be loaded from packfiles or memory? In theory I could create a subclass of FileLocator that searches packfiles for a resource (at least this is my current thinking). I need to think on this some more.

More to come soon...

26 November, 2006

Trying To Think Small

Progress on the game engine continues slowly. One of the reasons it is progressing a little slower than it otherwise would normally is that I'm trying things differently - I'm trying to do them the Smalltalk way. And, in the process, I'm attempting to assertain whether or not the Smalltalk way is the better way.

The best example of this (so far) is the resource system. A resource would be anything that is read from disk or memory that requires a Direct3D interface object. The two most obvious kinds of resources are textures and fonts. Later this system would also include sound banks, wave banks, render targets, and more.

The initial pass was nothing more than the brute-force C++ method: there's a font object, a texture object, a scene creates them on initialization, frees them when done, and uses them in between. This works fine, until one realizes that multiple scenes probably will want access to the same resources.

Now, for a typical program, having two different objects load the same object individually probably wouldn't be so bad. However, in this case, it's very bad. For a texture, we'd be using double the VRAM (if two scenes each loaded it). Excusing memory, there's an even bigger problem with doing this. State changes in Direct3D are a performance killer. Each one basically cause the GPU to finish doing everything currently sent to it, halt while it changes the state, and then you can continue to send instructions to it. And switching textures is a type of state change. So, having the same texture loaded in memory multiple times can cause unnecessary state changes.

In C++, this would be fixed by simply making textures global in some way. They would either be global variables, or there would be a texture system that manages all the loaded textures. Both are equally good solutions. However, the former method in Smalltalk (using global variables) isn't quite so elegant. So, for my first pass at a more Smalltalk-ish implementation of a resource manager, I decided to do just that, create a GameResourceManager object, that would handle the management of all loaded textures and fonts.

This worked, but it had some definite problems. The first problem is, of course, how are other objects going to gain access to these resources? Well, Smalltalk "tackles" the global variable problems through hash tables. And this certainly is a viable solution. So, trying a LookupTable in the resource manager worked, but not very well. Why not? Primarily because the resource manager didn't know how to load the resources. Each resource could load itself just fine, but then needed to be added to the resource manager. I didn't want some end-programmer using my library to have to "know" and add their resources to a manager. Equally frustrating was that each user of a resource had to accept the fact that it may not be loaded yet. This required lots of code that looked like this to be strewn about the game:

bg := GameEngine current resources at: 'mytexture'
ifAbsentPut: (TextureResource fromFile: 'media/bg.tga').

Obviously every single time I want to get a texture, I don't want to have to know not only it's name, but how to load it as well. Yuck. So, then I toyed with the idea of the resource manager knowing how to load the textures and automatically adding them to the LookupTable. This definitely wasn't the road I wanted to go down. What happens in the future? Should the resource manager know how to load every kind of resource the game ever needs? No, that would be horrible.

Over the next day, I thought about it some more. At one point I decided to stop and ask myself, "okay - what does Smalltalk do best?" The answer to that is obvious: objects. So, how could I use objects to solve this problem? Does Dolphin have anything that's a similar problem I could look at for help? As I started thinking more, it came to me that there was a similar problem (and one that I'd been making use of this whole time): dynamic libraries.

So, the proposed solution was this: what if there was no resource manager (or, what if Smalltalk itself was the resource manager for me)? What if every resource was really just a subclass? Since classes are objects in Smalltalk, I could make each texture, each font, each sound, etc, an actual class in my game - a singleton of sorts, that other objects could just get, and each would know how to load itself if needed.

The first step was to create the GameResource object. This would be a simple implementation of a resource singleton, and have instance methods for loading, unloading, and restoring (when Direct3D loses the device context). Next, I needed to make my font and texture objects just a subclass of GameResource. These would be slightly more specialized, actually knowing how to load and unload themselves, and how to render, etc. All that was needed now was to make a few class methods "describe" the resource. For a font, this was the #face, #height, #bold, and #italic methods. For a texture, this was the #fileName. And for future resources, there would be equally appropriate methods.

Now to test the idea and see how well it is in practice (note: the above changes took all of 20 minutes - another win for the Dolphin interface and Smalltalk in general).

In the little sample game that I'm working with, I just subclassed TextureResource and created BackgroundTexture. Overwrote the #fileName class method to return the correct filename, and that's it. Now anytime I want that texture for use, it's just:

bg := BackgroundTexture current.

If it isn't ready, it's automatically read from disk and created for me. If that's already been done, then I get a reference to it. What's even better, is that all the resources for the entire game can be listed, restored, loaded, or unloaded in a single line of code. For example, when the GameView is closed and DirectX shutdown, we need to release all the resources:

GameResource allSubclasses do: [:each | each unload].

Now, for a full-blown, giant game this does have drawbacks.

This method can unpredictably access the disk, and loading all the resources would hit the disk a lot, as opposed to reading a single, giant, compressed file that contained all our resources, uncompressing into memory, and then loading from there. However, I see that as trivial for two reasons: I'm not making giant games with this engine, and if I wanted to, I'm sure I could easily create a #loadFromMemory method and a #loadFromDisk method to specify how I would like the resources loaded.

Also, if a game were to have a lot of resources, there would be an awful lot of classes in the hierarchy tree. I still haven't decided if this is a big problem or not. Certainly for a very large game with thousands of resources, it would definitely be a problem. But I see this engine being used for games with an order of magnitude or two fewer resources.

On the flip side, one very nice advantage is being able to inspect every single resource in the game. I can check to see if it's loaded, how many objects are using it, etc. Later on, I could even add DirectX debug views so I could actually view the resources outside of the game while it's running. And that is very appealing.

There are still a few changes I'm considering, but they are pretty minor. Overall, I like the direction this is going, and progress continues forward. Next up will be character maps and hopefully a screenshot of the game running.

However, I'm curious to know if I'm walking on a slippery slope. Perhaps there are some known pitfalls to my current approach that someone can point out to me? Or perhaps there is a better way of creating the resource manager that I didn't see. Let me know what you think!

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.


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;

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:


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:


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

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)
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!

03 September, 2006

Introduction to Talking

My first exposure to Smalltalk was around 2001. It was using Smalltalk MT, and I created a simple raytracer with it (that was the typical pet project I did with all new languages at the time). It turned out reasonably well. I didn't really understand much about Smalltalk at the time other than the syntax and how to move around the environment. Once I did enough to feel that I had a "reasonable understanding" of the language, I put it down and moved onto other things....

Over the next 5 years I would periodically check out Squeak. Each time, Smalltalk looked a little more foreign than I remembered it being. Squeak would never last more than 10 minutes on my machine. This was mostly due to it being extremely different from the OS I was working on (Windows XP), and it being very unintuitive to the newcomer (if it truly is "great for kids," then I must be getting old). The other major change in my life was that I went from being an desktop/embedded programmer to a console game developer (believe me, this is a completely different way of thinking when it comes to programming). Subsequently, I never really gave Smalltalk more than a passing glance.

Very recently (mid-2006), I was quite bored, and decided to do a Google search for Smalltalk once more. Perhaps something new was around (funny that something as simple as a programming language could hold such an allure that I'd keep coming back to it). This is when I found an updated version to a very slick looking implementation of Smalltalk: Dolphin X6. They recently published a free (community) edition and so I downloaded and gave it a try.

First, let me say that the boys (Andy Bower and Blair McGlashan) at Object Arts did an absolutely fantastic job with their presentation of the language. All implementations I'd seen to-date were either very foreign (Squeak) or extremely "old" (ObjectStudio, MT). This not only looked and felt modern, it actually had all the features a professional programmer expects from a development environment: syntax highlighting, view composing, source control (built in), tutorials, and more, all presented very elegantly. Andy and Blair really took their time and got it right!

Alright, so I was sold on the presentation. However, over my many (10) years of programming experience (mostly C/C++, but also Forth and lots of assembly) I had slowly come to completely distrust object-oriented programming. OOP is a tool. It can help in some domains, but can also cause more problems than it solves in many others. All too often, some co-workers and I at find ourselves chuckling and commenting, "I've C++'ed myself into a corner again." Ah, the allure of OOP is great.

Now, before I get comments from OOP fanatics and C++ gurus telling me how we do it "wrong" let me asure you that we don't. In the world of game development, the twin evils are Design and Fun. Both of which cause the requirements of the game to change radically from day to day (and sometimes from hour to hour). Because of this, development needs to be fast, fast, fast. This idea was best expressed by Chris Uppal in a comp.lang.smalltalk post:

> Make it work.
> Make it right.
> Make it fast.

Chris disagreed with this when he posted it, but that's okay. In games, making it work is most important during early development. It's all about prototyping. The designers and artists need to see what it's going to be like before deciding to keep it, throw it away, or do something different. With a heavy OO philosophy, a programmer will spend far too long working out the perfect class hierarchy just to get a triangle drawing on the screen. And God forbid when the designer sees it, he decides that he'd like stars instead. Suddenly half the code is now useless (and the other half needs restructuring to be useful).

Alright. So what's this got to do with Smalltalk? Well, I was skeptical. I was still curious, but I really didn't want to spend my free time I had relearning a language that was all about something I was almost entirely against.

But then it occured to me - what if the phylosophy (OOP) wasn't the problem, but the implementation (language) was? Admittedly, almost all OO languages in existance are derivatives of C++. But, Smalltalk is very different! Also, Smalltalk was the first (well, second, but who's counting?) OO language. Certainly any inherent problems should have been solved by now. Perhaps there was a gem here, and I just wasn't giving it the complete attention it deserved.

I decided to write a complete program in Smalltalk. And, just to give myself an added challenge, it had to be a game: a complete DirectX driven game with sound, graphics, controls, etc. To be honest, I didn't care about the result, what I cared about was how it got there. Could it interface well with DirectX? Was there an advantage to the Smalltalk environment (Forth and Lisp both wowed me with their interactive developing)? And most importantly, would "true" OOP be a benefit or a hinderance?

For the first 2-3 weeks of playing with Dolphin, I was clearly unimpressed. The community was great (everyone at comp.lang.smalltalk[.dolphin] was extremely helpful). When learning Forth and Lisp, the biggest hurdle was getting around the community to ask questions. On comp.lang.lisp, try asking "how do I get the type of a variable?" and you'll get a barrage of snide replies reminding you just how naive you are, because "variables don't have types; values have types!" Of course, this has nothing to do with the evaluation of a language, but certainly made the experience a more pleasurable one.

That said, I was still unimpressed. In all the toy problems I'd try to learn the language in more depth, I kept coming back to my original concerns. I just couldn't see anything that would be helpful. In fact, I had an ah-ha! moment when I discovered how to actually define global constants in Smalltalk. Something as simple as a constant needs to be a string object, in a pool object, in a singleton Smalltalk object. And that felt like some serious over-engineering to me. But, I decided to chalk this up to the fact that I still hadn't done anything of any reasonable size and still didn't understand the language all that well.

And about one week later something happened. I don't exactly recall how it happened (reading a post or just trying something out), but I learned something that wasn't in any Smalltalk tutorials on the web (note to Smalltalk tutorial writers: this needs to be there):

Everything in Smalltalk is an object!

Okay. That's in every tutorial to Smalltalk on the web. However, those tutorials don't show you just how far the rabbit hole goes! Let me explain. Coming from C++, a class has a constructor: the place where data is initialized. Likewise, in Smalltalk, objects have an instance method called #initialize. However, in C++, one uses the new operator to create an instance of the class, and it (in turn) calls the constructor for me. That isn't the case in Smalltalk. In Smalltalk, when you define your class, there is suddenly a new object created in the image. That object is the "class object" for that class. The class object is a kind of singleton where class data and methods are.

So? How is this different from static data and static methods in a C++ class? That's what I initially wondered as well. And, let me tell you, there is a world of difference. But, let me reiterate again this key point: when you use the class name in your source code, you are sending a message to an object! In Smalltalk, if I type:

ShellView new

This calls the #new method of the class object for the ShellView class. ShellView is not a keyword or a type. It's an actual object, and you are sending it a message. That message is resposible for the creation of an instance of the ShellView class, and returning it. This is very important. Because each class has a class object, this gives Smalltalk some unprecedented reflection capabilities. And I'm only just beginning to scratch the surface of them. As an example, open up the Worksheet; we're going to try a few things:

ShellView allSubclasses

There is a list of all the class objects which constitute that classes which derive from ShellView.

ShellView allInstances

There are all the instances of the ShellView class that are currently in existance right now.

Pretty slick. And that's just 2 of the many functions that class objects have available to them. Experienced programmers should already be drooling. This alone provides some impressive power. But, let's show a practicle use for someone still a little confused or not yet convinced.

In my game engine, I have certain functionality that is required in a subclass of ShellView that I need the window to have. So, I created GameView, a subclass of ShellView. However, I don't want the end-programmer to actually use GameView. Instead, I want them to subclass it and override some important functions that describe the behavior of the window, etc. At the same time, for various reasons, I don't want the end-programmer to actually create and instance of this view (for DirectX reasons I'd like only one at a time to ever exist).

So, what I was able to do was in my GameEngine object, I created the method #createGameWindow:fullscreen:. This method's first parameter is a class object, which is of the GameView subclass you want to use. But this poses a problem: how can I be sure that the class object passed is a subclass of GameView? After all, I need to make sure that it will work. However, this is a trivial problem to solve:

self assert: [class inheritsFrom: GameView].

Done. The C++ solution would have been to have the end-programmer create the view and pass it in. However, the Smalltalk method has an added bonus: I don't have to create the window right then! I can just hold onto the class object and create it later when I really want to. Or, I might never create it (in the event that some other initialization code failed).

Alright. You get it. The reflective power of Smalltalk is awesome. This was my "the sleeper has awaken" moment in Smalltalk. And consequently, one hour later I purchased a copy of Dolphin X6 Professional. But, this still didn't answer the question of whether OOP would hinder more than help in the development of a game, and subsequently, whether the OOP problem was one of phylosophy or implementation.

At this point, I think it's fair to say that if I hadn't purchased Dolphin, I have thought the OOP was more of a hinder than a help. And this isn't because it's true. It's because the professional version of Dolphin comes with some very nice features, most importantly the Idea Space. Up until this point, I had painstakingly been putting together Direct3D and DirectInput wrappers for Dolphin. Not only did I have no less than 7 Dolphin windows open at once at any given time, but no matter how friendly the UI was, jumping around between objects, copying, pasting, package browser, etc, was becoming a monstrous headache. The Idea Space made that headache go away with a single click. To anyone on the edge of purchasing Dolphin, just know now, the added features in the Pro version are well worth the purchase price.

Back on point. One of the major reasons someone can "C++ themselves into a corner" is that if their class hierarchy is wrong (and it always is). Rearchitecting can be a major hassle. And if you discover the problem(s) well into development, you may just be stuck with them. Likewise, whole companies have succum to the "rewrite it right" bug (summary: in rewriting, you lose a lot of fixes). So, does Smalltalk suffer from this as well?

Honestly, I don't know. Going into this, I would have felt very comfortable saying "yes." But there have been a few things happen that are making me wonder.

As part of my "make it work" step, the first thing I wanted to do was get a 2D texture on the screen. Without going into morbid details, this required a specific vertex format (one of many) with a RHW vector component, texture coordinates, diffuse color, etc. Once I got the texture rendering, it was now time to implement the other vertex formats. However, in a perfect world, the old format would be a subclass of one of these new ones. Behold, all I need to do is drag the old class onto the new one, it's now subclassed. I rename it to a more appropriate name, and Dolphin opens a new window showing me every place in code that referenced the old name so I can change them promptly.

Later, in further development of the game engine, I have no less than 5 times changed hierarchies and inserted new objects to simplify the current (working) ones. These changes have taken minutes (not hours as it would have been in C++). I found that the "make it right" step wasn't so clearly a distinct step from "make it work" any more. Once the code was working, I was immediately able to make it right.

From past experience programming GameBoy Advance games in Forth, I know that interactive development is a monumental win for any programmer. I've already been able to have my game engine up and running, and change the render loop on the fly and see updates without ever stopping execution. And while the engine is running, I can inspect it at any time and modify any data within it, all without bringing down the program. While this has nothing to do with OOP, it certainly is a testament to Smalltalk (and to a great implementation).

I'm only at the beginning of the road. I'll be posting more thoughts and findings as I continue down it. But I'm feeling very good, and I look forward to finding what else Smalltalk has lurking under the hood for me.

Jeff M.

P.S. A hearty thanks to everyone at comp.lang.smalltalk[.dolphin] for taking the time to answer my questions, answer them thoroughly, and without the typical "why would you want to do that?!" usenet response. :-)