The last time I wrote about Stop That Hero! development was in July. Here’s a quick summary of the work I’ve done since then:
Fixed memory bugs
I fixed a number of issues in July, specifically with weird corruption issues that seemed to result from the use of std::vector<bool> which is apparently not a real vector of boolean values. I was easily able to discover where memory leaks were occurring with Valgrind.
Recently, I ran into a bizarre unit test failure when adding code to a module that had nothing to do with the unit test, and I discovered that I had introduced a bunch of memory leaks that were finally manifesting in such issues. It wasn’t hard to fix since I once again was able to use Valgrind, but it was tedious work. A lot of it was fixing dumb mistakes, too. I have no idea why I thought I could get away with the code I wrote when I wrote it.
Unless there are corruption problems, memory bugs are not usually a big deal during development. Still, it would be nice if I used tools that made it easier to avoid the problems in the first place. I use UnitTest++, but these memory leak issues would have been caught had I used a tool such as CPPUTest which fails tests if memory leaks.
Added more minions, entities, and projectiles
Once I made combat revolve around projectiles, I added fireball-launching dragons and warlocks. Warlocks will eventually have a magic spell they cast, but they launch fireballs because that was the only projectile I had at the time.
Recently, I added new heroes. Archers shoot arrows, and wizards cast lightning bolts. I eventually want to add villagers and knights and get rid of the generic Hero character.
Optimized rendering
I’ve had the same update/rendering code for a long time, and on a whim, I added some logging to my game to find out why I wasn’t able to get 60 FPS even though I didn’t think I was doing much.
It turned out, I wasn’t doing much. All of my code ran within a millisecond, but the actual SDL call that blits to the window took between 30-50 ms to run! The good news is that my own code isn’t slowing me down, but mathematically it’s impossible that SDL MUST render this slow since so many other SDL games run much faster. So I looked to find out what other people did to make it work.
Here’s the code I was using to set the video mode:
m_screen = sdlInstance->SDL_SetVideoMode(m_x, m_y, m_bitDepth, SDL_DOUBLEBUF);
And here’s a much faster version based on a thead at Ubuntu Forums that I apparently did not bookmark:
m_screen = sdlInstance->SDL_SetVideoMode(m_x, m_y, m_bitDepth, SDL_SWSURFACE | SDL_ASYNCBLIT | SDL_DOUBLEBUF | SDL_ANYFORMAT | SDL_SRCALPHA);
So I went from 30-50 ms to 8 ms. The game runs so much more smoothly now, and it didn’t take a lot of work at all.
Switched away from pie menu
Pie menus are great for usability, but only if you can guarantee that the menu can be displayed in its entirety around the mouse cursor. Since one goal with “Stop That Hero!” was to make the interface as simple as possible, I didn’t want a scrolling world. The entire world fits on the screen at once. To use pie menus, I’d have to reduce the world size to provide a border all so that buttons could fit on the screen if a tower was selected near the edges.
So I removed the pie menu and went back to a traditional UI at the top of the screen.
Added resources and minion costs
Before, I was adding minions to the game whenever I wanted. Now there are resource costs, and it takes time to summon a minion from a tower. The player starts with a base set of resources, and the current system adds 1 resource every second. It’s simple, and it works. I can experiment with resource mechanics, such as adding rewards for killing heroes or if certain minions collect items and bring them back to the player’s castle, but the basic system is in place.
Made object creation more generic/data driven
I initially tried to make the game as quickly as possible, so instead of trying to genericize object creation, I created a bunch of separate commands: CreateHeroCommand, CreateDragonCommand, CreateOrcCommand, etc.
While it worked, it was also very limiting. Each time I added a new type of entity or in-game object, I had to create a new command. Maybe that’s fine if I know what entities and objects I want to create up front, but it limits the design. Maybe I want to make weak squires, regular soldiers, and strong knights as variations on each other. The effort to write the code for the separate creation commands would be tedious and slow.
So I replaced all of those CreateXYZCommands with CreateObjectFromTemplate. Instead of having coded commands to create an orc, I create a template called Orc, which defines components and data that an orc would have. CreateObjectFromTemplate(“Orc”) then creates the components with the correct data, and an orc appears in the game world.
Templates can be created and changed much more easily than hardcoded commands, which means adding and tweaking minions, heroes, and other in-game objects is easier, which means game design and balancing is easier. It also allows me to data-drive the game a lot more, which means more interesting entities and game situations.
Added timer-based summoning queues
Both heroes and minions take time to appear. Minions are summoned and there is a summoning bar that lets you know how finished the current summon is. By using the same summoning queue code, I now have a Village which pops out heroes over time.
Timers seemed like a special case of general triggers. It would be nice to have dwarves pop out of caves if any entities come near or have other similar scripting in the game, but my initial attempt at general triggers might have been trying to do too much. Maybe for another game.
What’s Next?
The game is still silent, so eventually I would like to add some sound effects and music. Animations and special effects would really punch up the visuals, which need a consistent art direction. It’s all functional programmer art and will get replaced.
But the biggest thing left to do is improve the AI. Dragons can attack from distance, yet they still try to run up to the heroes the way melee fighters do. Also, entities tend to bunch up. 10 orcs attacking a hero tend to look like a single orc attacking the hero, and it is hard to see what’s happening.
My initial attempt at solving these problems resulted in unacceptable slowness last week, but I’ve identified what’s going on and think I have a fix for it.
But hey, this is AI work. I already know I can’t expect that I’ll figure it out in a matter of hours or days. There’s going to be a lot of changes, tweaks, and fixes until it looks right.
And besides game development work, there’s the work of marketing and selling the game. There’s a “Stop That Hero!” Facebook page, and I just sent out a newsletter to my list announcing the upcoming release. I’m hoping to get a pre-alpha release out soon.
4 replies on “Stop That Hero! Development Summary”
Any reason you wouldn’t use SDL_HWSURFACE instead of SDL_SWSURFACE? I would think you would want to take advantage of any hardware acceleration that is available…
Also, regarding the pie interface, you could still clamp it to the edge of the window, the way operating systems do with right-click menus. It doesn’t always have to open perfectly centered under your cursor.
I didn’t notice any difference when I implemented it before. It could have to do with the fact that I’m developing on a Linux-based system where it doesn’t matter, and maybe it makes a difference on Windows, but I’ll worry about it if I run into issues later.
As for pie menus, clamping COULD work, but you lose one of the benefits of pie menus: muscle memory. If I click on a tower and always move the mouse left a small amount to click the Summon Orc button, it would be frustrating if I had to remember that clicking the tower in the top right corner forces me to move down and left to do so. If I don’t remember, I might accidentally click a different button. It seemed too frustrating a problem to worry about with this one-screen, no-scroll interface. Any fix would necessarily be a trade-off, and I decided not having it at all would be best to avoid violating any usability expectations.
Depending on what you are doing with your surface, SDL_SWSURFACE could be faster, i.e., if you are using per-pixel alpha or locking/unlocking it a lot.
Also, doesn’t SDL_DOUBLEBUF only apply to a hardware surface?
And does SDL_SRCALPHA do anything as a flag to SDL_SetVideoMode?
I sorta had the same idea as Troy, but don’t just clamp the pie menu, warp the mouse too. The whole menu should appear on the screen no matter where you click (clamping or always in the center) and you retain ‘muscle memory’ (warp the mouse to the center of the menu every time).