Month 2: Prototyping
Indie Game Dev Production Prototype Software Engineering
It's always tough to pick up work where I left off after getting back from vacation. I at least had the sense to leave some detailed notes for myself on where I was at and what needed to get done, and just picked a few easy tasks as a way to get back into the code. One thing I'm thankful for is my code commenting and descriptive variable names.
As far as the prototype goes, I've slowed down on progress as I fix a bunch of problems and try to figure out how things should work. I'm a bit unsure on what should and shouldn't go into a prototype. The purpose of a prototype is to quickly test things out to see if they work before spending a lot of time on it in production. My initial thought was that this means you create a quick mock-up of your tentative game design and see how the mechanics work together. But, what about some of the technical challenges I don't quite know how to resolve yet? In my case, I've got up to a few hundred creatures on a battlefield in box formations. Writing the code for the formations isn't as straight forward as it would seem. How does the formation change when members die? How does the formation move from one location to another while maintaining cohesion (cue some flashbacks to bootcamp)? When should a creature attack an enemy creature? If attacking a nearby enemy creature causes the creature to leave formation, how do you determine when its appropriate to break ranks? What about creatures with a ranged attack who can see and target an enemy creature, but doing so requires a change in orientation which is different from the formation orientation. When does a ranged unit reorient themselves from their formation position to attack a nearby enemy? How important is it for a creature to value a command, such as a move order? How much can the creature deviate from that?
Player: "Move over to this position"
Creature: "Okay, got it."
Creature: "Oh hey, there's an enemy creature close to my current position. I'm going to go attack it before returning to my original order!"
Creature: "Hey, that enemy creature is running away and I'm getting pretty far off track. When should I abandon my attack and resume my original orders?"
My principles on prototyping has changed slightly. While the prototype is all going to be thrown away, it's a good way to find these problems and answer them. The exact code/solution discovered by prototyping and play testing can then be copied almost verbatim into the production version of the game and then polished. The uncertainty will always linger though: what is important enough to be included in a prototype vs. what is "just polish" and should be added in during production?
My tentative answer: "If the feature adds significant impacts to how the game is played, it should be included in the prototype."
Example: my creatures reorganize themselves in formation to fill in any gaps when a member dies. It looks pretty and pleases me, but also has tactical significance to the way the game is played because it keeps the front lines unbroken. If a creature dies, its position is filled by the back row, so the fighting continues and it's harder for enemy units to get a "surround" situation.
I ran into a significant challenge earlier this week. I had decided to use my Octree implementation. It was really buggy and causing lots of crashes. That meant that I needed to go back and rethink the code on it. I spent a good day and a half working on trying to get it to work as initially planned -- to update intelligently -- but that was way too complicated. On the train home yesterday, I was reflecting on what a show stopper this challenge was becoming. Once again, I was becoming a victim of premature optimization. Why exactly do I have to be intelligent about what part of the octree I update? It was just a part of an overly engineered wet dream. The whole purpose of an octree is to reduce collision checks to a manageable time, so that when you have hundreds of objects, you're not choking your CPU. I realized that there was no good reason not to just completely trash and rebuild the octree every single frame. The CPU costs of that are negligible and satisfy "prototype quality" code. If I was actually using my octree in production, it would be worth it to get it 100% correct, provided my existing solution is showing performance problems. Again, I know not to optimize prematurely and yet I do it anyways. To avoid that in the future, I need to periodically to a check on myself and think about what I'm doing for at least two minutes. If it costs me two minutes to realize I don't need to do two hours of work, it's worth it.
I have started working on rudimentary artificial intelligence for my creatures. Initially, my approach was very crude (prototype appropriate) but it wasn't robust enough to handle the changes I needed to add. I was creating a few scripted behaviors using if statements and math. If I needed to extend it, I had to dig into this mess of spaghetti code and it was daunting. On many occassions, it got too confusing and complicated and I ended up scraping it and starting over again, only to repeat the same thing. Today, I had a genius idea. Rather than creating a ton of spaghetti code or a large state machine with a massive switch statement, I would create a bunch of "Behavior" functions to handle every possible scenario I could dream up, and then write some code to look for a "situation context" when that behavior should be triggered, and then I use a function pointer which hits the appropriate behavior. It is so much more elegant, much less complicated, and much more extensible.
I also spent a lot of time writing the back end game mechanics infrastructure. To my own surprise, I'm starting to get to the point where all of these detailed game mechanics are coming to life and it is quite thrilling to see it all in action. At this point, my archers use their equipped short bows to shoot arrows at enemy targets which are within their cone of view and in their area of attack. The arrows fly and deal damage to the enemy units, provided they actually hit. Dead units turn into skulls and their positions are filled by surviving members of a unit. I almost have everything done on the tactical battle mechanics front. The last bit is a morale system. Then, it's moving on to letting wizards cast spells on the battlefield, adding additional spells, adding additional units, adding additional weapons, more game mechanics, and trying to keep things balanced and most importantly.... FUN!
If the prototype isn't fun, it's not worth going into production until it is.
I signed my team up to go to a day long game dev conference at Digipen being hosted by Intel. They have some sort of indie game challenge for indie game devs. The top prize is some marketing exposure or something. I certainly am not ready to enter anything into that, but I'm hoping I can get my prototype into a stable, working state by then. If I can, I'll plop it onto my laptop and shop it around informally for some feedback. We'll see. I hope the conference is worth all of the opportunity costs I'll be incurring. I still haven't thought of a game title or company name. That's surprisingly difficult. When people ask me, "Who do you work for? What's you're game called?" I don't really have a good answer. That's going to turn into a problem as time progresses.
Next update in a month! I hope to work hard and bring you something tangible to look at by then!