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....

 1

About

User