There is currently very little documentation for the Unstdio engine. Eventually there will be documentation explaining the class hierarchy. For now, hopefully these tutorial snippets showing how a few things are done will be enticing enough and give an idea for how things work.
Tutorial 1 - Hello, world!
No documentation section would be complete without some sort of "Hello, world!" tutorial. This tutorial is designed to show how easy it is to get something that runs right away. After installing the Unstdio game engine package, open up a Workspace and type the following:
(GameEngine initialize)
createGameView: 800 @ 600 fullscreen: false;
run: GameScene new.
Once evaluated, you should see an empty (black) window appear. That's it. You've just created your first OpenGL viewport with Unstdio. In the background, it's actually running the engine's main loop: polling input devices, processing audio, advancing game logic, and rendering the scene. Just close the window or press ESC when you are done.
Tutorial 2 - Harnessing Smalltalk
For the next tutorial, while you'll get introduced to more of the engine, I'm going to do it in a way that will show newcomers to Smalltalk what makes this language so great - truly interactive development. Let's start by evaluating the code from tutorial 1 again. We should now have our empty game view up and running.
Now, open up a Class Browser and find the GameScene class. This is the parent class to all scene objects. In order to make a custom game, we need a custom scene. So, let's subclass it and make a new scene class called "TestScene".
Once you've created the new scene class, override the #enter: method. In the source code block, enter the following code:
enter: prevScene
GameEngine current presenter caption: 'My First Scene Object!'
Save to compile it, now let's open go back to our Workspace, and enter the following code to be evaluated:
GameEngine current scene: TestScene new.
Evaluate it and see what happens. The game window's caption should have changed. While your game was running, you successfully created a new scene object, overrode a method, and then told the game to enter your scene.
But, we're not quite done yet. There's still nothing all that interesting happening from within our scene object. Let's go back to the Class Browser and override the #render method. Since we don't have any textures or fonts loaded yet (for a later tutorial), let's just throw down some simple OpenGL code.
render
(OpenGLLibrary default)
glBegin: GL_LINES;
glVertex2d: 100 y: 100;
glVertex2d: 200 y: 200;
glEnd
Once you are done entering it. Save it to compile it and watch. There should now be a simple line being rendered every frame to the game view.
Congratulations!
You've now completed another tutorial. And best of all, you were able
to enter all the code above, compile it, and interact with the
GameEngine object without ever having to stop your game from running.
Tutorial 3 - Resource Manifests
Before we start diving in to code up a real game, let's take a moment to look at how we load data, what kinds data there is to load, and how to access that data from within the game environment.
The engine uses a resource management system based off of singleton objects called "manifests." Each manifest is a container for all the [named] resources of that type in the game. Resources can be either an external resource loaded from disk or an object created at runtime. Resources can be loaded and unloaded at will (they are automatically loaded when needed, though).
Something very important to note is that resources are lazily evaluated; they won't be loaded (or created) until requested by for another resource or the game.
The manifest interface is quite simple. Games can subclass the base GameManifest class to create their own resource types. For example, one might make an NPCManifest to describe all the various NPCs types in a game: what sprites they use, how many hit points they have, and how much damage they do.
Each manifest file is a simple INF file. At the top is a short header with information about the manifest good for version tracking, default values, and any other global settings to that manifest file. Following the header are all the objects (resources) described within. Here is a sample SpriteManifest file:
version=0.1
author=Me
date=2/3/2007
game=asteroids clone demo
[spaceship]
texture=master
origin=482 @ 405
extent=27 @ 26
[bullet]
texture=master
origin=51 @ 59
extent=7 @ 19
To load this manifest, all we need to do is call the #read: method for the manifest object:
SpriteManifest default read: 'media/sprites.inf'
Note: it is possible to read multiple manifest files to accumulate objects. Once read, this manifest will contain 2 sprites in it, named "spaceship" and "bullet". Later on, from anywhere in your game, you can access these sprites at any time using the manifest:
SpriteManifest default at: 'spaceship'
The above will load the texture named "master" (found within the TextureManifest) if necessary, and create the GameSprite object if that hasn't already been done. Once done, the sprite will remain loaded in the manifest until unloaded (by either closing the manifest or calling #unload: or #unloadAll).
Since manifests are evaluated lazily, it is possible to read all the manifest files for your game in any order at startup, and then just use them when needed. Of course, getting a pause in the middle of the game to load a sound or texture wouldn't be good.
For this reason, there is a special attribute used for resources: preload. It's possible to call a manifest's #preload method to instantly load/create all the resources with this attribute set to true. There is also a #preloadAll method in the manifest object to force load/create all resources in the manifest.
Now that you know how to create manifest files, read them, and get the resources from them, we can move onto things that are more fun!
More to come...!