Save the Sheep Postmortem, 5/11/04

 

Overview

To summarize, the theme of Save the Sheep is that you are a part of a team of sheep within a brick wall, with wolves outside that are trying to attack. The wolves gradually break down the walls, but it's your job to repair them by pushing new bricks into place.

From the beginning, my goal for the game has always been to make it fun, and different from the gameplay of most normal games. I kept in mind several design principles: it's important to have a definite conflict (the conflict in this game was between the sheep and the wolves), it helps to follow the rule of 3: have multiple decisions for the user to choose between - in my game the player can choose between training the sheep's block pushing ability, or training their block creation speed. The controller can also decide whether they want to create bricks themselves, or push them to the wall (or both).

Note: I've made the game binary available - see Downloads.

Development Summary

External Code:

  • GUI - the GUI was implemented in Qt, a multiplatform GUI toolset (which I have worked with before).
  • Sound - done with Fmod
  • 3DS model loading - uses code provided by Andy Herrman and others.

External Content:

  • The pig model was from 3D Cafe I couldn't find any good sheep models on the Internet, so I had to use pigs. The pigs are cute too though.
  • The wolf model was called Mr Tusker, from MrCad. I had trouble getting the 3DS loader to load colors properly, and the model didn't provide textures.
  • The musical soundtrack was ambient techno from Abaris.

Key Technical Challenges

  • pathfinding: This turned out to be much more of a challenge than I expected. I had planned on simply taking my A* pathfinding code from lab3 and using that. I had intentionally designed my A* code to be easily reusable and general. And this held true - in only about 15 minutes time I had A* up and running in my game. But, I found that the pathfinding for my game would need to be more powerful in a couple ways:
    • - I needed to calculate anywhere from 5 to 20 paths per cycle (depending on how many players you run), whereas in lab3 it had only been one (the path for my single tank). Running A* 5 to 10 times per cycle slowed down my game too much (or, too much to keep it at 50 fps anyway). My solution was to cache the A* paths. I simply store every path calculated, paired with the start and end point. That solves the speed problem. However, I didn't have time to make a good caching system, and there are a few bugs: I never discard cache entries. This means if bricks get moved around, players could use invalid paths. Yes, this would take like 5 minutes to fix, but it was 6am before the demo and I had higher priorities on my list. Another problem is that the A* does not consider player positions. I previously used player positions, but it caused some problems, and it actually works better without considering player positions.
    • - In the tank lab, my A* never had to handle the situation where no path exists to the goal. In Save the Sheep, this happens sometimes because there is no path from inside the enclosure to outside it. (I have a separate wall breach detection function, but it's not perfect).
  • gameplay balance: I expected this to be a challenge, but it was more difficult than I expected (or perhaps I just didn't have enough time to spend on it). Gameplay balance means how do you tweak parameters to get the game to be challenging yet still beatable. I had a lot of parameters I could adjust: teammate and opponents speeds, brick creation speed, brick damage speed, map size + structure, number of teammates + opponents, and others.

    I think the current settings are passable, but there are many more scenarios I could try out.

Reflection

  • Things that went right:
    • game mechanics - brick pushing, creation, etc.
    • general gameplay - it actually does play roughly the way I had envisioned
    • graphics - better than I expected (since graphics were not a priority, my expectations were low anyway).
  • Things that went wrong:
    • I didn't have time to implement all the AI I wanted.
    • 3DS models look dull, not quite what they should be.
    • didn't get things done early enough (last 48 hours of work was done in the last 48 hours before the deadline). This was due to having other classes that made stuff due before that.
  • Lessons learned:
    • Game design always takes longer than you expect. And designing a well-balanced, fun, and graphically pleasing game is very challenging.
    • Making good, portable code in my previous projects definitely had a payoff on this project. I estimate that 3000 to 4000 lines of this project (out of ~11000 total lines) was code reused from the previous two labs. Some of it was just utility and debugging stuff - not a direct part of the game core - but it's still useful.

Future Work

You might think it odd that I have a future work section. Well, I *may* work on this during the summer a little, just for fun. And since I might consider the game development field after finishing my master's, this would be a nice addition to my portfolio.

Things I'd consider doing:

  • port to Windows - requires rewriting the GUI in MFC, because while Qt is multiplatform, the Windows version requires a license I believe.
  • fix pathfinding
  • fix player models (they need better colors, and textures)
  • vastly improve AI - currently it's very basic.
  • possibly add networking? there could be options for cooperative or opponent-style play.
  • name change? - since my models currently are pigs, I'm not quite sure if I should change the name to Save the Pigs (which might sound pretty stupid), or try to create a sheep model.

Screenshots:

A close-up of my pig model:


The wolf model. It's a very good model, but I couldn't get the colors right:


A fullscreen shot showing the training system controls (buttons on left):


I threw together a help system - I decided that was important because my game is impossible to understand without at least a brief intro/tutorial:


This shows the debugging objects that I could display: