Gish Source

Gish Screenshot

Now that the Gish source code has been posted, it's time to actually look at this thing. Here are some of my notes while chugging through this thing quickly:

  1. Firstly, this project is in C, and not C++. C tends to be faster and more portable, but large game project tend to go with C++, so this surprised me, but in a good way. :)
  2. Secondly, in order to compile for Apple computers, you need to compile with "THINKSTUPID" defined. I lol'ed heartily about that.
  3. Thus far, I have not found any useful comments. They're all either licencing info or commented-out code. Too bad. :/
  4. This code uses OpenGL all over the place, not just in one neat file. This sucks, because in order for someone to port this to the Pandora, they'll have to go file-by-file through out this project, converting the glBegin()/glEnd() code to OpenGL ES's vertex buffers.
  5. Lots of the code REEKS of copy-and-paste, and magic numbers are littered throughout the code. This results in functions that are hundreds or thousands of lines long, with HUGE if-blocks that span nearly the entire function. Plus, many of the other functions could have been written WAY nicer. Consider loadstorylevel() from setup.c:
    void loadstorylevel(int levelnum)
    {
    #ifndef DEMO
    if (levelnum==1)
    loadlevel("sewer1.lvl");
    if (levelnum==2)
    loadlevel("sewer2.lvl");
    if (levelnum==3)
    loadlevel("sewer3.lvl");
    if (levelnum==4)
    loadlevel("sewer4.lvl");
    if (levelnum==5)
    loadlevel("sewer5.lvl");
    if (levelnum==6)
    loadlevel("sewer6.lvl");
    if (levelnum==7)
    loadlevel("sewer7.lvl");

    if (levelnum==8)
    loadlevel("cave1.lvl");
    if (levelnum==9)
    loadlevel("cave2.lvl");
    if (levelnum==10)
    loadlevel("cave3.lvl");
    if (levelnum==11)
    loadlevel("cave4.lvl");
    if (levelnum==12)
    loadlevel("cave5.lvl");
    if (levelnum==13)
    loadlevel("cave6.lvl");
    if (levelnum==14)
    loadlevel("cave7.lvl");

    if (levelnum==15)
    loadlevel("hell1.lvl");
    if (levelnum==16)
    loadlevel("hell2.lvl");
    if (levelnum==17)
    loadlevel("hell3.lvl");
    if (levelnum==18)
    loadlevel("hell4.lvl");
    if (levelnum==19)
    loadlevel("hell5.lvl");
    if (levelnum==20)
    loadlevel("hell6.lvl");
    if (levelnum==21)
    loadlevel("hell7.lvl");

    if (levelnum==22)
    loadlevel("egypt1.lvl");
    if (levelnum==23)
    loadlevel("egypt2.lvl");
    if (levelnum==24)
    loadlevel("egypt3.lvl");
    if (levelnum==25)
    loadlevel("egypt4.lvl");
    if (levelnum==26)
    loadlevel("egypt5.lvl");
    if (levelnum==27)
    loadlevel("egypt6.lvl");
    if (levelnum==28)
    loadlevel("egypt7.lvl");

    if (levelnum==29)
    loadlevel("church1.lvl");
    if (levelnum==30)
    loadlevel("church2.lvl");
    if (levelnum==31)
    loadlevel("church3.lvl");
    if (levelnum==32)
    loadlevel("church4.lvl");
    if (levelnum==33)
    loadlevel("church5.lvl");
    if (levelnum==34)
    loadlevel("church6.lvl");
    if (levelnum==64)
    loadlevel("sewer8.lvl");
    if (levelnum==65)
    loadlevel("cave8.lvl");
    if (levelnum==66)
    loadlevel("egypt8.lvl");
    if (levelnum==67)
    loadlevel("death.lvl");
    if (levelnum==68)
    loadlevel("death2.lvl");
    #else
    if (levelnum==1)
    loadlevel("demo1.lvl");
    if (levelnum==2)
    loadlevel("demo2.lvl");
    if (levelnum==3)
    loadlevel("demo3.lvl");
    if (levelnum==4)
    loadlevel("demo4.lvl");
    if (levelnum==5)
    loadlevel("demo5.lvl");
    #endif
    }
    That very well could have been just:
    void loadstorylevel(int levelnum) {
    char buf[16];

    assert(levelnum>0);

    #ifndef DEMO
    if (levelnum<=7 ) sprintf(buf, "sewer%d.lvl", levelnum);
    else if(levelnum<=14) sprintf(buf, "cave%d.lvl", levelnum-7);
    else if(levelnum<=21) sprintf(buf, "hell%d.lvl", levelnum-14);
    else if(levelnum<=28) sprintf(buf, "egypt%d.lvl", levelnum-21);
    else if(levelnum<=34) sprintf(buf, "church%d.lvl",levelnum-28);

    // All of the super-secret bonus levels are special cases:
    else if(levelnum==64) sprintf(buf, "sewer8.lvl");
    else if(levelnum==65) sprintf(buf, "cave8.lvl");
    else if(levelnum==66) sprintf(buf, "egypt8.lvl");
    else if(levelnum==67) sprintf(buf, "death.lvl");
    else if(levelnum==68) sprintf(buf, "death2.lvl");

    else assert(0);

    #else
    if (levelnum<=5) sprintf(buf, "demo%d.lvl", levelnum);
    else assert(0);

    #endif

    loadlevel(buf);
    }
    I know it really doesn't matter; the code does the same thing, but the code on the bottom is shorter and easier to read.
  6. I'm seeing all kinds of code that relies on chdir()'s, and other functions that force the program to be run out of the same directory as the executable. Plus, the high-scores, and game saves go into that same directory as well, and replays get saved into a replay directory. That type of code may be cool on Windows, but it's going to need some rewriting if we ever want to see a Gish *.deb, or *.rpm.
  7. Check out animation.c if you dare. 1 function. 1337 lines of code. That's a cool number for it to be, but O.O at the actual function...
  8. Finally, the reason I dove into this code in the first place... the physics code. The physics code is surprisingly simple. Gish himself is merely a bundle of unbreakable bonds and springs. (See: createtarboy() in object.c), as are all of the dynamic blocks and such. From what I can tell, the internals of their physics engine is actually incredibly simple. It will simply go through all dynamic objects subject for collision, and will then compare that block to every other dynamic block for collision handling. Each block will compare the level separately from the blocks, separately from the particles, and so on. With this engine, each physics update has a O(n2) running time, where n is the number of dynamic objects in the level. This simple approach seems to have worked well for Gish, but probably won't work for other projects, so don't try to use the Gish physics engine in other projects... It would probably be best to just stick with more advanced 2d physics libraries, like Box2d for C++, and Chipmunk for C. (I'm personally a huge fan of Chipmunk, and I used it in that Tetris Hell game I posted a short while back.)

One final note: this list may seem a little harsh at points, but I don't want it to be. I know that I have coded some pretty horrible things when I've been under pressure, and I don't want to act like I'm above committing my own personal coding sins. I am completely thrilled that the Gish code is now free under the GPL, and I hope more projects do the same!

That said, rewriting a few bits couldn't hurt... ;)

Where's the source?

So, it's been a couple of weeks since the Humble Bundle made over a million bucks. That's great, cause 4 of the games in the bundle offered to release their source code if the Bundle made over a million. Thus far, both Lugaru and Penumbra:Overture have released their source. Bit-Blot, the makers of Aquaria, seem to be chatting about implementing an online mod database, so they're obviously hard at work getting us some nice, high-quality source. However, I haven't heard anything from Cryptic Sea (the makers of Gish)...

I know the Cryptic Sea guys are probably hard at work, but I do wish we could hear more about the publishing process... That soft-body physics engine looks neat... I'm wondering how they did it... :) It's especially interesting, because I really liked Gish back in the day... it's the game that introduced me to indie gaming. I bought it back when it was released in 2004, again when it was released on Steam, and again with the Humble Bundle. (Although, I got the Bundle mostly for the other games...) I do seem to like supporting it. :)

Plus, it looks like, for the FIRST TIME EVER, the Pandora open-source handheld gaming console is less than "2 months away." (It's been "2 months away" for, like, 2 years now.) And so, it would be nice to see either Gish or Aquaria on it, since they're both really cool games, and both games are Linux-ready. (Although, I don't think either is ARM-ready, so porting might take some work...)

...

Oh, and despite the long breaks between posts, this blog is not dead. I'm currently working on a new project, and if it pans out, I'm sure that it will make for some good writing material. :)

EDIT: Gish released source! Wow, I didn't see that coming. I thought aquaria would release source first....

Android Development for the Nexus One, on Linux

A day or two ago, I got my AT&T-enabled Nexus One, and I must say, this thing is awesome! I've spent the last few days going back-and-forth between working on that TunnelTanks game, and playing with this thing. It's crazy cool! So, naturally, I wanted to write software for it. I mean, I learned all about Android development last year, in ECS160, so now it is time to put that knowledge to some good use!

Well, I finally have got it all working... At 3:20am, a day later. Unfortunately, some of the Android Documentation deals with *REALLY* old versions of Ubuntu and is now obsolete, so I thought I'd add a few notes:

  1. I use Ubuntu 9.10, which finally packages the latest Eclipse, which is compatible with the Android SDK. That said, DO NOT USE IT!!! Seriously, it's not worth the effort. Ubuntu removed all of the plugins that are required to use the SDK, so in order to use it, you would have to hunt each and every one down, which is a royal PITA. It's far easier to download the Eclipse Classic tarball from here, and just unzip it into ~/bin. (Ubuntu will automatically add ~/bin to your PATH if that directory exists.)
  2. Installing the SDK is crazy easy. Just stick with Google's tutorial; it still applies.
  3. If you want to upload your program ONTO your Nexus One, then don't follow the Linux directions for device development on Google's site. They're old, and now wrong. First of all, despite the Nexus One being an HTC device, it doesn't use HTC's USB vendor code (0bb4). It uses Google's (18d1). So just create a file in /etc/udev/rules.d called "51-android.rules", and put this in it:
    SUBSYSTEM=="usb", SYSFS{idVendor}=="18d1", SYMLINK+="android_adb", MODE="0666"
    Udev should notice the new file instantly, but if it doesn't, run: "sudo udevadm control --reload-rules". Then, try running "adb devices". If your Nexus One is plugged into the computer's USB, and nothing shows up, verify that the Nexus One is in Debugging Mode (Settings>Applications>Development). If it says it is, try rebooting the Nexus One, and check again.

Hopefully, with those notes, you can then follow the rest of the Android tutorials normally. To finish, I'll just post a picture of my Nexus One with a "Hello World" application running. :)

My nexus one saying 'Hello World'

PS: Thanks Google, for the awesome phone, for the free engraving on the back, and the free overnight shipping! Wow! After waiting over a year-and-a-half for that Pandora open-source gaming device (still waiting, btw...), I forgot that cool electronics can be only 2 days away.

 1

About

User