Bourtange Postmortem (ILGE 2010)

August 11th, 2010

Bourtange @ github

Overall I’m satisfied with my lisp game. My major goals were to learn lisp (to a shallow yet useable degree), learn a little about functional programming and last but not least to end up with a playable game. I feel I hit those goals and as an added bonus I’ve enjoyed programming in lisp so much that I’m looking for another project to start working on. That said, here is an explanation of what went into the game, what went right and what went wrong.

Built with
I made the bulk of the game using sbcl with cl-opengl for graphics and TextMate for editing. I wrote some custom ‘build’ scripts to send my monolithic game file to the sbcl repl. The development cycle was similar to what you’d expect from programming in C, ‘write->compile->test’. Later on after my first version I got help from the guys at #lispgames (irc.freenode.net) (sykopomp, xristos, 3b) with setting up emacs and using slime-connect, as well as setting up a .asd for my game. Using the interactive dev env that emacs + slime enables is really a liberating way to program.

What went right
* My game is playable! More often than not I leave my game projects in an unplayable (sometimes not compilable) state. I’m proud to say that this game is playable.
* The difficulty of the game goes up over time.
* I tried to program in a very functional way, which worked most of the time. It enabled my program to easily reset, and should allow for a fairly easy save function, but I never got into file i/o to finish that.
* The colors are cool

What went wrong
* Writing in a functional way messed me up a little. I tried my best to make things functional, without really having a firm grasp on what that means. I would give up on writing functionally and go back to just making things work when the going got tough. This means that in the end, I feel the code is naive and dirty.
* Collision detection is very simple. This would be fine if things didn’t move very fast, but when using gravitational equations for motion, things get very fast when they get very close. In order to keep the collision detection simple I put limits on how fast things can move. It works, but it’s dirty.
* After something gets hit I recalculate 360 points of an arc to display the life left. Halfway through development I wanted to have all the circles be drawn using ONE list of points generated ONCE. I could draw some percentage of the points to represent life lost. When I tried to refactor for this, drawing became very, very broken. If I had more time to work this out I think the game would be much faster and much smoother.

All in all, I’m pleased. I hope you play my game, and I hope you have fun playing it!

My Lisp Game is Done!

August 9th, 2010

I just checked in the ‘final’ code to github. Check out my first program in lisp!

Bourtange, a fort defense game writting in Lisp

Bourtange!

Lisp Game Progress

August 1st, 2010

So after my first (almost) 30 days of learning lisp, I have a playable game. The gameplay is a cross between tower defense and orbient. You control a planet-base (the core) in the center of the screen. This core comes equipped with one weapon, the core-blast. Enemies are generated at the edge of the screen, in the spawning-belt, and are drawn toward your core by gravity. When enemies collide with the core, the core looses life. Life is displayed as a green outline around the core and when your core is out of life, it explodes. When an enemy dies, which happens either by colliding with your core, being hit by a blast or being thrown past the spawning belt, you gain resources. Resources are displayed by purple boxes in the upper left. You can spend these resources on extra cores and weapons in the weapon-store, which is displayed in the upper right. Below is a screen shot of the game in action.
Screen Shot
A lot of work still remains to be done, but I hit the 30 day deadline with this first draft. Luckily, the contest hosts have extended the due date to August 10th. By then I plan to fix some bugs, add more weapons, enemies, a game-over screen and do some optimization. I feel accomplished after learning lisp, though I know I’ve only seen the tip of the iceberg and have found my new favorite language. To the hosts of the competition, thanks! You guys have made me a better programer.

The source to the game is here and you can download and build the game as you please. Send me a message with your thoughts on my game or my code!

Lisp Game Competition

July 3rd, 2010

A friend and I have decided to write a game in LISP in 30 days. The game will be entered in the 2010 lisp games expo.

My good friend Aaron Maus is a lisper, and wanted to make a game. I’ve never programmed in lisp. We have 30 days to program a game for this contest. Super fun.

The blog has moved.

April 13th, 2010

Yes, that’s right – I moved the blog again. Now we’re hosted at Linode, which is cheaper and easier than Media Temple. The main url is now http://efnx.com instead of http://blog.efnx.com (though both should still work).

DIY Webserver Using PureMVC++

December 22nd, 2009

To test out my newly ported PureMVC++ implementation I decided to write an example webserver. I’ve always wanted to write one, and I didn’t realize just how easy it is (to make a VERY rudimentary version).

The server parses your http request and then spits it back out at you, with some nice html.
Screen shot 2009-12-22 at 2.35.47 PM
That’s it! Source code is here:
http://github.com/efnx/PureMVC-Plus-Plus/tree/master/example/httpserver/

