[lisp-game-dev] LGDC010: Roto Mortar post-mortem
Patrick Stein
pat at nklein.com
Tue Mar 30 14:33:54 UTC 2010
On Mar 29, 2010, at 1:23 PM, "David O'Toole" <dto1138 at gmail.com> wrote:
> I'd like everyone to post an entry postmortem
My game is called Roto Mortar [1]. When I started trying to come up
with a game that I might be able to pull off in a week, I remembered
an exercise from the book: Game Design Workshop [2]. The exercise
was to design a game with a one-button interface.
The concept I came up with for this contest was that you were trying
to defend a base against attack. You've got two mortar cannons.
Unfortunately, their controls have been blasted. Lucky for you, Ace
Repair Guy Billy Bob has rigged one of them to rotate and hooked up a
button that let's you tilt it while you hold the button and fires when
you release it.
Here is the game announcement I made on my blog [3].
What I got done was the basic shell of the game. There is a quick
title screen with a message from Billy Bob setting the stage. Then,
you're plopped into the game. Another message from Billy Bob
announces that he's gotten one turret back online.
The game scenery, enemies, and projectiles are all UV textured, X3D
objects made in Blender with PNG textures. The game uses shadow-
volume techniques to overlay a range and angle indicator onto the
scenery so you can tell where you're aiming. Those shadow volumes are
non-textured, X3D objects built in blender.
I used my own code for font-rendering in cl-OpenGL using zpb-ttf [4]
to render the messages from Billy Bob and the opening title. I used
cl-png to load the PNG files (textures and Billy Bob icon). I used a
custom parser atop CXML SAX parsing to read the X3D files. I used
CLOS throughout and made much use of the PROGN method combination.
[1] http://nklein.com/software/roto-mortar/
[2] http://www.amazon.com/Game-Design-Workshop-Prototyping-Playtesting/dp/1578202221
[3] http://tinyurl.com/ykeahl8
[4] http://nklein.com/2010/01/better-text-rendering-with-cl-opengl-and-zpb-ttf/
> 1. what did you learn?
I had read about Shadow Volume rendering in OpenGL several times
before. This is the first that I actually did it. I could probably
do it again now without references.
I had a bunch of my methods return a new 'screen instance if you want
to switch screens. I think, if I were to do it again, I'd either make
a robust check on the receiving end to ignore return results that
aren't of type screen or add a slot to the screen class that is NIL
until it's time to switch screens. As it was, I accidentally returned
T or a mesh or something incompatible from my event handlers way too
many times (especially by the end of the second all-nighter).
> 2. what went right?
I drew a simple UV cube in Blender. I exported it to every choice on
the export menu. After looking a bit, I opted for X3D. It's badly
structured XML, but not too hard to parse. (I say badly structured
because its lists of number are all encoded into strings. Rather than
stuff like <coordinates><coord><x>3.5</x><y>2.0</y></coord>...</
coordinates> or even: <coordinates><coord>3.5 2.0</coord>...</
coordinates> they instead have attributes of comma-separated lists
coordinates="3.5 2.0, ...".)
Anyhow, I think X3D was a good choice... easy to get going. And, with
baked textures from Blender, things looked pretty good.
I was glad I had already published the font-rendering code cuz I could
otherwise have a day there. As it was, I just pulled in the font.lisp
I had published earlier [4].
I used SBCL's save-lisp-and-die to make a command-line executable and
Platypus to wrap that up as an OS X executable. Those both worked
great.
> 3. what went wrong?
As I mentioned, having each event handler for a screen possibly return
a new screen seems like a cool, lispy idea. Really, it is easy to
mess up when you're tired.
I spent lots of time, too, trying to figure out which attributes I
hadn't saved that I should have in one place which screwed up things
in another place.
I also spent way too much time working around the OpenGL matrix
methodology. What I needed to do for my direction-indicator and range-
indicator was... translate to where they need to be and draw them at
the appropriate angle and scale. What I wanted to be able to do is
set up the angle and scale and then translate things and draw. If
OpenGL had more room available on the :projection matrix stack or
another :model-local matrix after the :model-view, I could have reused
code much more. As it was, I had to make some custom draw code for
these objects to get the rotation and scaling to happen after the
translation.
There is a whole list at [1] of things I wanted to get done in a week,
but didn't.
There may well be an option to CXML to get it to ignore the DOCTYPE
declaration. But, I just manually removed them from the X3D files to
keep CXML from trying to fetch them.
> 4. what's lispy about my entry?
In the game-play itself? Nothing.
In the implementation, I used PROGN method combination to great effect
here. In particular:
(defmethod update-item (item delta-time)
(:method-combination progn :most-specific-last))
This way, the base object can track total time elapsed since some
point, but derived objects can use either that total time or the most
recent delta or an intermediate classes total time since some other
indicator.
The XML parsing also makes use of interning symbols to avoid lots of
string compares.
> 5. what interesting algorithms or designs did i use?
The basis of the X3D parser was generated from other Lisp code that I
was working on a few weeks back.
And, the PROGN thing was pretty cool.
And, the shadow volume technique is pretty flexible for projecting
stuff onto surfaces.
-- Patrick <pat at nklein.com>
More information about the Lisp-game-dev
mailing list