Postmortem

Posted by
April 29th, 2010 11:55 pm

A few days have passed, so its time for me to write a postmortem before I forget everything I did with Invasive.

First: Thanks to everyone who played my game!

This is long, and possibly of little interest so I’ll hide it behind a read-more tag.

What went right/techniques learned…

– Hybrid blitting engine

I didn’t implement a full-redraw-each-frame blitting engine, so I’m calling it a hybrid. The main viewing area of the game consists of three “zoom” classes extending Flash’s native Sprite class, which in turn each have a terrain, flora, fauna, and artifact layer. Those layers are 500×480 transparent bitmaps to which I draw almost every frame. (The zoom class tracks a camera, and if it hasn’t been moved the terrain layer doesn’t refresh. The other layers get fed model data, and get cleared and repainted every frame.) At any given time, only one zoom class is visible, the others are .visible=false and aren’t fed model data.

Performance isn’t earth shattering, but up till now to do this project I would have added sprites to the display list for every movable object. Having a Flash display list several thousand items long just doesn’t really work well. :) So I was happy with this.

-Bitmaps for storing data

There are several cases in the game where I need to know if two things are in the same place. (A kiwi and a tree, a glomper and a kiwi, etc..) Since I had divorced the model from the view, I couldn’t do use either Gilbert’s bitmap collision class as I had planned , or Flash’s bitmap.hitTest[method]s. I was storing every objects locations in their own arrays. (Ie: Kiwi:Array, Glomper:Array, etc) Each object had it’s own class, but all of them had public GlobalX and GlobalY properties.) I’m sure there are faster ways of finding all intersections between two lists than a nested loop, but unfortunately I don’t know them (yet). In pseudo-code:

FOR EACH Kiwi:

FOR EACH Tree:

if the Kiwi's location == the Tree's location:

Do Stuff;

On the other hand, most of the objects weren’t colliding at any given time. So, rather than checking -every- Kiwi against -every- tree, I did the following (in pseudo-code):

PLOT EACH tree on an off screen bitmap

FOR EACH Kiwi:

Look at bitmap and see if there is a tree, IF there is a tree:

FOR EACH Tree:

IF the Kiwi's location == Tree's location:

Do Stuff;

Even though I added an if operation to the nest, and even though there’s an extra loop outside the nest (to do the plot), the second pseudo-code snippet runs faster because it cuts out a nested for loop in a large percentage of cases. Since in the cases of the Kiwi/Glomper interactions the arrays could have literally thousands of members, this made the game possible. (Though I think the second snippet is still O(n^2)? I don’t have enough of a CS background to assess that.)

I also used a bitmap for initially storing map information (to set terrain tiles during initialization). This worked beautifully vs using an xml, just in terms of my own convenience.

What went wrong:

The zoom wasn’t intuitive

I was pretty happy/comfortable with my pan and zoom, but i had written it in the first place and knew how it was going to operate. I -should- have provided mouse-wheel zoom, mouse-edge panning, etc. And the zoom levels I provided were poorly chosen; for my convenience, rather than the player’s. Several commenters noted this and they’re right.

– On the outermost level of zoom, animals should have been more than 1×1 pixel. And their colors could have been better.

It’s very hard to tell the difference between glompers and kiwis, because they’re represented at this level by single pixels– and those pixels are red and brown, two colors which don’t really show up well against the terrain. I think 2×2 pixels might have been more visible, and I could have given more thought to contrast. (Also noted by commenters)

– I spent most of my time on displaying a model, and didn’t spend time on gameplay or interface.

In the versions up to 0.6, walls stop glompers but don’t stop Kiwis. Since I cowardly shrank from the challenge of pathfinding several thousand animals at once, the movement is decided at random. As a result I was afraid there was no win condition. So at the last minute I changed it so that walls stop everything… this meant there was an easy but possibly tedious way to win, hurting the fun value of the game. I didn’t really tune things I should have, such as the number of kiwis each glomper needed to eat before reproducing. Ultimately, this comes down to me failing to test sufficiently.

Likewise, several commenters noted that it would have been nice to have click-drag to place walls (which after all, are useless if just single blocks!). They’re right.. in fact I knew this before I released it, but-

– Time management/motivation

I stopped with several hours left because I was dead tired, and probably should have tried to take a nap rather than calling it a day. The major casualty of this is a sound effects engine, but there were others.

For the present:

I had fun building the game, and I think I improved my technical skills by dealing with the movement of large numbers of objects– a task I just wouldn’t have attempted in my usual projects.

For the future:

– I’ve now done two LDs where I tried to pull off something with more complexity than I was able to do properly. Next time I’m going to try to do something small, and polish it until I gotta wear shades.

– The general setup seems ok, and I like the idea of doing a game about invasive species. I may revisit this and try to implement a better ecosystem model (along with the interface improvements), and come up with a better game. There are other projects I need to finish first though.

-TF


4 Responses to “Postmortem”

  1. jplur says:

    Interesting post mortem.

    Regarding the collision checks, if the map grid can store pointers to objects inside it, (and kiwis store a pointer to the tile they are on) then you can slim it down a bit.

    For EACH kiwi:
    if other things in kiwi’s tile:
    interact with them

    • TFernando says:

      AFAIK, AS3 doesn’t allow for C-style pointers, BUT… I could store in each map cell the array index for each object in the cell.

      At the moment, those indicies change as the arrays grow and shrink, but I could make them fixed with a little additional overhead for each add/remove (I’d have to flag dead objects and over-write them rather than just splicing them off.) Since the add/remove happens infrequently compared to the collision checks that should be a decent trade in exchange for flattening the nest.

      Thank you!

  2. Hamumu says:

    I don’t worry about quitting early… I’m an old man, and about halfway through Sunday (in my timezone, LD ends at 7pm on Sunday), I always decide that’s good enough and just polish up a couple of loose ends, zip it up and go for a walk. I always find that by that point, I’m just completely burned. I could get more done, but why smash yourself when the actual work week is starting the next morning? Of course, I also take it really easy on that next work day too. LD is a mentally draining experience!

Leave a Reply

You must be logged in to post a comment.

[cache: storing page]