One of a Kind: Extended post-mortem

Posted by (twitter: @ddrkirbyisq)
December 29th, 2011 7:44 am

Alright!  Finally got around to doing this post.  This is going to an extended look back at the development process of One of a Kind, which you can download, play, and rate here.  It’s going to be a lot of walls of text, so if you want the shorter, regular port-mortem with “what went wrong vs what went right”, you can instead read this post.

That said, onto walls of text!

First off, timing.  LD22 was just not really at a convenient time for me…it was right after finals week, and though I normally don’t have many problems at all with finals, I -did- have some final project work I needed to finish up, and I was busy doing Christmas letters and stuff like that as well.  Initially I had intended to use the weekend/week before Ludum Dare to try out making an extremely simple shmup with SDL.net.  I had been eyeing SDL.net and wanting to try it out because it was C# just like XNA, but with SDL.  I knew I really liked developing in C# from my previous work on XNA stuff, but the major downside of XNA is that it locks you into the microsoft/windows platform.  Now, SDL.net isn’t really totally geared to being cross-platform either because you still need to use Mono to get the .NET stuff in there.  But from what I’ve seen, mono with SDL.net at least works better than monoXNA, which seems to be -really- immature.

Anyhow, I was intrigued by SDL.net but was still a little bit wary of whether or not it would really work the way I wanted it to.  If I could get working in it rather quickly and it did cross-platform okay, then that meant I had a winner.  So pretty soon I had a spaceship sprite moving up and down and left and right and shooting bullets on my Visual Studio 2010 setup.  Okay, great.  But then I noticed that I was getting some slight jerkiness, and not totally smooth motion even though my movements were all whole-pixel amounts.  Okay, a lot of referencing later, I’ve read stuff like the “Fix Your Timestep!” article and I actually for the first time am wrapping my head around the finer points of timesteps, framerate, vsync, and all that.  Since SDL.net doesn’t seem to have vsync (unless you use OpenGL, which I wasn’t willing to do because it was going to be a little more trouble for performance/etc gain that I probably didn’t need, and I -really- didn’t have time to write up OpenGL sprite functions or anything anyways), I concluded that the best thing I could do was to have an unlimited graphics framerate, while keeping a fixed game logic step.  The only bad part about that is that there’s possible tearing, but I was willing to accept that over the alternatives.

Meanwhile, I’m trying to get SDL.net working on my macbook classic in OSX (normally I’m booted into windows), as well as my linux VM.  This takes…quite a bit of effort, actually.  And my time is running REALLY short.  As in, the theme is going to be announced and I’m still trying to get things working on the OSX side (linux was a bit easier).  Theme gets announced and I go “huh…”, and then I actually get a .app on OSX that runs and gives me my spaceship, and keyboard input actually works! (for a while it wasn’t)

Though I still haven’t really solved the porting problem, I decide that this is good enough for me to go the C#/SDL.net route.  It’s something that I wanted to try out at some point anyways, so I might as well do it now and see how it goes.

After that, I went to a social dance event where I…didn’t really brainstorm any ideas.  After that I came back and don’t think I really got too much done as I was pretty pooped and had accumulated some sleep debt.  So despite the fact that it was like 9 hours into LD and I hadn’t really done anything, I just went to bed and decided that I’d get a real good full night’s worth of sleep.  I could have short-charged myself on sleep, but dammit, I was tired, and it’d just end up biting me in the ass later if I didn’t anyways.

So, Alone.  I started thinking pretty early on that I’d do a 2D platformer.  Yes, I know 2D platformers are really common in LD, but I’ve never actually done one before, and I figured that it’d be a good way to invoke the emotional atmosphere that I was going for.  Here’s my first brainstorming note sheet:


To me, “Alone” as a theme is nice because it doesn’t immediately bring any sort of content to mind like some of the other themes do, nor does it immediately call out some sort of game mechanics.  Take that in contrast to something like “dinosaurs”, for example, where you know all the games are going to have dinosaur characters in them, or “randomly-generated” where you already know that randomness is going to play a pretty big element.  So “alone” is pretty abstract and lets you go in a lot of possible directions.

I thought it would be really nice if I could manage to achieve both an overall mood of “alone-ness” and a somber feeling, but at the same time think of some kind of game mechanic that ties in with “alone” somehow.  Already I was thinking a lot along the lines of The Company of Myself (which by the way probably would have fit right in with this theme), and you’ll see a lot of that influence play in everywhere.

Eventually I settled on what I initially called an “alone-ize” ability, where the character can “alone-ize” an object, meaning all other objects of that type will disappear from existence and therefore leave that object “alone”.  The tie to the theme was slightly strenuous but I was generally happy with it and how it fit into my sort of vision so I decided to roll with it.  My only worry at this point was whether or not I could actually come up with any interesting gameplay out of the concept (which seemed cool).  This would end up biting me in the ass later…

