tag:blogger.com,1999:blog-28851676052139769152009-06-04T16:02:50.831-07:00Aspen Street GamesNews, opinions, and other assorted writings on independent game development.Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.comBlogger17125tag:blogger.com,1999:blog-2885167605213976915.post-25398101391879077772009-02-15T21:06:00.000-08:002009-02-15T21:32:10.231-08:00Three-Day Weekend SVN LogblogI 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 <span style="font-style:italic;">game</span>.<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r1059 | Administrator | 2009-02-07 18:59:41 -0800 (Sat, 07 Feb 2009) | 2 lines<br /><br />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.<br />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.</span><br /><br />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.<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r1070 | Administrator | 2009-02-09 01:21:06 -0800 (Mon, 09 Feb 2009) | 1 line<br /><br />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.</span><br /><br />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 <span style="font-style:italic;">because</span> 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).<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r1092 | Administrator | 2009-02-15 16:37:46 -0800 (Sun, 15 Feb 2009) | 1 line<br /><br />Implemented AI weapons and a very simple AI attack task.</span><br /><br />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.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-2539810139187907777?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-81848893984938888182009-02-03T11:44:00.000-08:002009-02-03T11:47:24.432-08:00Code as Art<span style="font-style:italic;">Reposted from a TIGForums discussion, in response to the assertion that programming is more frustrating than other creative endeavors</span><br /><br />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.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-8184889398493888818?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-8907897448430943082009-02-02T00:01:00.001-08:002009-02-02T00:25:20.140-08:00I 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:<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r1024 | Administrator | 2009-01-26 20:55:22 -0800 (Mon, 26 Jan 2009) | 1 line<br /><br />Fixed bug trying to spawn ammo classes while serializing in a world. Protecting against similar cases in the future with a spawning "semaphore".</span><br /><br />1024th checkin. I sort of wish it had been a more momentous change than a simple bug fix.<br /><br />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 <span style="font-style:italic;">did</span> 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.<br /><br />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.<br /><br />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.<br /><br />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.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-890789744843094308?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-30957965150504073502009-01-13T09:56:00.000-08:002009-01-13T09:57:37.406-08:00<span style="font-style:italic;">Reposted from a TIGSource thread on the "timeline of programming," i.e., how people got into this hobby and how long it took:</span><br /><br />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).<br /><br />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++.)<br /><br />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++.<br /><br />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.<br /><br />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++).<br /><br />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.<br /><br />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.<br /><br />tl;dr: It took me about 18 years to get my black belt in game programming, and that's just the beginning.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-3095796515050407350?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-92074634398494601302009-01-04T01:09:00.000-08:002009-01-04T01:16:38.251-08:00New Year's SVN LogblogI've got a few interesting developments on the engine to catch up on here eventually, but for now, here's a milestone:<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r1000 | Administrator | 2009-01-04 00:58:09 -0800 (Sun, 04 Jan 2009) | 1 line<br /><br />Fixed quickturning while quickturning.</span><br /><br />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.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-9207463439849460130?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-47349976378452782662008-11-29T13:58:00.000-08:002008-11-29T14:24:51.015-08:00Weekend 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...<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r954 | Administrator | 2008-11-17 22:20:42 -0800 (Mon, 17 Nov 2008) | 1 line<br /><br />Refactored a bit more to commit to a real breadth-first sector traversal. Has same known issues but I feel better about it.<br />------------------------------------------------------------------------<br />r953 | Administrator | 2008-11-17 21:58:47 -0800 (Mon, 17 Nov 2008) | 1 line<br /><br />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.</span><br /><br />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.<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r957 | Administrator | 2008-11-19 22:58:51 -0800 (Wed, 19 Nov 2008) | 1 line<br /><br />Added support for attaching ConcreteEntities to each other.<br />------------------------------------------------------------------------<br />r956 | Administrator | 2008-11-18 21:13:00 -0800 (Tue, 18 Nov 2008) | 1 line<br /><br />Added composite collision for doing higher detailed traces and getting region information from entities.</span><br /><br />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.<br /><br />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.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-4734997637845278266?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-70516402338631058452008-11-10T22:55:00.000-08:002008-11-10T23:00:27.946-08:00Not-Quite-Weekend UpdateI 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.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-7051640233863105845?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-54432666356194603382008-11-02T01:24:00.000-07:002008-11-02T01:36:08.981-07:00Weekend non-updateThis week has been mostly slow progress on the Strange Visit maps. I realized from working on this project that I needed to structure my Blender objects better, so I spent several hours reorganizing the meshes and materials I'd already built. It was a lot of time spent with no apparent gain, but it will hopefully save me some time as I polish the assets in the future. I'm looking forward to wrapping this thing up ASAP so I can get back to working on my primary project, but it has been useful to make a proper level in my engine and work out the kinks.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-5443266635619460338?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-27351172851673209072008-10-28T11:38:00.001-07:002008-10-28T11:46:59.642-07:00One of those days...The collision bug I mentioned last time turned out to go deeper than I'd realized. At the lowest levels of my swept ellipsoid tests, I transform the ellipsoid into a unit sphere and transform each triangle in each collision mesh into the same space as this sphere. It sort of normalizes and simplifies the math. So then I sweep this sphere against the plane of the triangle, and if there's an intersection, test that point for containment in the triangle. That was where I thought things were going wrong before, but it was actually because of bad results from the sphere-plane sweep. It took me several hours trying various permutations of potential fixes on a half page of code before I finally rewound, started fresh, and ended up with a fix that I swore was one of the first things I had tried.<br /><br />That's the frustrating side of programming. Hard-to-debug problems without obvious causes, where there's nothing to do but keep hypothesizing about why it's broken, applying a patch based on that theory, and then hammering on it to see if it holds. Fortunately, days like that aren't as common as the good, fun days where everything just works. Sometimes, though, we just have to dig in and fix nasty bugs. That's what really separates a good program from a bad one, regardless of the programmer. It's still pretty satisfying when it's finally fixed; in this case, I can walk through the 3D world and trust that it's solid again. That's a nice feeling.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-2735117285167320907?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-54984334555418856212008-10-26T03:22:00.000-07:002008-10-26T03:34:39.447-07:00Weekend SVN Logblog, (Oct. 26, 2008)Last week I played Fable II. The end.<br /><br />Okay, maybe my productivity this past week wasn't <span style="font-style:italic;">that</span> bad, but it sure feels like it. Maybe a review of my recent checkins will prove me wrong.<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r905 | Administrator | 2008-10-26 00:38:40 -0700 (Sun, 26 Oct 2008) | 3 lines<br /><br />Fixed a bug with point-in-triangle testing (I wasn't checking that the point was in the plane).</span><br /><br />I posted a pre-alpha build of Strange Visit on the TIGSource forums, and at least one user called me out on the collision bugs. I knew they were there, but I was trying to pretend they weren't that big of a deal. Of course, it was--worst case, the player could become completely stuck in the geometry of a map and be unable to move. I eventually tracked it down to a point-in-triangle test that was giving false positives because I wasn't first ensuring that the point was actually in the triangle's plane. This is was happens when I copy algorithms wholesale from other sources and don't fully grok their proofs. Lesson learned.<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r901 | Administrator | 2008-10-25 15:50:58 -0700 (Sat, 25 Oct 2008) | 2 lines<br /><br />Bunch of work on SV exterior.<br />Fixed endless recursion bug in sector traces.</span><br /><br />Most of this week was spent blocking out the level for Strange Visit, and it's finally at a decent state. Working on it has continued to reveal bugs relating to sectors and portals; in this case, a stack overflow when a ray was traced through more than one portal such that it ended up back in a sector it previously traversed. This is why it's important that I'm finally making a "real" level instead of just simple test cases.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-5498433455541885621?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-27880728991166302802008-10-19T13:53:00.000-07:002008-10-19T14:41:09.005-07:00The Weekend SVN Logblog (Oct. 19, 2008)It was a busy week for my hobby projects. I made some substantial performance improvements to the engine and started a small side project that has been shaking out bugs like crazy. Let's take a look:<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r858 | Administrator | 2008-10-14 00:40:52 -0700 (Tue, 14 Oct 2008) | 1 line<br /><br />Big particles refactoring, so that particle systems don't allocate and create new vertex buffers every frame. Sadly, locking and copying doesn't seem much faster.</span><br /><br />I've been worried about the performance of my engine for a little while now; I was only getting 20-30fps in Release mode, and the rates in Debug were almost unplayable. Profiling suggested that particle systems were to blame, so I looked into it and realized that I had left particles in a very hacky state, intending to come back and clean it up if performance started to degrade. Every frame, for every particle system, I was allocating new vertex arrays and creating new Direct3D vertex buffers from them. I rewrote it to reuse a persistent vertex array (updated each frame) and to lock and modify a dynamic Direct3D vertex buffer for each particle system. As the changelog suggests, it wasn't actually a great performance gain, but it helps a bit and I feel better about the code. I still hate having to deal with dynamic Direct3D objects when resetting the device, though.<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r860 | Administrator | 2008-10-14 22:57:51 -0700 (Tue, 14 Oct 2008) | 1 line<br /><br />Added some HTTP socket stuff for eventually doing leaderboards, stat tracking, whatever.</span><br /><br />Inspired by J. Kyle's leaderboard solution for <a href="http://www.j-kyle.com/arc">Arc</a>, I decided to dig into WinSock and get some communication going with my web server. I found it surprisingly easy to establish the connection and send HTTP requests, and before long, I had a sample program sending a POST request to a Python CGI script and getting back a meaningful response. I'll have to revisit some of this when it comes time to actually write the leaderboard code, because I'm not actually parsing the response yet, but for a first pass at something I had no prior experience with, I was very satisfied with the time it took to get something running.<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r862 | Administrator | 2008-10-15 06:14:38 -0700 (Wed, 15 Oct 2008) | 1 line<br /><br />Added core of a new profile system. None of the UI is started yet, and profiles can't be deleted, but the folder structure and config files are all working as intended.<br /><br />------------------------------------------------------------------------<br />r866 | Administrator | 2008-10-15 18:30:50 -0700 (Wed, 15 Oct 2008) | 1 line<br /><br />Short of finding and fixing bugs, profile system is done.</span><br /><br />A profile system is something I've been thinking about for a while now, but I kept debating its usefulness. Basically, it provides a named container for saved games and player options, so that multiple players sharing a computer can have their own personal configurations. The leaderboard concept (coupled with a sick day that gave me hours and hours to work at home) finally provided the catalyst for doing this, because I wanted to have a constant user name available instead of making the player type a name every time he submitted a score. Despite it being a fairly significant chunk of work, I managed to finish the bulk of the profile system in just over twelve hours on Wednesday, with a last few fixes coming in just before midnight.<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r871 | Administrator | 2008-10-16 19:52:25 -0700 (Thu, 16 Oct 2008) | 1 line<br /><br />Added typed EIDs.</span><br /><br />This is a small one, but significant for code readability and type safety. I previously just used unsigned integers (EIDs, or Entity IDs) as handles to game entities. It's a simple abstraction trick: these EIDs are used as keys to look up the Entity pointers in a map, so a deleted object will return NULL and I avoid dangling pointers. In the past, I would simply static_cast the returned Entity* to whatever type I knew the handle was meant to represent, but I was never happy with that solution. Now I have a small TypedEID class, templated on the type of Entity it refers to. This class mostly just wraps the basic EID functionality, but it returns a pointer to the correct type (just static_cast still) and also has a slightly more expensive checked accessor that returns NULL if the actual type of the entity does not match the class template. (This requires run-time type information, but I've previously rolled my own RTTI implementation, so that was free.)<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r881 | Administrator | 2008-10-18 16:45:22 -0700 (Sat, 18 Oct 2008) | 1 line<br /><br />Some initial work on the Commonplace Compo map.</span><br /><br />I've been trying to get involved in the indie games scene a bit more, and to that end, I'm entering the TIGSource Commonplace Book Competition. It's a very casual competition: no entry fees, no prizes--mostly just a deadline so people actually get things done. The theme is H. P. Lovecraft's "commonplace book," a journal in which he jotted down ideas and story fragments that might eventually have been developed into fuller stories. I chose the following quotation to base my game upon:<br /><br /><span style="font-style:italic;">30 Strange visit to a place at night--moonlight--castle of great magnificence etc. Daylight shews either abandonment or unrecognisable ruins--perhaps of vast antiquity.</span><br /><br />Strange Visit, as I'm calling it, will be a small game built on the engine I've already got. Because I don't have any real gameplay systems yet, it will about atmosphere, exploration, and discovery instead of rules of play. Developing a real level has uncovered some latent bugs that were hiding in my engine (especially with regard to sectors and portals), but I've been steadily squashing those as they arise.<br /><br />I expect that the next few weeks will be consumed almost entirely with content development for Strange Visit. I'll return to programming around Thanksgiving, after the competition deadline, and finally start developing some gameplay systems (weapons, inventory, AI, etc.).<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-2788072899116630280?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-26989822968045285712008-10-17T00:08:00.001-07:002008-10-17T08:22:39.623-07:00Don't Be Stupid!I'm in the process of changing web hosts, so this won't post until probably a few days from now. Midphase was recommended to me, and their basic web hosting package looked like a really good deal, so I took the plunge. Their service has been prompt so far and the controls are way better than my last provider, so I'm happy. On a side note, I still hate the way domain names (and in this case, the transferring thereof) are handled.<br /><br />But that's not why I'm writing this. No, today I learned an important lesson: <span style="font-style:italic;">don't be stupid</span>.<br /><br />I have this nifty little "configuration variables" system in my engine. It primarily lets me define key-value pairs in a config file (just like an INI) and access those values by name at runtime, like so:<br /><br />float Foo = ConfigManager::GetFloat( "Foo" );<br /><br />There's many reasons why data-driven values are preferred to hard-coded "magic numbers" in games, and I get quite a lot of use out of this system. In fact, as performance on my game began to decline, I suspected it might be due to my rampant use of config vars all over the code base.<br /><br />What happens when this config var is accessed? The name ("Foo") is passed down to the accessor function, where it is converted into a hashed value (that is, reduced from a string of letters to an integer). That hash can be quickly compared against all the hashed names in the massive table of config vars to find the requested variable. If it is found in the table, the function asserts that the config var is the type that was requested (in this case, a floating-point value) and returns that value to the caller if it's valid. A default value may be used in case the value was not found or was of the wrong type.<br /><br />A metaphor for non-programmer types: You go to pick up your jacket from the dry cleaners. You supply the clerk with some information about your jacket, and they go and find it on the racks and bring it back to you. But imagine that instead of handing the clerk a stub with a number that matches the tag they left on your jacket, you hand them a piece of paper on which you've written a riddle. When solved, the riddle reveals the number that matches the tag on your jacket. You can still go and get your jacket from the dry cleaners just like before, but now the clerk spends all her time solving riddles. When a flood of customers starts arriving, she's so backed up solving the riddles that she can't deliver everyone's garments in the expedient fashion to which they're accustomed.<br /><br />Back to programmer land. Solving the riddle is a metaphor for the hash function. If the system is using small, simple hashed values to find the requested items, why are we giving it big, long strings? These are just riddles that it needs to solve before it can do the task that it was meant to do.<br /><br />So, bringing it all back to that important lesson: <span style="font-style:italic;">don't be stupid</span>. You would never expect the dry cleaners to solve a riddle to find your jacket, and it was just as stupid of me to be hashing strings inside the config var accessor functions instead of just using a hashed value as the given key.<br /><br />A conclusion! It was an epic two-hour refactoring job to actually fix this in my game. Every case where I used a string literal (like "Foo" in the earlier example) was replaced with a static hashed name so that it would only have to be computed once. This one simple fix <span style="font-style:italic;">doubled</span> my frame rate in Release mode. Don't be stupid.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-2698982296804528571?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-49186104240163379192008-10-13T16:43:00.001-07:002008-10-13T16:55:21.459-07:00RantI realize that EA/DRM anger is so last month, but I recently came across an interesting case that makes me question the honesty of EA's promises to the Spore community.<br /><br />In an <a href="http://multiplayerblog.mtv.com/2008/09/16/spore-drm-update-ea-loosening-one-restriction/">interview</a> with MTV Multiplayer, an EA representative promised that:<br /><br /><span style="font-style:italic;">If we were to ever turn off the servers on the game, we would put through a patch before that to basically make the DRM null and void. We’re never walking away from the game and making it into a situation where people aren’t going to be able to play it.</span><br /><br />This is a decent way to pacify a very real concern amongst gamers, that the products they buy might be remotely deactivated at some arbitrary time in the future. This will surely happen eventually, and nothing is ever lost on the internet, so the remaining Spore players will hold EA to this. Whether EA keeps their word (or are even around anymore, or can find developers to make the patch, etc.) remains to be seen. But there's a way EA can really secure the faith of gamers, <span style="font-style:italic;">today</span>.<br /><br /><span style="font-style:italic;">Patch your games from ten years ago.</span><br /><br />Show your concern by fixing the DRM-related problems that plague older games. Off the top of my head, I can name two EA-published games from several years ago that no longer run properly because of the existing copy protection: System Shock 2 and Clive Barker's Undying. I know, because I've recently tried to play both and been thwarted by SafeDisc protection that won't validate on my newer machine even though I own a legitimately-purchased copy.<br /><br />Of course, there are illegal ways to circumvent the problem. There are several SafeDisc cracker programs that will get me playing my old games in no time. But that's not the point. The point is that, <span style="font-style:italic;">right now</span>, there are games published by EA that I purchased but cannot legally play because of DRM measure. If EA wants anyone to take their new promises seriously, they need to first fix the problems from years ago.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-4918610424016337919?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-18505824560460026992008-10-13T11:51:00.000-07:002008-10-13T13:23:08.541-07:00The Weekend SVN LogblogSo I'm going to try something new that I've been meaning to do for a couple of weeks now. Every weekend, I'll post comments regarding interesting developments on my hobby project from the previous week. I <span style="font-style:italic;">should</span> have posted this last Friday or Saturday, so I'm off to an auspicious start.<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r845 | Administrator | 2008-10-06 22:00:09 -0700 (Mon, 06 Oct 2008) | 1 line<br /><br />Early work on behavior trees.<br />------------------------------------------------------------------------<br />r853 | Administrator | 2008-10-08 23:05:51 -0700 (Wed, 08 Oct 2008) | 1 line<br /><br />Finished the fundamental composite behavior tree tasks.</span><br /><br />(Yes, I log in as Administrator. What of it?)<br /><br />So my big accomplishment last week was doing a first-pass implementation of behavior trees for AI decision-making. I spent a while debating what I would use for behaviors in this project. I had prior experience with Goal-Oriented Action Planning, but I didn't anticipate needing the benefits of a planner. Behavior trees seemed more useful for this game (a fairly straightforward shooter), and it gives me a chance to learn something new. I'm following pretty close to behavior trees as defined in AlexJC's articles (at AiGameDev and in the latest AI Wisdom book), and I've finished implementing the basic composite tasks (Sequences, Parallels, and Selectors) that will be the core of every tree. I've also implemented a very simple movement task as a proof of concept, so I now have a non-animated, faceless, blocky character proxy turning and navigating through my world. It's uncanny.<br /><br /><span style="font-style:italic;">------------------------------------------------------------------------<br />r848 | Administrator | 2008-10-07 23:07:37 -0700 (Tue, 07 Oct 2008) | 1 line<br /><br />Added option to toggle vibration. Changed all visible instances of the word "rumble" to "vibration" (because rumble is a Nintendo-specific term).</span><br /><br />I think I'm right about this, but...? It can't hurt, anyway.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-1850582456046002699?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-44609801936404960742008-09-27T01:27:00.000-07:002008-09-27T01:28:49.311-07:00Me, Myself, and AI<span style="font-style:italic;">(I just made myself cringe writing that title. I'm sorry. The following is reposted from my introduction at the AiGameDev forums.)</span><br /><br />Hi, I'm David. I've been programming games for fun for as long as I can remember and professionally for the last two years.<br /><br />AI became a passion of mine largely due to its mystifyingly transparent nature. Even before I understood the math behind it, I could look at a textured 3D model in a game and understand that it was made of triangles and texels and projected onto the screen. AI, by contrast, was just this magical black box, responding in sometimes wildly unpredictable ways to the player. Playing Thief was a landmark moment for me; although its AI was generally predictable and could be gamed with relative ease, it sold its characters as believable human beings with a combination of interesting behaviors and a near constant stream of barks that relayed everything the player needed to know about the AI's state. Years later, when I had begun to study and implement AI behaviors, I revisited Thief and began to see how AI was not simply a programming endeavor but a cross-section of all disciplines of game development, a massive collaborative effort of engineering, animation, design, and audio.<br /><br />I attended the outstanding Guildhall at SMU program as a way to catch up on professional-level game programming and eventually break into the industry. Notably, my application to the school and both of my individual projects were focused on AI. For my application, I wrote a little grid-based "mini-Thief" game. It was my first time implementing (and even learning about) the A* algorithm. Eye-opening stuff at the time. Halfway through my education there, I revisited the Thief concept in 3D and with more complex group behaviors. As I scoured the internet for interesting AI behavior topics for my Master's thesis, I came across Jeff Orkin's publications on goal-oriented action planning. I was intrigued and ended up writing an UnrealScript-based implementation of GOAP and building a hierarchical squad behavior system on it. (Jeff even agreed to advise on the project--thanks!)<br /><br />Then I entered the real world of professional game development. Of course, I didn't expect to jump straight into an AI dream job, and in fact, I barely touched gameplay code let alone AI code at my first job. I was disappointed at first, but it gave me a great opportunity to explore other aspects of game development that I had largely overlooked before (especially audio, but that's another story). In the meantime, I took on two personal ventures: first, a hobby engine that would eventual require some custom AI, and second, writing an article for the fourth installment of the AI Wisdom series. For the latter, I pared down my Master's thesis, focusing on the original aspect of hierarchical squad behaviors using GOAP. (Again, thanks to Jeff for encouraging me to do it, and thanks to Kevin Dill for his assistance on our section of the book.)<br /><br />I've continued to work part-time on my hobby project, and finally, more than a year later, I'm beginning to implement some AI. I've just got pathfinding over navigation meshes working and am evaluating whether I want to use GOAP again or whether Alex-style behavior trees might be better suited for my needs. In the meantime, I've found an awesome new job where I'm able to stretch my engineering muscles and work on a huge amount of exciting tasks including some fun AI behaviors. With this recent rekindling of my interest in game AI, I decided it might be a good time to check out the community here and get involved.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-4460980193640496074?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-39707713400765489302008-09-09T21:57:00.000-07:002008-09-09T23:22:16.146-07:00Content Pipelines and Build Processes (Part One?)Perhaps the most important thing I've learned since graduating from the Guildhall and working in a couple of professional studios is the effectiveness of a good content pipeline and build process. These are things that were mentioned in passing at Guildhall lectures but that didn't register with me at the time. Since then, two things have happened to elucidate to me why content pipelines matter. The first was working with a bad pipeline and worse build process at my former company. The second was when I needed to roll my own pipeline for my hobbyist engine.<br /><br />To be clear, what I mean by content pipelines and build processes are the answers to the questions "How do you get data into your game?" and "How do you produce code and data builds?" respectively. The two problems are closely related, but build processes are sometimes limited in scope to only building code, with data being processed at a different time (especially when baking content for consoles).<br /><br />Given the popularity of the Unreal Engine, it's worth looking at how their content pipeline works. The decision was made long, long ago for the original Unreal that the game's raw and baked files should be the same (at least for levels and asset packages). There's a lot of interesting implications to that, and it's probably worth arguing whether the original rationale for this decision is still valid today, but that's the way it has stayed for over ten years of development of the engine. What it means with regard to the pipeline and build process is that there <span style="font-style:italic;">is</span> no process.<br /><br />In Unreal, content creators import raw files (textures, meshes, etc.) and produce package files--binary bundles that blur the line between raw and baked because they can be edited in UnrealEd but are also ready for use at runtime. Likewise, level files never need to be exported or baked into any other form; the raw level files that designers work on are the same files that the player loads in the finished game. Of course, Unreal does have baking of a sort, but it happens in-editor, when the designer clicks the Build button, instead of as an automated process, and the product is saved into the original file. For PC-based Unreal games, that's more or less all there is. Iteration time is fast, because all the data is already in its final form. For console games, the data will be baked for the target platform, which means fixing the endianness, building seek-free packages for fast loading, etc. It's a bit slower but not terrible, and the baked data can be cached and only rebaked when it changes, so iteration time is still relatively light.<br /><br />In stark contrast to the Unreal model is the pipeline and build process used at my former place of employment. We used an in-house-developed engine, and there seemed to have been no clear vision as it grew, resulting in a monstrous pile of conflicting tools and methodologies. That doesn't mean that the general design of the pipeline was bad, it was just burdened with years of baggage from hastily-made, myopic decisions.<br /><br />For most assets in this engine, the raw files were standard filetypes (TGAs for textures, AIFF for samples, INIs for configurations, etc.). The rest were custom text formats for worlds, particle definitions, and other non-standard asset types. (Unrelated note: As far as I recall, there were no custom binary formats; however, the text files that the world editor produced were indeterminate, with the contents being ordered apparently randomly each time the file was saved.) Because the raw files and baked files were different formats, every file had to be baked before it could be viewed in the game. That's pretty common. Making it more difficult was a complex dependency chain that I have to assume was a too-early step to produce seek-free packages. If a texture was changed, it was not merely enough to rebake the texture; every world, mesh, or UI element that referenced that texture needed to be rebaked. And there was no automated dependency checking. And the dependency graph was so convoluted that no programmer on the team understood it, not to mention the content creators. The implications? Almost every time a content creator changed anything, they rebuilt everything. That was an iteration time of almost two hours, sometimes just to verify something as simple as changing a texture.<br /><br />Ironically, I decided after that experience to implement a very similar pipeline in my hobby engine. It's a fairly obvious paradigm: develop raw files, bake them, run the game with the baked files. Having noted that the problems I observed on the aforementioned project were due to other issues than this core design, I figured that I could implement a simple system this way and use my experience to avoid the pitfalls. In practice, it has worked surprisingly well. Given that my only target platform is the PC, I don't have to worry about seek-free packages, so there are no dependency issues in the build process. When I change a texture, I only need to rebake the texture file. Worlds and meshes simply reference the texture by name instead of storing the texture inline. (As an aside, it seems that it would be far simpler to do this seek-free stuff as a late post-bake step, the way Unreal does it. I haven't thought it through completely, but I can't see why it would be done any earlier.) I use timestamp checking to determine what needs to be rebaked, so builds are minimal. Iteration time is only an issue when building world files, because of the amount of heavy calculations they need for lighting. Most other changes take less than a second to build. After baking, I can either use the loose baked files to run the game or zip everything up into compressed package files.<br /><br />There's more I could say on this subject, so I'll probably be following this up with a second part eventually. I'd like to write about the horror of the automated build process on my last project and delve a bit further into my own system. I'll also try to revisit the loose ramblings from this article and tie it together into a more concise evaluation of how each engine answers the questions I posed at the start.<br /><br />For more information on content pipelines (including some refreshing examples of pipeline design with some forethought), check out these slides and audio from Gamefest 2008: <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=7B506E72-96DF-434A-BC35-BD0B4D1765B3&displaylang=en">Next-Gen Content Pipelines: A Study of 1st Party Titles</a><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-3970771340076548930?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0tag:blogger.com,1999:blog-2885167605213976915.post-45069835159042044212008-08-25T20:51:00.000-07:002008-08-25T21:28:16.013-07:00Blogs Are SillyThis is my introduction of sorts. I'm not of the opinion that every chump on the intarwebs really needs a blog, but I'm also not a web developer and enjoy easily publishing things without having to do any real work. It's a little bit backwards that I can make a game engine in C++ but the mere sight of XHTML/CSS makes my head spin. Incidentally, I don't really have a plan for this blog. I don't actually anticipate (gasp!) <span style="font-style:italic;">readers</span>. Eventually I'll be closer to releasing a game, and I'll announce things here. For now, I may just post random technical updates as I find interesting problems to tackle.<br /><br />So, a little bit about me. I'm a game programmer (or just "developer", but I'll get to that). Have been since birth, or as near as I can remember. I grew up with BASIC programming, dabbled in animation, modeling, and level design during high school, and finally came back to programming. One BS in Computer Science later, and I was off to the <a href="http://guildhall.smu.edu">Guildhall</a> to learn what academia doesn't teach about software development and games. Now I'm employed at a very cool studio with two shipped titles under my belt.<br /><br />But a brief biography doesn't really say all that much about me, and I've still got that "developer" comment to get back to. I'm borderline obsessive about game development. I program games for my job, then come home and unwind by programming games. Couple that with a real thirst for knowledge (increasingly so since I don't have grades that depend on it) and you've got a guy who wants to learn how to do everything in games.<br /><br />It's not realistic, practical, or anywhere near a good idea that one person could touch every system in a modern game's code base. There's hundreds of thousands of lines of code in even the smallest of engines, and the accumulated knowledge behind any given system could fill books. So we specialize. Gameplay programmers, graphics programmers, AI, audio, physics, etc. And this isn't a phenomenon unique to engineering; artists specialize, designers specialize... There are simply too many kinds of tasks in modern game development for any one person to excel at all of them. But that doesn't mean we put blinders on. In order to do our jobs effectively and to communicate amongst disciplines, the best of us keep informed about other aspects of development.<br /><br />In my case, that means learning everything about everything in game development, to include tangentially related fields such as music composition. Yes, it's an impossible goal. I'll never even begin to approach it, and that's the point. I'm not a good artist (yet). I haven't designed a good level (yet). I'm actually decent at music composition, albeit woefully out of practice. But I want to be great at all these things, and given enough time, I know I can be. Right now, professionally, I'm a programmer, and I'm very happy with that. But sitting here at my desk at home, I'm just a "developer." I design, I implement, I polish. It's old school. If I need some art, I make some art. And I learn something while doing it.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2885167605213976915-4506983515904204421?l=www.dphrygian.com%2Fnews'/></div>Davidhttp://www.blogger.com/profile/11242107976166975748noreply@blogger.com0