PureMVC++ – A C++ MVC framework (ported from AS3)

December 18th, 2009

I had some time over the past month to port the popular PureMVC application architecture from AS3, to C++. I learned a ton about C++ and it turned out to be a rather smooth process. The code is up on github.

Differences in the C++ version

Notification names and types are ints!
At first I used strings for notification names and types, just like in other ports. I did this until I was writing the first sample application. At that moment I realize in C++ you can’t switch on strings! There’s no support for writing a switch statement on the type std::string. I simply didn’t know that. So code like this just won’t compile:

switch ("somestring")
{
    case "notthisone":
        trace("not gonna happen");
        break;
       
    case "northisone":
        trace("also not gonna happen");
       
    case "somestring":
        trace("this one gets evaluated");
        break;
       
    default:
}

C++ only allows you to switch on ints, so to save us from having to write something like this:

if(note->getName() == "notthisstring")
    cout << "not gonna happen";
else if(note->getName() == "northisstring")
    cout << "also not going to happen";
else if...

I decided to make note names and types ints. This way we can enumerate our notification names and types like so:

class n_name
{
public:
    enum name
    {
        NIL,
        STARTUP,                // triggers the app startup sequence
        SET,                    // sets something
        GET,                    // makes a request to get something
        DISPLAY,                // display something
        QUIT                    // quit the app
    };
}

and then handle the notification with ints:

int name = note->getName();
switch(name)
{
    case n_name::STARTUP:
        cout << "Startup the app!";
        break;
    case n_name::QUIT:
        cout << "Shutdown...";
        break;
    default:
}

IFacade no longer contains a registerCommand method
I tried my best to figure out a way to implement stateless commands in C++. The way the AS3 version accomplishes this is by passing around references to classes. In that port handling references to classes in an abstract way is easy because AS3 has built in type introspection. In order to do the same thing in C++ we’d have to depend on something from the boost library. That’s not an option. Instead I gave Facade a templated method to replace IFacade’s registerCommand (conveniently called registerCommand). So instead of calling registerCommand(noteName, CommandClassName), one makes a call like this: registerCommand<CommandClassName>(noteName). This calls a special template function created by the compiler that adds CommandClassName to a templated Observer, which is added to the View’s observer list.

That covers it for now. In the coming weeks I’ll probably be adding example code to this post, as well as example applications to the repo. If you’re interested in the project, keep up to date with the repo at github and soon we’ll have a repo at PureMVC.org. I’ve added some temporary documentation for you to use as well.

AS3 – Creating a Convex Polygon from Unordered Points

September 21st, 2009

Let’s pretend you have an application that lets users create shapes to be used in a physics simulation and that the user must click on the screen to set the vertices of the shape. Many physics engines only support convex polygons, or shapes that don’t have inlets, bites, or coves, basically shapes that don’t have inward facing edges. With this limitation we have to be able to restrict [read as "guide"] the user to make only convex polygons. For this we are going to need an algorithm that takes an unordered set of points and finds the convex hull that encloses those points. This way the user can click and add points at random, if desired, and your program will keep track of what points create a convex polygon, while the others are thrown away [or dealt with however you see fit].