But for the time being I set up really simple platformer physics, with placeholder graphics.

This actually ended up being really easy.  I knew C# was easy to develop in, but I didn’t think making my physics would be THIS easy.  The code was super-simple too, and I’m honestly a bit surprised that it held up so robustly.  The only weird part of it is that the character has 2 sets of coordinates–one real set of floating-point coords that I keep myself and one set of integral coords that’s used by SDL.net for blitting (since we’re extending the Sprite class), and so I have to make sure to keep those synced.  If I were doing things properly, I’d do something like make get/set functions and such, but I was doing pretty messy quick-and-dirty coding, so I just kept them in sync myself, and luckily this never bit me in the ass.  Note that the reason I needed floating-point coordinates at all was for vertical motion, as if you try to restrict yourself to integral coordinates, jumping looks…really really weird.

Anyways, other than that, everything was super-simple.  I could test for collisions using SDL.net’s functions which just did simple rectangle-intersections based on sprites, which was good enough.  So then I just did simple logic like if you’re holding right, move one to the right, unless that causes you to collide, etc.

I ended up coding a really simple thing that used pixel values of .png files to load in the map.  So actually every white tile that you see is a separate entity/sprite, and when I collision-detect I just see whether you intersect with any of them.  This ended up actually being a performance bottleneck, which I didn’t really realize until later.  Unfortunately I didn’t know how to easily profile my code automatically and I wasn’t about to try and find out, so my performance tuning consisted mainly of me realizing my game was stuttering, turning off various parts of the code (rendering?  logic?  collisions?) and seeing whether the stuttering went away.  Eventually at some point after I added the “reflection” mechanic I realized that the reflection was causing a huge performance hit, and realized that it had to be some code in the Character class, since I duplicated that code for the Reflection class (yes, code duplication, evil but necessarily in LD).  After I verified that it was the collision-checking I just optimized it by simply only checking objects that are within 2 tiles of the character’s position; and that solved things very nicely.

Speaking of performance bottlenecks, I also figured out that having alpha channels in my surfaces really slowed down blitting a lot, so I tried to avoid those (this was most important for the huge 640×480 backdrops).  I also needed to convert surfaces to the video screen format after loading them–I think that also made a difference (there needs to be an automatic way to do this).

Speaking of alpha channels, apparently in SDL.net (and in regular SDL), you can’t mix per-pixel alpha with per-surface alpha.  Which means that if you have a .png with some 50% opacity pixels, you can’t draw the whole thing at 50% alpha, or fade it in or out.  This actually took a little bit of time to look up and discover, and unfortunately it meant that my “alonify” sparkle sprite needed to use color-keying and couldn’t have translucency if I wanted it to fade.  On the plus side, the animation looks good (maybe even -better-) without alpha anyways, so it was fine.  Another consequence of this is that I ended up using separate sprites for the “nonexistent” versions of blocks, which was slightly inconvenient to make a second set of sprites, but ended up working okay.  Yet another consequence is that the text rendering couldn’t use anti-aliasing (per-pixel alpha) because it needed to fade in (per-surface alpha).

Speaking of the blocks…so, two things about that.  One is that in my initial “alonify” concept, I simply had the other like-colored blocks disappearing completely.  After thinking about that for a bit and trying to reason about puzzles, I realized that it was….not really quite that interesting at all.  So then in a flash of insight I had the idea that the others wouldn’t disappear completely, but instead would become passable so that you could “realonify” them.  Another thing is that at some point I actually made “walls” which were thinner versions of the blocks.  My reasoning was that with the block graphic, people might see it and get the idea that they can push them around.  I even considered perhaps making the blocks pushable, but never really ended up seeing any interesting puzzles that could be made involving that.  Eventually I decided that it was better to just keep things consistent and make everything blocks.

When I was drawing the character animation, I intentionally wanted to make the character graphic very plain, because I wanted it to be a vessel for the player to place themself into.  If I made it some emo guy with long hair or something, then the feeling would be more like “that character is alone” rather than simply the player experiencing it more directly.  So I didn’t use any colors and didn’t add much detail.  I didn’t have many pixels to add detail with anyways.

Speaking of pixels, I should note that I actually started making the game at 320×240 upscaled to 640×480, but then realized that at that size the maps were just too small to get interesting level designs, so I upped it.  This also happened at the same time that I was running into performance issues trying to upscale every frame, so whatever.  This wouldn’t have been an issue at all if I had been using OpenGL, but again, I didn’t want to go that route for this project.

So then I had a lot more space to work with.  This screenshot also shows the “walls” that I had in place of the blocks in an early version.

