sIQ: An OpenGL Puzzle Game in Smalltalk
By: Brad Jones, Chris Lattner, Joel Stanley
IQ is a game for the Sony Playstation upon which sIQ is based. The basic
premise of the game is that rows of blocks roll forward towards the player, who is
upon a supporting grid of squares. The player dies when it either falls off of the edge of
the playing field or is rolled over by a block. The player can “capture” blocks by placing
triggers and activating them when the block is on the square wher
e the trigger was
placed. There are three types of blocks: regular blocks, green blocks and black blocks.
When you capture a regular block, the block simply disappears. When you
capture a green block, green triggers are placed on the playing field wher
e the block was
captured and in the surrounding squares (thus expanding the region that may be
captured). These triggers are distinct, and are triggered differently from the triggers that
the player places. The player is to avoid capturing black blocks;
if they do so, the back
row of the playing field is removed.
The player controls the player via the keyboard. Arrow keys move the player.
The space bar places and activates the player’s trigger. The enter key activates the green
While this could be viewed as a 2
D game, the version on the Playstation is 3
So we decided to make the game 3
D. We used JUN, which is a pretty full
wrapper to OpenGL to handle many of the rendering chores. The basic framework
The game has one model that is of type GameModel. The GameModel object is
in charge of keeping track of all the game objects. The controllers send messages to the
model to tell it that the user wants to perform some a
ction, or the next game cycle has
occurred. In this way the GameModel acts as a Mediator between the game objects and
Within the model, we have classes to represent particular game objects. We have
a Player class, which represents the
player in the world. We also have Cube and Square
classes, both of which inherit from Block. Squares represent the Blocks that the player
runs around on. Cubes represent the cubes that roll towards the player.
The GameModel stores an array of arrays f
or both Cubes and Squares, which can
be indexed at a particular grid location to return the Block instance stored there. Blocks
know how to render themselves, they also know their x and y position. Much of the code
in GameModel is spent guaranteeing that
the x and y position of the Blocks is consistent
with their indexes.
The View is an instance of GameView. It handles much of the code related to
getting things rendered correctly on the screen. While Blocks actually know how to
, other global aspects must be handled in some reasonable way. For
example, setting up the lights and the camera for the scene is handled by the view. There
is no good reason for us to use the “changed” event structure available within the MVC
because we want to draw to the screen as fast as possible and as often as
possible. Things change every time that we draw so sending events with self changed
within the model is unnecessary.
The controllers that we have are specialized becau
se we want our game to be
constantly running. The SIQController class is derived from JunOpenGLDisplay
Controller, and modified to not ever block. However, we maintained the same interface
as regular controllers, and so our controller is fully compatible
with the existing event
framework. We do this by checking the event queue to see if is empty before we invoke
the (blocking) routine that obtains an event from the queue. If the event queue is empty,
we invoke the rendering code, and if not, dispatch t
o the default event handling routines.
We ensure that all pending events are handled before we force a redraw.
Controllers also translate user commands into actions. These actions are just a
simple translation from particular key presses to message
ds to the model.
We experienced some implementation obstacles that are worth mentioning. At the outset
of the project, we were plagued by having a poorl
documented (at least in English,
anyhow!) object framework which provided virtually no nontrivial examples. Even now,
we believe that many of our performance problems are related to misuse or abuse of the
Jun framework. It is altogether possible that w
e are pushing the boundaries of JUN’s
capability, in which case it is ill suited for modern real
The handling of keyboard events within the VisualWorks UI framework is nontrivial.
press events involves a c
omplex object registration scheme that requires
instantiation of KeyboardProcessor objects and hooking them up in the right way with the
appropriate views and controllers. Thanks to Samuel S. Shuster on the VisualWorks
Commercial mailing list for prov
iding us with a detailed description of handling
In order to get the display to use an off
screen graphics context, we had to do two things.
First of all, we had to implement a custom DamageRepairPolicy for our window th
prevented the background color from filling the graphics context every frame. Secondly,
we had to inherit from the JunDisplayView and properly override the renderOn: method
to manifest the desired behavior. We could not find examples of how this was d
because all of the source code was available, we were able to browse until we found the
appropriate location to place our hooks.
The VisualWorks environment did not seem particular suited for the development of a
time 3D graphics ap
plication intended for use on modern hardware. However, the
rapid prototyping features allowed us to obtain much functionality and do a lot of testing
in a relatively short time, as soon as our technical difficulties had been resolved. We
spent a lot of
time “testing” our game by playing through the various levels time and time