Sunday, February 15, 2009

Three-Day Weekend SVN Logblog

I passed another milestone today: fifty thousand lines of code written. I've hit a renewed stride over the past week or so and have been continuing to optimize while also implementing several features that bring the project closer to being a game.

------------------------------------------------------------------------
r1059 | Administrator | 2009-02-07 18:59:41 -0800 (Sat, 07 Feb 2009) | 2 lines

Finally implemented my old idea to allocate all the mostly-static stuff that is loaded in Game::Initialize() and while loading worlds in a separate place from the main allocator, which improves block seek time substantially.
Also implemented a very easy #define switch to turn off my memory manager for Brass City, so I can compare performance against the default allocator and try to justify having my own at all.


This was a huge optimization that I had considered making months ago and then left alone because it seemed difficult to implement. My custom allocator uses a single linked list of blocks, and as the number of allocations grows, it takes longer and longer each time to iterate over that list and find the first free block of the right size. I realized that I very easily use a temporary, scoped override to allocate all my static content somewhere else entirely, so that allocations made while the game is running have practically nothing to iterate past. This was the last and biggest of several optimizations I made last week; after making this change, memory is no longer a bottleneck and the game is much, much faster.

------------------------------------------------------------------------
r1070 | Administrator | 2009-02-09 01:21:06 -0800 (Mon, 09 Feb 2009) | 1 line

Added the persistent weapons stuff I'd been thinking about doing for a while. Weapon and ammo equipped can persist across level transitions by use of some scripts.