Once I had my actual character animation in, the block sprites and the gray tiles in, I also did sound effects with a mix of bfxr and FL Studio.  Once I had those, things were already looking like the beginnings of something cool, so I knew I was on the right track.

Unfortunately, I had a disaster incoming in the form of level design…

So, designing the puzzles for the game ended up being the most stressful part of the whole ordeal.  Well, closely followed by the initial start of LD where I was caught unprepared, and porting and distribution.  But puzzle design definitely caused me to bang my head against the wall most…or more accurately, it caused me to just sit at my computer and generally get nothing done for hours.

The problem was that I had no idea what kinds of interesting puzzles and puzzle concepts were possible using the whole “alonify” mechanic.  In fact, I didn’t even know if there were =any= interesting puzzles I could make.  I didn’t really know all of its implications and how it really worked.  Pretty early on I came up with the idea of having puzzles where there are multiple different corridors you pass through and each corridor has a certain sequence of colored blocks, and you’d have to go through and alonify the right blocks in order to pass.  And so I ended up with a bunch of sheets with grids of numbers trying to construct a non-trivial puzzle that looked like that, and…well, nothing I tried seemed to really work.

It was looking pretty hopeless at some points.  I even tried looking at some videos of Closure, that game where only things that are in the light exist, but that didn’t really spark anything either.  I kept on trying to think of something else I could add besides the colored blocks.  Enemies wouldn’t really be good, because “alonifying” an enemy doesn’t really make sense.  Switches/pressure plates/etc. didn’t really seem to make much obvious sense to me either, and seemed a little complicated.  Keys/locked doors didn’t make sense either–why would you ever “alonify” a key?  It didn’t really seem like I was getting anywhere with my ideas, so I think what happened was I just called it a night and slept for a while before waking up again.

Eventually I stumbled upon the puzzle above, which was kind of a eureka moment as it’s actually non-trivial.  It’s not -hard-, but not totally straightforward either.  I eventually realized that having blocks form floors was a useful trick, as a kind of one-way drop.  I also got the idea of having a narrow corridor at the right end of the room with a bunch of “target” blocks indicating that you needed to alonify some other block of that color before you could proceed.

Eventually I started to come across this sort of more standardized type of puzzle, with multiple rows and a sort of pyramidal structure.  After thinking about it a little I realized what actually makes these sorts of puzzles tick, which is that the blocks in the middle column are “protected” by the blocks on either side, which creates a sort of dependency chain.  Again, not exactly the more interesting or difficult thing, but it was all I had at the moment and it wasn’t -boring-, so I went with it.  And of course, I came up with a few variations, such as the room where you can’t alonify any blue blocks because you need the blue floor to be there.

So, despite all the troubles, I actually managed to come up with puzzles that IMHO worked decently (not great, but not bad).  In contrast, the earlier screens were pretty fun and easy to design, and each one actually has a fair deal of thought put into it.

Because I didn’t have any sort of instructions or tutorial, I needed the first few screens to both teach the basic controls to the player, as well as set up the mood and connection to the theme.  The first screen does -exactly- that.  It establishes the #1 basic action of a 2D platformer (walking to the right) and introduces the recurring theme of the character feeling “unspecial”.  I should mention that I actually had some different ideas for endings to the game, and one of them involves you finding a mirror at the end (the sprite for that is actually still in the content directory) and using your “alonify” on that, essentially suggesting that you “found what is special in yourself”.  When I came up with the actual mirror character concept, I decided that it would make more sense to have the ending work with that instead.

Again, introducing jumping to the player (and forcing them to use it in order to advance), while also strengthening the mood.

While the rest of the game doesn’t really require much in terms of platforming ability, I still needed to introduce the restarting ability, which is necessary if you ever make a mistake in any of the puzzles.  So I made some pits where you’d have to restart, so that the player would try out that ability.  It should be noted that this is probably very, very similar to how the restart ability is presented in The Company of Myself.

This room is actually more for flavor than anything else.  I needed these two lines of narration in order to explain that the character has the ability to “see what makes something unique”, which ties into the next room where you first learn about the “alonify” ability.  This is actually the one room that I sort of screwed up on, as the platforming here is unnecessarily hard.  Granted, anybody who’s familiar with standard platforming will have no problems with this whatsoever, but for those who aren’t, this screen might actually pose some difficulty.  So if I were to redo things, I’d make this particular room a little bit easier.

After that we go into the main rooms where we introduce the alonify ability and in each room we kind of explore a new concept based on it.  First we introduce the ability itself, then we show that the ability isolates based on the colors of blocks.  Then we force the player to realize that you might need to alonify things while you backtrack.  Then we introduce the “one-way” aspect of having colored-block floors, and then use that in a basic puzzle.  The next puzzle after that is the one where you’re allowed to approach the rows of blocks from both directions, then one where you’re allowed to approach the rows from both directions until you alonify the blues, and then after that the one where you aren’t allowed to alonify the blues at all.