The Graham Scan Algorithm is a process of ordering a random set of points and then calculating jumps to the points in that set that constitute a convex polygon. In this algorithm there are three steps. First is to find a corner point, usually the topmost, leftmost point in the set. The second step is to order all other points by the polar angle between the corner point and the point in question. The last step is to traverse the set, taking each proceeding subset of three points (n, n-1, n-2) to determine whether the angle made by these three points is a left turn, right turn, or a straight line. If the turn made is our desired turn [which is usually left - but in Flash it's right, due to the flipped y-axis] then we add that point to the convex hull. If the turn is not our desired turn, we get rid of that point and move on.

Here is an example that shows first the data set drawn from point to point. Each successive line gets progressively whiter. In the second step we find the corner point, order the other points and then show the outer polygon.

Example

Example

Here’s the code for the class:

/**
 *  Use this class freely - 2009 blog.efnx.com
 */


package
{
    import flash.geom.Point;
   
public class GrahamScan extends Object
{
    /**
     *  The Graham scan is a method of computing the convex hull of a finite set of points
     *  in the plane with time complexity O(n log n). It is named after Ronald Graham, who
     *  published the original algorithm in 1972. The algorithm finds all vertices of
     *  the convex hull ordered along its boundary. It may also be easily modified to report
     *  all input points that lie on the boundary of their convex hull.
     */

   
    public function GrahamScan()
    {
        super();
    }
   
    /**
     *  Returns a convex hull given an unordered array of points.
     */

    public static function convexHull(data:Array):Array
    {
        return findHull( order(data) );
    }
    /**
     *  Orders an array of points counterclockwise.
     */

    public static function order(data:Array):Array
    {
        trace("GrahamScan::order()");
        // first run through all the points and find the upper left [lower left]
        var p:Point = data[0];
        var n:int   = data.length;
        for (var i:int = 1; i < n; i++)
        {
            //trace("   p:",p,"d:",data[i]);
            if(data[i].y < p.y)
            {
                //trace("   d.y < p.y / d is new p.");
                p = data[i];
            }
            else if(data[i].y == p.y && data[i].x < p.x)
            {
                //trace("   d.y == p.y, d.x < p.x / d is new p.");
                p = data[i];
            }
        }
        // next find all the cotangents of the angles made by the point P and the
        // other points
        var sorted  :Array = new Array();
        // we need arrays for positive and negative values, because Array.sort
        // will put sort the negatives backwards.
        var pos     :Array = new Array();
        var neg     :Array = new Array();
        // add points back in order
        for (i = 0; i < n; i++)
        {
            var a   :Number = data[i].x - p.x;
            var b   :Number = data[i].y - p.y;
            var cot :Number = b/a;
            if(cot < 0)
                neg.push({point:data[i], cotangent:cot});
            else
                pos.push({point:data[i], cotangent:cot});
        }
        // sort the arrays
        pos.sortOn("cotangent", Array.NUMERIC | Array.DESCENDING);
        neg.sortOn("cotangent", Array.NUMERIC | Array.DESCENDING);
        sorted = neg.concat(pos);
       
        var ordered :Array = new Array();
            ordered.push(p);
        for (i = 0; i < n; i++)
        {
            if(p == sorted[i].point)
                continue;
            ordered.push(sorted[i].point)
        }
        return ordered;
    }
    /**
     *  Given an array of points ordered counterclockwise, findHull will
     *  filter the points and return an array containing the vertices of a
     *  convex polygon that envelopes those points.
     */

    public static function findHull(data:Array):Array
    {
        trace("GrahamScan::findHull()");
        var n   :int    = data.length;
        var hull:Array  = new Array();
            hull.push(data[0]); // add the pivot
            hull.push(data[1]); // makes first vector
           
        for (var i:int = 2; i < n; i++)
        {
            while(direction(hull[hull.length - 2], hull[hull.length - 1], data[i]) >= 0)
                hull.pop();
            hull.push(data[i]);
        }
       
        return hull;
    }
    /**
     *
     */

    private static function direction(p1:Point, p2:Point, p3:Point):Number
    {
        // > 0  is right turn
        // == 0 is collinear
        // < 0  is left turn
        // we only want right turns, usually we want right turns, but
        // flash's grid is flipped on y.
        return (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x);
    }
}

}

PHP – Nested Tuple

September 4th, 2009

Here’s a quick nested tuple [list of head and tail, where tail is the list minus the head]. I wrote this for a current project I’m working on. It works with any parameters except one array. If you only pass one array, it will convert your one array into a list of Tuples.

<?php
/**
 * Tuple is a list of variables. Really it is a head and a tail, where the tail
 * is also a Tuple. (Tuple(n)=head + Tuple(n-1))
 */


class Tuple
{
    public $head;
    public $tail;
   
    public function __construct($args = null)
    {
        if(! (is_array($args) && func_num_args() == 1))
        {
            // get all the arguments and package them as an array
            $args = func_get_args();
        }
       
        // take the first element and use that as the head of the list
        $this->head = array_shift($args);
        // if there are still args left, make a new list and use that as tail
        if(count($args)>0)
        {
            // pass the remainder
            $this->tail = new Tuple($args);
        }
       
    }
}

?>

Here’s some usage and output:

<?php
$list = new Tuple(1, 2, 3, 4);
print_r($list);

That prints out:

Tuple Object
(
    [head] => 1
    [tail] => Tuple Object
        (
            [head] => 2
            [tail] => Tuple Object
                (
                    [head] => 3
                    [tail] => Tuple Object
                        (
                            [head] => 4
                            [tail] =>
                        )

                )

        )

)

Game Progress 1

July 11th, 2009

I’ve been working on another game lately, it’s called Machinista – it’s a game where you control motors in a 2D physics simulation. The entire thing is built around Box2D, which is a great physics system. Last night I worked on using Brownian Bridge fractals for explosions – check it out! Use keys W, A, S, D and shift+click to control the tank and make explosions, respectively.