It’s been a long time since I blogged about anything, and any “Stop That Hero!” posts were sparse, so let me update you on what I’ve been doing over the last couple of months.
When I made the original Ludum Dare #18 entry, I had just finished reading through two AI books: AI for Game Developers and Artificial Intelligence for Games, Second Edition. My LD version of “Stop That Hero!” was the proving ground for what I learned. Three days of “why won’t this work?!” frustration concluded with everything coming together, and I was proud of it.
As I worked on the full version of the game, I found that one of the struggles I’ve had with STH! is with regards to software architecture. The entity AI was especially unintuitive to work with because I had written a bunch of disparate systems that weren’t aware of each other but depended on all of them working together.
The Movement system assumed that the MovementComponent had its direction set correctly and moved the entity’s position according to its speed. The Targeting system would find the nearest targetable object. And the Pathfinding system would find a path to that targetable object. Now, they sound like they work together fine, and for those three responsibilies (movement, targeting, and pathfinding), they were great.
But path following was the responsibility of the pathfinding system, which updated an entity’s MovementComponent’s direction based on where the next node in the path was. Targeting was a bit weird, too. For example, the Hero targets treasure chests, castles, and towers. In the above system, the Hero would go towards the nearest targetable object, which means he’d pick up health even if he didn’t need it simply because he was closer to it than anything else, and I had no way to change it easily.
Part of the problem is my inexperience with creating AI systems. Another part is my inexperience with component-based systems. And a third part was my inexperience with software architecture in general.
Months ago, someone suggested I read Programming Game AI by Example by Mat Buckland. What this book had over the other two books I mentioned was actual working code and examples to read through. If you’re new to game AI, I would highly recommend Buckland’s book.
After reading through it and the source code, I rearchitected the AI of my game. Now instead of having disparate systems that somehow work together, making tweaks and changes unintuitive and hard, I have goal-driven agents. Entities have a Brain component, and different Brains have different kinds of goal evaluations. A sword-wielding hero, for example, might decide between conquering the nearest tower, going for the nearest health, or fighting the target enemy, and those decisions will depend on the health of the hero, the distance to a tower, and how strong the enemy is. A slime might be a simpleton and will merely try to reach its target enemy. A warlock might try to keep some distance from his enemy while staying within range to fire magic bolts or do whatever else warlocks do. And so on.
As you can see, changing the AI of an entity is much easier and intuitive with Buckland’s goal-driven agents. I understand that it is not the state-of-the-art in game AI, but it is way better than what I had, it is good enough for this project, and it wasn’t that hard to implement. The hard part is writing the code for the different goals and goal evaluators, which is more tedious than difficult.
As for other updates, I added the concept of teams to make conquering and fighting easier to manage. I was very unhappy with how the Targeting component was being abused in figuring out if a hero was at a tower or if enemies were within range of each other. I had envisioned levels where the player isn’t fighting against heroes but other villains. Slimes should be able to target slimes from another team, but before I added a Team component, there was no way to know.
In May, I added combat mechanics and death. Granted, I already showed a video of combat mechanics in action, but still. Weapons are implemented as projectiles for simplicity. If I want melee attacks, I’ll just set the range to be a short distance.
And since I was having trouble telling if the attacks were doing anything unless the target died, I added little health bars to provide feedback. When an entity’s health drops to 0, it dies. As in the original prototype, the hero has 3 lives (after all, all video game heroes have 3 lives), but I’m rethinking that idea based on a lot of other ideas I have for the game.
Originally, I was thinking about having melee attacks only, but when I added slime trails, projectiles made sense, and at that point, I realized that melee attacks can be implemented as projectiles. Yay, simplicity!
Also, yay, feature creep? Every feature that gets added means more time is needed to make the game. Isn’t it a bit late to make such a fundamental change to the game? The project is already way, way behind the original schedule. Why make it harder to ship?
Here’s my take: I’m less interested in shipping as fast as I can and more interested in shipping a fun, compelling game. By adding projectiles and slime trails, I’ve made the game noticeably more interesting.
Frankly, the game needed more interesting things to do. Since starting the project in October, it is only recently that I’ve done so much work specifically on experimenting with the game design as opposed to putting in scaffolding. Yes, I’ll be the first to admit that I took way too long to get to this point, but I woefully underestimated the technical requirements and did not have a full understanding of the scope of the project when I started.
The website is not polished yet, but then again, neither is the game. There is a development blog where I will talk about STH!-specific work, and I’ll use the main blog here to talk about my business or anything else as before.
And now, I’ll disappear into my work again. There’s more that I haven’t mentioned above, but I will say that I’ve been redoing a bit of the front-end work in my attempt to separate the GUI from the actual game logic. While it might sound like I’m trying to do things “right” instead of “good enough for game dev”, I found that the separation is already making it much easier to move forward. Like I said, I’ve been weak in software architecture. I think other game developers assume I know more about how to hack something out that works well enough, but the truth is, the more I try to slap something together in the interest of going fast, the more I end up painting myself into corners. So I’ve been reading up on GUI architectures and reading through code to see how others handle it, and it’s been eye-opening.