Then we introduce the mirror character, which I really have to thank the gods for as it was a really good insight that came to me and was really necessary to make this game complete.  I struck on it with probably less than 6 hours to go and decided that it was worth it to try implementing it and seeing how it went.  I just created another class that was almost identical to the main character class with some key differences.  Of course, one tricky part was getting the reflection to start out in the same place that the main character does so that they aren’t desynced–at least, not in the beginning of a screen.  And I needed that to work with respawning too.  So what I ended up doing was that the reflection starts as inactive, and is constantly checking the spot that’s half a screen height below it to see if the main character is there.  If he is, then the reflection activates and starts responding to input.

One other tricky part was how to handle the case where both character and reflection alonify blocks of the same color.  I’m actually still not sure exactly how the situation works, but I think what happens is that it alternates each time, which is good.  But yeah, that took some tweaking.

The reflection puzzles honestly aren’t quite that interesting, and could have probably been better, but I had to rush through some of them for the sake of time.  On the plus side, I had already finished most everything else at this point, so I knew how much time I had to work with.  And even though the puzzles themselves aren’t that interesting, the narration ties in well.  I like the “pyramid of gold” idea on the 3rd to last screen–that was actually sort of a happy accident that I came up with that idea.

One thing that worked well for me was taking breaks from level design and such to work on other things, such as music and artwork.  This was especially important because of how much time I was “stuck” and feeling unable to make progress on levels.  So I tried to not waste time by using those periods to work on other things.

The music was super-easy to make, to be honest, since I have so much practice producing things in very short time periods.  Once the first few piano notes were in, the rest of the song basically flowed very naturally from that.

As for the stage backdrops…they took a bit longer.  I wish I would have had a way of just doing them totally automatically, but I didn’t have time to do anything like that, so I just drew all the levels myself.  Thankfully I managed to work out a pretty quick way of doing it, involving clever selection growing/shrinking and flood-fills to save time.  In the end it still looks really simple, but -infinitely better- than if I had just kept the solid gray blocks.  Those black outlines and dark/light shading really, really do make a big difference.

And I think that’s an area where I really succeeded-making a game that looks, feels, and sounds pretty polished.  I think that’s something that’s really nice to get, especially in Ludum Dare where a lot of other entries have really rushed MS paint-style sprites that aren’t animated and placeholder graphics everywhere and no shading and such.  So I think mine really succeeded in standing out in that respect.

Also, a note on the ending–there’s actually a sort of secret where, on the last screen, if you instead have your mirror alonify you (as opposed to you alonifying your mirror), the screen flashes cyan instead of white.  That’s it.  Yeah, okay, not really much, but I put it in for fun anyways 😉  The ending is kind of ambiguous as to what actually happens, which is…totally fine by me.  I think it works; or works well enough for what I had to work with, anyways.

After everything was set and done, I had some time left over for packaging and distribution, which was kind of a nightmare.  On the windows side, my binary produced by Visual Studio required the .NET framework, so I instead compiled using MonoDevelop and that ended up solving that issue.  Unfortunately I still ended up forgetting a Tao DLL at first but I fixed the package soon enough, so Windows was set.  Linux wasn’t that hard to set up, but unfortunately requires you to install mono which has a lot of dependencies.  Plus, I don’t think it works on 64-bit Linux.  OSX was really terrible and I couldn’t find any way to package it without requiring additional installs until I finally just tried Wineskin, which worked but I needed to bloat the download to 150MB.  Ugh!

So, overall, SDL.net was pretty nice to work with.  I really really like working in C#.  However, I can tell from this experience that it’s not the magic bullet that I’m looking for.  So my next target will either be to try out pygame, or maybe even try a browser-based game using Flixel or one of the multitude of other tools that seem to get a lot of use during LDs.  I probably want to try both at some point…maybe I’ll try each at least once between now and April so that I have more options for next time.

When all is said and done though, I managed to make a pretty awesome game, despite some troubles with level design and not really starting off on the right foot.  I don’t think I regret a single part of the process, besides perhaps making that early platforming room a little harder than it needs to be.  Well, and also making the initial screen go away on mouse click instead of just keyboard hits.  I know that I was sort of dealing with an element of uncertainty in that I based my game on an “unknown” mechanic and therefore didn’t know whether I could really take it anywhere, but I don’t really regret taking that risk, and it certainly turned out well enough.  But again, the biggest accomplishment was how the whole package came together–pixel art, animation, music, and narration really worked together to make a very coherent piece and I’m really happy with how that turned out.

Hope to try this again in April. :)

Tags: , ,


Leave a Reply

You must be logged in to post a comment.

[cache: storing page]