This is just one of a large number of gameplay changes I've made recently. It is a solution to carrying weapons between levels. Because my levels are completely discrete units, anything that is supposed to persist across level transitions has to be stored before the transition and restored afterward. In the case of the player's health, score, etc., I can simply store a number and set it on the newly-constructed player in the new level. Weapons are more complicated, because I have to reconstruct the set of weapon objects, all the ammo objects used by the weapons, reassign the amount of ammo remaining in each weapon's magazine, and make sure that whichever weapon the player was actively holding is the one that is selected in the new level. There was no especially clever trick to this or apparent generalization to the problem that could save me time now or in the future; I simply had to write a bunch of code to store the large amount of relevant data and set everything back up again on the other side. In fact, it's really only worth mentioning because there was no clever solution; sometimes the blunt force approach is the only way to go (and I'm getting into the realm of special case gameplay code where this sort of thing may become more common).

------------------------------------------------------------------------
r1092 | Administrator | 2009-02-15 16:37:46 -0800 (Sun, 15 Feb 2009) | 1 line

Implemented AI weapons and a very simple AI attack task.


This is the change that broke the 50K LOC mark. It's also especially significant to me because AI is one of the last remaining generic systems I need to write before I can start prototyping gameplay. There's a lot left to do here to make even a simple combative bot, but AIs can now aim and fire weapons at the player, which is one big step toward that goal. At this rate, I believe I might have a functional AI opponent within a week, perhaps, and from there, I can build out some test levels and start getting a feel for how the game will play.

Tuesday, February 3, 2009

Code as Art

Reposted from a TIGForums discussion, in response to the assertion that programming is more frustrating than other creative endeavors

I actually find similar challenges in writing code and composing music. I start with a basic idea in my mind of something I want to create. How a system should work, or how a piece of music should sound. Then I start building it, writing code or arranging chords and melodies. On a good day, it all just works, but sometimes things don't fit together so nicely: my interfaces aren't well-architected, or a harmony sounds dull and trite, or a matrix transformation isn't working the way I thought it should, or I can't find the right chord change to segue into the prechorus the way it sounds in my head. If the problem gets really hairy, I step through one line at a time in a debugger, or try every combination of notes until I find the right ones. And in both cases, I find that the more I practice, the more it comes naturally and I learn to anticipate and avoid the tricky problems in advance.

Monday, February 2, 2009

I was going to write a Weekend SVN Logblog, but it's useless to pretend those are actually weekly at this point, and I've made too many small, incremental changes over the past week to easily summarize with a couple of select entries. I will, however, post this because it was a huge milestone for me:

------------------------------------------------------------------------
r1024 | Administrator | 2009-01-26 20:55:22 -0800 (Mon, 26 Jan 2009) | 1 line

Fixed bug trying to spawn ammo classes while serializing in a world. Protecting against similar cases in the future with a spawning "semaphore".


1024th checkin. I sort of wish it had been a more momentous change than a simple bug fix.

Last weekend saw a huge system finally get added to the game: weapons! It actually took me by surprise the first time I ran the game with a proxy weapon mesh on-screen just how important the first-person view of a weapon (or any instrument in the player character's virtual hand) is for immersing the player in the game. Even before the weapon did anything, before there were animations or ammo classes or any of the myriad of details I've added in the last week, I was running around in this world with a simple, untextured revolver on-screen, feeling at last like I was a part of the game world.

I'm sure there's something meaningful to be said regarding the destructive nature of games that a weapon is critical to grounding a player in the world, but analyzing games in that fashion isn't my style.

Most of the rest of my week was spent either improving the game in small but significant ways (the camera topples over when the player dies, there's a Return to Title button on the pause menu, you can't save your game after being killed, etc.) or starting the arduous process of optimizing this whole thing. I made a couple of simple optimizations (not emptying and reallocating some large arrays every frame) that actually helped bring me back up to 60 Hz in my best case scenes. There's still a long way to go if I want this to perform well on older computers, but then again, I'm developing on a laptop that's over three years old, so my own machine keeps slipping further toward the low end of the spectrum. I guess that's not a terrible place to be--it keeps me honest in my expectations of the engine.

Finally, I added a race timer. It was a very simple class that took me maybe ten minutes to fully implement and test, but it was significant because it is one of a few gameplay systems to be designed specifically for my next game (as opposed to the engine in general) and brings me much closer to having a working prototype. In fact, as soon as I can hash out some more details on the broader AI architecture--sensors, behavior design, AI weapons--I'll be ready to put the code aside momentarily and build out my first real level for this game. I'm excited about this again.

Tuesday, January 13, 2009

Reposted from a TIGSource thread on the "timeline of programming," i.e., how people got into this hobby and how long it took:

I started "programming" when I was about 5 or 6 years old by copying simple GW-BASIC games out of 3-2-1 Contact! magazines. I'd make small changes to understand how it all fit together and eventually learned to write my own games (most of which were of the PRESS ENTER TO NOT DIE variety, but hey, I was 6).

I liked programming and dreamed of being a programmer on big commercial games (or as I said back then, "I want to work for Nintendo!"), but I lingered in BASIC purgatory for a while, mostly writing QBASIC games and eventually trying Visual Basic when they added VB DirectX hooks. I dabbled in level design and 3D modeling and animation, but that went nowhere. I knew that programming was what I really wanted to do, and if I was going to really make it, I needed to learn C++. (Bear in mind, this was around 1999--the current era of high-level languages with wonderful libraries wasn't what it is today. And I wanted to make big commercial games, which are still typically written in C++.)

My self-discipline back then wasn't as strong as it is now, and I never could take the time to learn C++. I enrolled in a Computer Science program at college where they offered a Java path (for most students) and a C++ path (recommended for students who already knew C++). It wasn't a great CS program. I spent two years in CS Java hell and eventually took an elective class that (unknown to me at the time) required all homework to be submitted as C code. So I finally, in the lamest way possible, wrote my first working C program and so began the long road into C++.

For the next two years, I wrote a mix of Java, C, and C++ for different classes, only vaguely grasping the differences between C and C++ and not really feeling like I was learning anything. Of course, CS projects are pretty far removed from games, and I finally realized that I just needed to man up, stop wasting time watching TV, and MAEK GAEM. I downloaded SDL, dug into the documentation, and made a bouncing ball demo. It had sprites moving around, it had keyboard input--once I could do that, I thought, it was a small step to make a game.

Meanwhile, I'd been looking at the Guildhall at SMU as a path into the games industry, but I didn't believe in myself. I didn't think I had what it took to be accepted there. On the other hand, I didn't want to program business applications for the rest of my life, and my only graduate school alternative was to follow my dad's steps and go to law school. I aced the LSAT--it's all just logic and any good programmer should do fine on it--but I had no passion for law. I wanted to make games. So in my senior year, I started cranking out game and tech demos with the intent of building a portfolio for entry to the Guildhall. Months of anxiety later, I was accepted to the Guildhall, but I still felt like I was behind the curve in game programming. I spent the months after graduation brushing up on the areas of C++ where I knew I was weakest (namely, the entirety of object-oriented programming in C++).

The Guildhall was an awesome experience for someone like me--spending all day every day immersed in programming and games and learning genuinely useful information from the teachers and classmates. It's what I imagined undergrad was like before attending and being disappointed at the lack of passion there. If you ever have the opportunity to spend two years with twenty other programmers equally as driven and enthusiastic about game programming as you, take it.

And so I graduated the Guildhall, got my job in commercial games, and continued to program independently on the side. I finally feel that I really grok C++, but I'm finding so much more to learn in related fields: I'm developing better build processes, getting excited about tools development and content pipelines for the first time, exploring shaders a bit more, and reading lots of papers on graphics and game AI.

tl;dr: It took me about 18 years to get my black belt in game programming, and that's just the beginning.

Sunday, January 4, 2009

New Year's SVN Logblog

I've got a few interesting developments on the engine to catch up on here eventually, but for now, here's a milestone:

------------------------------------------------------------------------
r1000 | Administrator | 2009-01-04 00:58:09 -0800 (Sun, 04 Jan 2009) | 1 line

Fixed quickturning while quickturning.


While the change itself is nothing momentous (a simple bug fix for a just-implemented feature that wasn't tested thoroughly enough), this marks the thousandth change I've checked in to the repository. I'll probably also post when I hit the 1024th checkin too, and maybe it will even be something worth writing about.

Saturday, November 29, 2008

Weekend SVN Logblog (Nov. 29, 2008)

Back from a bit of a hiatus from regular updates. I wrapped up Strange Visit last week and got around to finishing some engine tasks that had been on my plate since October, then took a break from all things develop-y for the week of Thanksgiving. Let's see what I was up to before that...

------------------------------------------------------------------------
r954 | Administrator | 2008-11-17 22:20:42 -0800 (Mon, 17 Nov 2008) | 1 line

Refactored a bit more to commit to a real breadth-first sector traversal. Has same known issues but I feel better about it.
------------------------------------------------------------------------
r953 | Administrator | 2008-11-17 21:58:47 -0800 (Mon, 17 Nov 2008) | 1 line

Changed portaling a bit to build a list of all visible sectors from a sector before rendering them. Now it's a weird cross between depth-first and breadth-first that I'm not quite happy with, but that fixes the bug I found tonight.


Just before finalizing Strange Visit (or actually, while I was playing the first release candidate, I think), I found noticed some weird behavior when looking through certain portals. I stepped into the code and realized that my fix for endless portal recursion from a few weeks ago was now causing some sectors to never be rendered. I started experimenting with ways to fix it and ultimately wound up changing a recursive algorithm to an iterative one (which effectively changes it from a depth-first traversal of the visible portals to a breadth-first traversal--it's all computer science class up ins!). There's still a known issue that could occur in a very contrived case, but I can design around that.

------------------------------------------------------------------------
r957 | Administrator | 2008-11-19 22:58:51 -0800 (Wed, 19 Nov 2008) | 1 line

Added support for attaching ConcreteEntities to each other.
------------------------------------------------------------------------
r956 | Administrator | 2008-11-18 21:13:00 -0800 (Tue, 18 Nov 2008) | 1 line

Added composite collision for doing higher detailed traces and getting region information from entities.


These are two tasks that I'd been thinking about since before starting Strange Visit, and I had been eagerly awaiting the end of that project so I could finally write these. Attachments isn't something I intend to use a whole lot, but there are occasions where it's very useful (like attaching a particle emitter to an object on fire). I had been procrastinating on the implementation for a while because I was concerned about edge cases related to the collision on attached objects, but there ended up being fewer of those cases to deal with than I expected. Given that I have only a couple of expected uses for attachments, it should be fine.

The other task listed there was composite collision bounds for high detail objects. Because they work decently in many cases and because I don't want to introduce another order of complexity by using various kinds of collision geometry, almost every game object in my engine uses ellipsoids for its collision proxy. This works fine for low-detail objects--it doesn't really matter to me if a bottle on a table doesn't have pixel perfect collision. It does matter if the enemy character I'm shooting at doesn't get hit when my reticle was clearly on him. Most modern games solve this problem by using a collision proxy mesh built from connected rigid bodies (oriented bounding boxes) like an artist's mannequin. I prefer to do the Simplest Thing That Could Possibly Work (it's #1 on the list of five core values I defined almost two years ago), or in less lazy terms, find the solution that gives the best return on investment. For the kind of fast-paced shooter I'm making, I don't need that much precision, and it's a lot more work to do. So I settled on simply making a small list of composite ellipsoids centered about the Z-axis. My basic human shape uses a sphere for the torso, a slimmer ellipsoid for the legs, and a small one on top for the head. Pixel-perfect it is not, but it gives me more control than a single shape, lets me use named regions for damage adjustment (like high-valued headshots), and best of all, took about 30 minutes to implement fully. I think I've spent longer writing about it here than it actually took to code. That's a win in my book.

Monday, November 10, 2008

Not-Quite-Weekend Update

I guessed that it wouldn't take too long before I fell behind on these updates. In fairness, I haven't been doing much of interest to anyone including myself; mostly just slogging through a bunch of art that needs doing before I can call Strange Visit complete. I usually enjoy unwrapping, and texture painting can be fun when it just flows naturally, but I've just been trying to get as much done as fast as possible, so it's a bit of a chore. If time allows, the game still needs music and sound effects. I'm looking forward to the deadline in part so I can get back to programming, but mainly because this has become a six-week interruption from my regular work that I didn't anticipate.