<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>luminance &#187; design</title>
	<atom:link href="http://www.luminance.org/tag/design/feed" rel="self" type="application/rss+xml" />
	<link>http://www.luminance.org/blog</link>
	<description>Programming and Game Development - Kevin Gadd&#039;s Blog</description>
	<lastBuildDate>Sun, 02 Oct 2011 00:15:58 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Home stretch</title>
		<link>http://www.luminance.org/blog/gruedorf/2009/07/30/home-stretch</link>
		<comments>http://www.luminance.org/blog/gruedorf/2009/07/30/home-stretch#comments</comments>
		<pubDate>Fri, 31 Jul 2009 06:21:50 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Gruedorf]]></category>
		<category><![CDATA[audio]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[xna]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=645</guid>
		<description><![CDATA[In the next two weeks I have deadlines for two different contests coming up, so things are getting pretty hectic. Lots of things changed in the ~100 or so commits since the last blog post, so I&#8217;ll pick a few to describe. Combo System &#38; Attack Chains Instance Limiting Overhaul Active Controller Detection Combo System [...]]]></description>
			<content:encoded><![CDATA[<p>In the next two weeks I have deadlines for two different contests coming up, so things are getting pretty hectic. Lots of things changed in the ~100 or so commits since the last blog post, so I&#8217;ll pick a few to describe.</p>
<ul>
<li><a href="http://www.luminance.org/gruedorf/2009/07/30/home-stretch#section1">Combo System &amp; Attack Chains</a></li>
<li><a href="http://www.luminance.org/gruedorf/2009/07/30/home-stretch#section2">Instance Limiting Overhaul</a></li>
<li><a href="http://www.luminance.org/gruedorf/2009/07/30/home-stretch#section3">Active Controller Detection</a></li>
</ul>
<div class="video"><object width="720" height="430" style="width:720px;"><param name="movie" value="http://www.youtube-nocookie.com/v/8UJ6-5EHRsw&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0x2b405b&#038;color2=0x6b8ab6&#038;hd=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube-nocookie.com/v/8UJ6-5EHRsw&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0x2b405b&#038;color2=0x6b8ab6&#038;hd=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="720" height="430" style="width:720px;"></embed></object></div>
<p><span id="more-645"></span></p>
<p><a name="section1"></a><br />
<h2>Combo System &amp; Attack Chains</h2>
<p>Previously, combat basically consisted of hitting the punch button over and over to kill monsters. This sucked.</p>
<p>I took a few major steps to address this:</p>
<p>First, I added a second attack type bound to the button I was previously going to use for the grappling hook. This attack is slower and hits heavier, with a wider attack arc, and gives you a nice alternative to the fast, lighter-hitting punch attack.</p>
<p>After the addition of the second attack type, I built on that to add &#8216;combo&#8217; variations of each attack (punch combo, slash combo). The player can combo these attacks onto a previous attack by properly timing another button press near the end of the previous attack animation. Missing the timing (either by pressing too early or too late) &#8216;botches&#8217; the combo and causes the delay before they can perform another attack to be longer than it would be otherwise. The size of the time window in which you can successfully combo an attack decreases every time you combo, so over time it gets harder. This means that simply attacking once will be slow and inefficient, but you are also prevented from comboing attacks indefinitely, which strikes a good balance. The fact that a failed combo has a longer delay than a normal attack means that a player won&#8217;t be punished for choosing to simply combo once or twice and then attack again, since the effectiveness ends up being nearly the same.</p>
<p>Finally, I added a &#8216;attack chain&#8217; system that tracks the number of hits you land on a foe in rapid succession. This allows me to delay the &#8216;flinching&#8217; animation normally played when a creature recieves damage, so that the creature stays within reach of your attacks, allowing you to combo. Each successive hit extends the chain for a short period of time, allowing you to continue landing blows, and when the chain &#8216;breaks&#8217;, all the hits you landed deal their damage to the creature at once, knocking it back and possibly killing it. Chains can span across multiple creatures as well, allowing you to keep multiple enemies &#8216;locked&#8217; by your chain at once. Right now it&#8217;s a bit overpowered, but I think some careful tuning will maintain most of the positive aspects without making the game too easy.</p>
<p><a name="section2"></a><br />
<h2>Instance Limiting Overhaul</h2>
<p>Recently, while working on audio improvements, Troupe ran across a bug in XACT. PC builds of the game ran perfectly without any significant CPU usage problems, and the audio sounded great &#8211; but on the 360, as soon as enough channels of audio started playing, the game&#8217;s framerate tanked to around 15FPS and stayed there indefinitely. This was despite the fact that the game already issues most of its audio calls on a background thread to work around the prohibitively high cost of XACT&#8217;s API calls.</p>
<p>The problem turned out to be that despite the fact I was using XACT&#8217;s built in instance limiting support to control the number of instances playing at once, XACT was struggling to handle the number of cues I was asking it to start at once. Essentially, I was starting all the ambient loop cues for my level at once &#8211; around 30 &#8211; and expecting it to pick the 8 loudest ones to play at any given time based on the instance limit. On PC this worked perfectly without any performance issues, but for whatever reason, not so on the 360.</p>
<p>As a result I basically tore out all the existing code that relied on XACT instance limiting, and reimplemented limiting inside my engine. Luckily this only required changes to about 500 lines of code, but it was still rather frustrating to have to reimplement it when it worked perfectly on PC. On the bright side, now I have more control over how instance limiting behaves, so I at least got something out of it.</p>
<p><a name="section3"></a><br />
<h2>Active Controller Detection</h2>
<p>While doing some testing on my 360 I realized that my approach to handling the 360 controller was incorrect. While I assumed that the player might want to play with any of their four connected controllers, I neglected to notice that most of the XNA Guide APIs (storage device selection, etc) are designed to only respond to input from a single controller. This meant that I needed to detect which controller the player was currently using and make sure to only show XNA dialog boxes using that controller, and that I also needed to detect if that controller became unplugged so that I wouldn&#8217;t attempt to show a dialog box the player was unable to close.</p>
<p>I ended up spending a while changing my input framework so that it would automatically detect disconnected controllers, and inform the game code when a controller had been reconnected. I also did some work to automatically track the active controller, while still handling keyboard input correctly on the PC.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/gruedorf/2009/07/30/home-stretch/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Threaded Renderer</title>
		<link>http://www.luminance.org/blog/gruedorf/2009/07/20/threaded-renderer</link>
		<comments>http://www.luminance.org/blog/gruedorf/2009/07/20/threaded-renderer#comments</comments>
		<pubDate>Tue, 21 Jul 2009 05:07:44 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Gruedorf]]></category>
		<category><![CDATA[concurrency]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[xna]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=585</guid>
		<description><![CDATA[Lots of changes since last week, but the majority of my efforts were focused on overhauling my approach to rendering. My basic approach is primarily inspired by Christer Ericson&#8217;s post about the approach he uses for ordering draw calls. Some other useful sources of information were Tom Forsyth&#8217;s post about the cost of renderstate changes [...]]]></description>
			<content:encoded><![CDATA[<p>Lots of changes since last week, but the majority of my efforts were focused on overhauling my approach to rendering.</p>
<div class="video"><object width="640" height="385" data="http://www.youtube-nocookie.com/v/stiPgEW6AJI&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/stiPgEW6AJI&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><param name="allowfullscreen" value="true" /></object></div>
<p>My basic approach is primarily inspired by <a href="http://realtimecollisiondetection.net/blog/?p=86">Christer Ericson&#8217;s post about the approach he uses for ordering draw calls</a>. Some other useful sources of information were <a href="http://home.comcast.net/~tom_forsyth/blog.wiki.html#[[Renderstate%20change%20costs]]">Tom Forsyth&#8217;s post about the cost of renderstate changes</a> and <a href="http://www.guerrilla-games.com/publications/dr_kz2_rsx_dev07.pdf">Guerilla&#8217;s presentation on Killzone 2&#8242;s renderer from DEVELOP 2007</a>. The Killzone 2 presentation is especially worthwhile since it describes the way they take advantage of concurrency techniques in their renderer.</p>
<p>Until now, the rendering code in my game has been almost entirely immediate-mode; various objects in the game world like tiles and entities had Draw methods that would utilize the game&#8217;s GraphicsDevice and SpriteBatch to render themselves, changing render states as needed and generating dynamic geometry where necessary (like for water).</p>
<p><span id="more-585"></span></p>
<p>Of course, if every object changes render states, you quickly run into a situation where you&#8217;re changing states tens of thousands of times per frame, which doesn&#8217;t perform very well. As a result, I ended up having to add some basic support for grouping together identical render states. In the end, I often had to perform multiple passes over the scene in order to minimize state changes, and the addition of multiple onscreen &#8216;layers&#8217; meant that I often had to make half a dozen passes over the same collections (like Level.Entities and Level.Geometry) in order to render things in the correct order without too many state changes. My new renderer clearly needed to provide an inexpensive way to reduce state changes without complicating my code.</p>
<p>In addition to the issue of state changes, however, was the simple fact that rendering was too expensive. In particular, rendering all the onscreen tiles for the 6+ layers in the level could often add up to 5%+ of my CPU time, due to the relative inefficiency of the XNA SpriteBatch class when trying to draw thousands of bitmaps at various locations on the screen. The use of SpriteBatch also meant that I couldn&#8217;t effectively sort tiles by texture, because using a custom blending configuration with SpriteBatch requires you to disable its texture sorting support. (My tiles and sprites have to be premultiplied so they look correct when scaled, unfortunately.) As a result, my new renderer needed to minimize the cost of individual drawing operations, and it also needed to give me a way to utilize material/texture sorting with custom blending configurations.</p>
<p>One final detail that factored into the design was concurrency: Between the cost of actually rendering the game world, and the cost of waiting for vertical sync, the main thread was spending as much as 40% of its time performing rendering, which made it much harder to maintain a smooth, consistent 60fps framerate. In order to minimize the amount of time the main thread spent blocked during rendering, my new design needed to make it possible to move rendering work off the main thread without introducing thread safety issues &#8211; putting a lock around all my game state wasn&#8217;t going to cut it.</p>
<hr />The design I ended up with roughly looks like this:</p>
<p>Every frame, at the beginning of my Draw method I construct a new Render.Frame object to represent the frame that&#8217;s being rendered.</p>
<p>The Render.Frame object contains a list of Render.Batch objects; each Batch has an associated Layer and Material. Layers are simple integers that allow me to explicitly order batches, so that I can create batches in any given order, and even create multiple batches at once. This also allows me to perform a single sort of the Batches array before sending the batches off to the video card, in order to minimize state changes.</p>
<p>Any given Batch contains a list of structures representing &#8216;Draw Calls&#8217;. In some cases, a draw call maps directly to a hardware drawing operation &#8211; like DrawUserPrimitives &#8211; but in other cases, it maps to something more granular. For example, a BitmapBatch contains BitmapDrawCalls, where each draw call represents a single bitmap, much like the arguments you pass to SpriteBatch&#8217;s Draw method. This allows me to sort individual draw calls based on their parameters to minimize state changes within a batch.</p>
<p>Finally, the Material objects associated with a given Batch are a superset of the XNA&#8217;s Effect class &#8211; they include a VertexDeclaration, Effect, and optional delegates for configuring other rendering state like the current blending function or stencil state. Grouping all these parameters together in one object allows me to sort batches cheaply by comparing material instances, but still gives me some level of granularity since I can change the shader parameters of an active Effect within a batch, for example to support rendering multiple textures inside a single BitmapBatch.</p>
<p>In addition to the more obvious performance advantages of this approach, like the ability to sort by material, one other advantage is less obvious: Since a Frame contains information on all the drawing operations that need to be performed, but doesn&#8217;t depend on any of my game state, I can safely hand that object to another thread and have that thread perform the drawing operations. This lets me move a significant portion of my rendering off the main thread, and begin performing my next Update while the previous Draw completes, without needing to add any locking or complex synchronization.</p>
<hr />It&#8217;s not all great, though. The biggest downsides to this approach are twofold:</p>
<p>First, I basically have to reimplement everything from scratch &#8211; SpriteBatch and SpriteFont are both completely impossible to extend, so I have to reimplement them in order to render text and bitmaps with this approach, and the same goes for any other rendering code based on directly manipulating a GraphicsDevice.</p>
<p>Second, this approach is inherently more dependent on the garbage collector, since most of the types must be classes by necessity. If I want to run well on the 360, this means I need to make use of pooling and other techniques to avoid frequent allocations during frames. I&#8217;m also no longer able to reuse a single scratch buffer when generating geometry, so every piece of geometry I render needs to have its own buffer &#8211; more allocations.</p>
<p>So far I&#8217;m pretty pleased with this approach. There&#8217;s more work to be done &#8211; for example, I don&#8217;t have pooling implemented so my game collects extremely often on the 360 &#8211; but a large portion of my game is now running on this new rendering architecture, and my average framerate has already improved slightly from moving work off the main thread, despite the fact that I haven&#8217;t spent any time on optimizations.</p>
<hr />The biggest challenge that remains is porting all of my old GraphicsDevice-oriented rendering code over to using batches. Here&#8217;s a before and after example:</p>
<pre>        public void RenderTileLayer (int index) {
            var layer = RuntimeLevel.Layers[index];
            RuntimeLayer.ItemInfo itemInfo = null;

            BeginSpriteBatch(BlendModes.AlphaPremultiplied);

            using (var e = layer.GetItemsFromBounds(Camera.Bounds))
            while (e.GetNext(out itemInfo)) {
                RenderTile(itemInfo.Item, SpriteBatch, Camera.ViewportPosition, Camera.Zoom, AnimationTimeProvider.Ticks);
            }
        }

        private void RenderTile (RuntimeTile tile, SpriteBatch spriteBatch, Vector2 viewportPosition, float zoom, long time) {
            var info = tile.TileInfo;
            var pos = (tile.Bounds.TopLeft - viewportPosition) * zoom;
            spriteBatch.Draw(info.Texture, pos, info.Rectangle, Colors.White, 0.0f, new Vector2(0, 0), zoom, strip.GetSpriteEffect(), 0.0f);
        }</pre>
<p>You can see here that my approach for rendering tiles is pretty simple: Get all the tiles within the screen&#8217;s boundaries, and render them one by one using a SpriteBatch. I&#8217;m able to reduce the number of state changes since I know that every tile within a given layer shares the same state, but I still need to change state once per layer (using the BeginSpriteBatch function, which calls SpriteBatch.Begin and sets up my render state). I also have to go out of my way to render each layer in the right order, which means calling RenderLayer in multiple places so that certain tiles appear below entities while other tiles appear above entities.</p>
<p>The new implementation looks like this:</p>
<pre>        public void RenderTileLayer (int index) {
            var layer = RuntimeLevel.Layers[index];
            RuntimeLayer.ItemInfo itemInfo = null;

            int drawLayer = (index &lt;= 2) ? DrawLayers.Background : DrawLayers.Foreground;

            using (var bitmapBatch = new BitmapBatch(PendingFrame, drawLayer + index, Materials.Bitmap[BlendModes.AlphaPremultiplied]))
            using (var e = layer.GetItemsFromBounds(Camera.Bounds))
            while (e.GetNext(out itemInfo)) {
                RenderTile(itemInfo.Item, bitmapBatch);
            }
        }

        public void RenderTile (RuntimeTile tile, Render.BitmapBatch batch) {
            var info = tile.TileInfo;

            var drawCall = new Render.BitmapDrawCall(info.Texture, tile.Bounds.TopLeft, info.Bounds);
            drawCall.Mirror(info.Strip.Mirroring.X, info.Strip.Mirroring.Y);

            batch.Add(drawCall);
        }</pre>
<p>One thing you&#8217;ll notice is that RenderTile now has considerably fewer arguments. Since I had to reimplement SpriteBatch from scratch, this gave me the opportunity to integrate some of my rendering calculations, like zooming and viewport positioning, directly into the shader. As a result, I don&#8217;t need to pass those values around as parameters anymore; I simply set them as a shader parameter every time they change. Using an EffectPool for all my shaders also means that I only need to set those parameters once, instead of having to update all my individual shaders with the correct values.</p>
<p>One other difference here is the need to explicitly choose a layer for the tiles to render on when I create a BitmapBatch. I have a small set of constants (named DrawLayers) that I use to roughly organize my layers, but I also add values to those constants so that I can organize batches within those layers. That way, I can be certain that if I draw three sets of tiles on the same layer, they are always drawn in the same order relative to each other.</p>
<p>I also have to explicitly pass in a Material object for the BitmapBatch, instead of just passing a blend mode to the BeginSpriteBatch function. This isn&#8217;t a significant change, but it does mean that I now have to explicitly manage my materials &#8211; as a result, my game now has a LoadMaterials function that runs at startup and creates all the various permutations of parameters I need and stores them so that I can grab them at runtime.</p>
<p>You may also notice that there are no explicit drawing operations in here anywhere; I&#8217;m just creating a BitmapBatch and adding draw calls to it. Essentially, what&#8217;s going on here is that creating a batch automatically attaches it to the Frame being built. When the batch is Disposed (by the using block, in this case), the Frame is notified that the contents of the Batch (its draw calls) are ready and it stores them for later. The use of IDisposable to represent &#8216;readiness&#8217; instead of disposal is a little weird, but it&#8217;s convenient in that it gives me relatively automatic batch management. This also means that if I wanted to, I could create lots of batches at once and fill them with draw calls on multiple threads, since the Frame has a straightforward way to determine whether all of its batches are ready yet.</p>
<hr />Below you can see a short video of how the renderer groups the game up into batches. If you look carefully, you may also notice that particles are being rendered behind all the batches, since they aren&#8217;t yet integrated into the renderer.</p>
<div class="video"><object width="640" height="385" data="http://www.youtube-nocookie.com/v/NtlDmjVpIXg&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/NtlDmjVpIXg&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><param name="allowfullscreen" value="true" /></object></div>
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/gruedorf/2009/07/20/threaded-renderer/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Shipping a Brick</title>
		<link>http://www.luminance.org/blog/code/2009/07/15/shipping-a-brick</link>
		<comments>http://www.luminance.org/blog/code/2009/07/15/shipping-a-brick#comments</comments>
		<pubDate>Wed, 15 Jul 2009 19:18:30 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Games]]></category>
		<category><![CDATA[business]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[reliability]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=563</guid>
		<description><![CDATA[Computer software, and by extension, video games, are getting more complicated every day. It used to be that a game might be a few hundred thousand or maybe a million lines of code. Now, some of the third-party libraries we use in our games are approaching that size, if not already larger! Keeping that in [...]]]></description>
			<content:encoded><![CDATA[<p>Computer software, and by extension, video games, are getting more complicated every day. It used to be that a game might be a few hundred thousand or maybe a million lines of code. Now, some of the third-party libraries we use in our games are approaching that size, if not already larger! Keeping that in mind, it&#8217;s quite impressive that modern games still run for the majority of users. But here&#8217;s a simple fact: Sooner or later, someone is going to be unable to play your game. What you do then determines whether or not they will remain your customer.</p>
<p><a href="http://www.luminance.org/wp-content/uploads/2009/07/brick.png"><img class="aligncenter size-full wp-image-569" title="brick" src="http://www.luminance.org/wp-content/uploads/2009/07/brick.png" alt="brick" width="200" height="174" /></a></p>
<hr />A few years back I was doing design work on an MMORPG. Really satisfying work &#8211; come up with characters &amp; stories, try to construct gameplay around them, and then watch the rest of the team turn it into a living, breathing part of your game world that your players are going to interact with for months afterward.</p>
<p>So, at one point we decided to run a weekend promotion to promote our upcoming title. We temporarily enabled access to the content from our next game, and allowed people who didn&#8217;t own the game to create characters and play for the duration of the weekend. Great idea &#8211; get people in there at no cost, try and convince them your game is fun and worth playing. Works good for existing customers, too, because now they get excited about what&#8217;s coming down the pipe because you&#8217;ve let them play it for a couple days.</p>
<p>I was pretty excited about it, since it was the first promotion of its kind that we&#8217;d run since I had started working there &#8211; which meant I could finally show some of my friends what I was working on, and try and convince them it was worth playing. Most of them hadn&#8217;t even looked at the game since they had to pay for it first &#8211; and who can blame them, really?</p>
<p>Friday rolls around and I head home late and get some rest. The rest of the team does the same.</p>
<p>On Saturday morning, I send a message to a couple of my friends explaining how to download our client and try out the game. They&#8217;re both pretty enthusiastic about it and get started. A few minutes later, one of them says:</p>
<p><em>&#8216;Why can&#8217;t I use any skills?&#8217;</em></p>
<p>What? What do you mean you can&#8217;t use any skills? Are there buttons on the bar at the bottom of the screen?</p>
<p><em>&#8216;Yeah, but they have little lock icons over them. Nothing happens when I press them.&#8217;</em></p>
<p>Well, uh, s&#8211;t. That&#8217;s not supposed to happen. I emailed one of my coworkers to ask &#8211; uh, did anyone try creating a brand new account for the promotion to see if it worked? &#8211; and the answer is depressing: Nope. Luckily, it wasn&#8217;t a total loss &#8211; our existing customers were still able to participate in the event, because they already had working accounts. But for new, potential customers &#8211; the game didn&#8217;t work. They downloaded and installed our game, and it was mostly useless to them.</p>
<hr /><span id="more-563"></span>When you ship a title, you need to be prepared for it to break. What&#8217;s more, you need to <strong>know</strong> as soon as it breaks, and be prepared to take action to deal with the problem. Some issues simply can&#8217;t be solved, whether they&#8217;re caused by hardware problems or software glitches, and sometimes a bug that just affects one or two customers is not worth fixing. Regardless, though, you need to take action to keep your customers happy, whether that action is a patch, a refund, or a workaround. If you do nothing, your customers won&#8217;t be your customers much longer.</p>
<p>The worst possible scenario is that your game breaks and you don&#8217;t know about it. A modern game company can be quite hard to communicate with sometimes &#8211; when a person&#8217;s only choices for getting support are outsourced email support in India or &#8216;support forums&#8217; full of angry trolls, they might just give up instead of trying to get help. Even worse, if they bought the game with a credit card, they might just issue a chargeback instead of trying to get the game fixed &#8211; which costs you <strong>more than it would have to issue a refund</strong> &#8211; all because they either couldn&#8217;t, or simply didn&#8217;t, get in touch with you about their issues.</p>
<p><strong><br />
</strong></p>
<p><strong>As a developer, you want to do everything within your power to make sure that a customer with a broken game remains a customer. Here are some important steps you can take:</strong></p>
<p><strong><br />
</strong></p>
<h3>Provide a visible, straightforward channel for user feedback and support. An email address printed in the front of the manual, placed at the bottom of error dialogs, or on the front page of your website are a good start.</h3>
<p style="padding-left: 30px;">You can get extravagant by using things like forums, twitter, blogs, etc. to communicate with your customers &#8211; some of them will probably appreciate it &#8211; but it is <strong>tremendously important</strong> that whatever tool you provide for customer feedback be as simple and straightforward as possible, and that it be easy to find. Many game companies have switched to hugely complicated &#8216;automated support systems&#8217; that require logins, registration, password management, support tickets, etc. While these systems make sense from the perspective of a studio, most gamers <strong>simply won&#8217;t bother</strong> and will issue a chargeback instead of trying to figure out why your automated support system&#8217;s registration page is sending them an HTTP 500. If you want to manage support tickets using an automated system, go for it, but you <strong>absoutely</strong> need to accept customer feedback via email or some equally accessible method.</p>
<p style="padding-left: 30px;">Also, when considering the use of twitter, forums, or blogs, keep in mind that <strong>visible complaints and negative feedback</strong> cost you more than invisible ones. You should strive to encourage your customers to contact you privately before taking their issue public for the world to see. Ideally, you can resolve it in private before anyone else ever sees it, which limits the negative impact the issue has on your image as a developer.</p>
<p style="padding-left: 30px;">Prompt responses to feedback are also important. Nobody expects you to solve a bug in 2 hours, but you should strive to send your customer an initial response to their feedback as quickly as possible, even if the response is &#8216;We&#8217;re taking a look at your issue, please be patient &#8211; here&#8217;s a link to the ticket in our support system&#8217;.</p>
<h3>Provide news to your customers about ongoing issues with your game in an obvious and accessible location (your website&#8217;s homepage or the homepage for your title are good choices).</h3>
<p style="padding-left: 30px;">Running a website is, contrary to popular opinion, quite difficult. As a result, some developers tend to &#8230; <a href="http://brokentoys.org/2009/07/07/patching-is-so-2001/">forget to update their website</a>, or simply don&#8217;t offer support information for customers in a visible place, relying on blogs, forums, or news sites to serve as their method for communicating with customers.</p>
<p style="padding-left: 30px;">This is inadequate. It sucks, but you need to be putting regular updates out there for your customers in the first place they&#8217;re probably going to look &#8211; your website. If possible, you should put that news <strong>in the launcher</strong> for your game, if it has one. When you&#8217;re showing your customers an error message because the game failed to start, you should <strong>make sure to point them at your website, too</strong>, just to be sure that they get any information you have for them.</p>
<p style="padding-left: 30px;">It costs you time and money to communicate with your customers, but it&#8217;s time well spent and money that will pay for itself by keeping those customers from leaving.</p>
<h3>Design your game so that when it breaks, it breaks gracefully. Present clear, informative error messages that customers can pop into Google and send you via email.</h3>
<p style="padding-left: 30px;">So, let&#8217;s be honest. Software in general does not break gracefully. People are used to <a href="http://thedailywtf.com/Articles/Serious-SelfService.aspx">cryptic</a> <a href="http://thedailywtf.com/Articles/10,-10,-or-15.aspx">error</a> <a href="http://thedailywtf.com/Articles/Circular-Logic.aspx">messages</a> by now. Regardless, you should strive to do better.</p>
<p style="padding-left: 30px;">Every failure should present an error message that:</p>
<ul>
<li>Tells your customers what to do to resolve the problem (even if it is &#8216;contact customer support at support@mycompany.com&#8217;)</li>
<li>Clearly identifies the failure. Providing an error number or error code is good, so is providing the location where the error occurred. However, if possible you should avoid presenting gigantic stack traces or error dumps to the customer &#8211; they&#8217;re overwhelming, not helpful. Get them back to you, the developer, some other way.</li>
<li>Lists any <strong>user-actionable</strong> problems that contributed to the failure &#8211; &#8216;your microphone isn&#8217;t plugged in&#8217; is actionable, while &#8216;your Direct3D driver returned D3DERR_INVALIDCALL&#8217; is not.</li>
</ul>
<h3>Do whatever you can to find out about failures.</h3>
<p style="padding-left: 30px;">When your game fails, if possible, it should &#8216;phone home&#8217; to notify you. At the very least, it should report the version number of your game, the error that occurred, and a stacktrace of where it occurred.</p>
<p style="padding-left: 30px;">Sometimes it&#8217;s not possible to phone home &#8211; no internet connection, for example &#8211; and in that case, it&#8217;s okay to give up. If you&#8217;re concerned that failures happen a lot in this environment, consider storing the most recent failure message in your game&#8217;s AppData directory and reporting it the next time your game is launched with an internet connection. Better than nothing, right?</p>
<p style="padding-left: 30px;">In many cases you may find it useful to report detailed information on the user&#8217;s system configuration, and the circumstances under which the failure occurred &#8211; remaining memory and disk space available, etc. This is a good idea, but if you do it, you must be <strong>absolutely certain</strong> that you do not report a single shred of your customer&#8217;s personal/private information along with the crash report. If you do, they will be completely justified in kicking up an annoying s&#8211;tstorm about it on the internet.</p>
<p style="padding-left: 30px;">Some customers will complain about your game phoning home no matter what you do. As long as you only phone home when your game fails, you can safely ignore them. You&#8217;re doing your best to make sure the game works for everybody, and you&#8217;re not compromising their privacy. If they&#8217;re worried, they can unplug the ethernet cable.</p>
<p style="padding-left: 30px;">Note that if your game requires internet access to work anyway, you should probably also consider reporting a successful start and exit of your game as well. This will help you track down situations where your automated crash reporting also fails to work correctly (these are more common than you might think).</p>
<h3>Don&#8217;t compromise your game&#8217;s reliability for business reasons.</h3>
<p style="padding-left: 30px;">Now, to begin with &#8211; I&#8217;m not a fan of DRM, but I&#8217;m not going to try and convince you to abandon it here. If you&#8217;re already using DRM, you probably have a reason for doing so.</p>
<p style="padding-left: 30px;">However, there is <strong>no excuse</strong> for allowing DRM &#8211; or any other addition to a game title &#8211; to compromise the reliability of your game. Any addition -  DRM, an automatic updater, a &#8216;compatibility check&#8217;, etc &#8211; should never prevent customers who purchased your title from playing it.</p>
<p style="padding-left: 30px;">Nobody&#8217;s perfect, of course &#8211; sometimes your game is going to break despite your best efforts, and it will be due to some secondary part of the game, like DRM. In these situations, the previous rules apply: Provide clear, informative error messages, and communicate with your customers.</p>
<p style="padding-left: 30px;">When a game breaks because of a business decision, customers tend to be less willing to forgive. They just want to play your game; they don&#8217;t care about your revenue. Sorry. Therefore, while a good business decision is still a good business decision, you should always strive to make sure that you don&#8217;t make your game more likely to break.</p>
<p style="padding-left: 30px;">If the addition of DRM reduces piracy by 2% but causes the game to break for 4% of your legitimate customers, you just kneecapped the effectiveness of that DRM package, which doesn&#8217;t benefit anyone.</p>
<p style="padding-left: 30px;">
<p style="padding-left: 30px;">
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/code/2009/07/15/shipping-a-brick/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Camera Constraints</title>
		<link>http://www.luminance.org/blog/gruedorf/2009/07/15/camera-constraints</link>
		<comments>http://www.luminance.org/blog/gruedorf/2009/07/15/camera-constraints#comments</comments>
		<pubDate>Wed, 15 Jul 2009 10:02:36 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Gruedorf]]></category>
		<category><![CDATA[camera]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[xna]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=559</guid>
		<description><![CDATA[As the level I&#8217;m currently building has gotten larger, it&#8217;s become obvious that I need a way to control the behavior of the camera &#8211; simply centering it on the player isn&#8217;t sufficient. While I already had some usable support for panning the camera to show points of interest, and locking it in place while [...]]]></description>
			<content:encoded><![CDATA[<p>As the level I&#8217;m currently building has gotten larger, it&#8217;s become obvious that I need a way to control the behavior of the camera &#8211; simply centering it on the player isn&#8217;t sufficient. While I already had some usable support for panning the camera to show points of interest, and locking it in place while the player performs an action like climbing onto a surface, I didn&#8217;t have anything in place for more advanced control of the camera, like constraining it to a region of the level.</p>
<p>So, the first approach I took was simple: I placed a rectangle around the entire level to constrain the camera. For smaller, rectangular levels, this worked good enough &#8211; all I had to do was place the rectangle so that you could see all the important parts of the level, and make sure I filled the entire space with tiles so the player didn&#8217;t see any ugly empty space while the camera panned around.</p>
<p>But to be honest, that kind of sucks. It means I have to waste time filling in the entire rectangle with tiles, and the camera doesn&#8217;t do anything to help give the player a sense of the layout of the environment. Ideally, the camera should be able to automatically position itself so that you can see the important parts of the area around you, and not show you unimportant sections of the level that you might have already passed through, or might be encountering later. Furthermore, it should avoid showing you empty/boring space whenever possible &#8211; no point in showing boring repeated tiles to the player when we could be showing interesting parts of the level instead.</p>
<p>The first approach I tried was a relatively simple one: I placed points of interest throughout the level, and then drew lines to connect them using the editor. After that, I assigned a radius to each point, controlling how far the camera would be allowed to &#8216;drift&#8217; away from the point. The end result was that I had a series of &#8216;rails&#8217; the camera could follow through the level, of varying thickness depending on the radius of each point.</p>
<p><span id="more-559"></span></p>
<p>While this approach provided very smooth, organic-feeling camera motion, it was extremely difficult to get it to do exactly what I wanted it to do. It&#8217;s hard to visualize how the camera will behave when following rounded paths through the level, and it was difficult to get the camera to transition between rails at exactly the times I wanted &#8211; if two rails were close to each other, the camera would often jump between them unpredictably, and it was hard to prevent that without introducing nasty side effects.</p>
<p>So, I moved on to a more complex approach: Instead of creating &#8216;rails&#8217; for the camera to follow, I instead defined a set of rectangular camera regions, covering all the parts of the level I wanted the camera to focus on. The idea was to have the camera automatically focus on the most interesting parts of the level, and as a secondary effect, have it avoid showing empty parts of the screen.</p>
<p>Once I had all the regions set up, I wrote some simple code to have the camera perform some simple collision detection, between the four edges of the camera (top, left, bottom, right) and the camera regions, so that it would automatically pan around to follow the player, but stop when hitting the edge of the visible regions. While I eventually got this approach to work, it was difficult to use it to hide empty parts of the level &#8211; most of the camera regions ended up being smaller than the screen, and when dealing with regions smaller than the screen, it&#8217;s impossible to get the camera to automatically show you the &#8216;right&#8217; parts of the level, since the camera algorithm has to choose between multiple equally acceptable positions for the camera.</p>
<p>The final approach I settled on was a refined version of the previous one. Instead of simply defining a set of rectangles, I built on that approach: I placed rectangles to define regions or &#8216;rooms&#8217; within the level, and assigned each room a set of constraints to apply to the camera. At runtime, the camera code selects a region based on the player&#8217;s current position, and then applies the constraints from that region to control the motion of the camera. In most cases, I only use one or two constraints on a given region, but if I want to, I can use all four of them, constraining the minimum/maximum position of the camera along both axes.</p>
<p><object width="640" height="385" data="http://www.youtube-nocookie.com/v/asuK-y5YCKs&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/asuK-y5YCKs&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><param name="allowfullscreen" value="true" /></object></p>
<p>This gives me most of what I need to make the camera behave in a pleasing way: While the player&#8217;s in a long corridor, I can lock the camera&#8217;s Y axis and make it follow the player along the corridor, but stop when it hits the edges of the corridor. When the player&#8217;s ascending a long vertical shaft, I can lock the camera horizontally but have it follow him vertically. And in cases where the player is moving along both axes, I can just lock it to a rectangular region so it attempts to follow the player, but avoids wasting onscreen space.</p>
<p>Of course, there&#8217;s one obvious flaw with this approach, once you prototype it: Since the player can only be in one camera region at a time, you get an abrupt jump when the player moves from one region to another. Luckily, there&#8217;s a relatively simple way to solve this problem: Interpolation. Unfortunately, the simplest possible approach here won&#8217;t work right: If you just interpolate between regions, the camera ends up bouncing around, traveling outside the constraints set by the camera regions. The solution I ended up applying works like this: When the player enters a new camera region, I slowly ramp up the effect of the new region, while leaving the previous region&#8217;s constraints operating at full strength. Once the new region&#8217;s constraints are in full effect, I then ramp down the effect of the previous region. This ensures that the camera is fully constrained at all times, but still provides a relatively smooth transition between regions. It&#8217;s not perfect, but in practice it&#8217;s relatively easy to set up regions so the camera smoothly tracks the player as he travels between them.</p>
<p>Overall, I&#8217;m pleased with how this turned out &#8211; I only had to write around a hundred lines of code to implement the final version of my camera constraint system, even though it took me around 8 hours to arrive at my final implementation. It&#8217;s unfortunate that it took so long to get it right, but considering that I had no idea how to solve this problem when I started, things went pretty well.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/gruedorf/2009/07/15/camera-constraints/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Content Pipeline integration and deployment</title>
		<link>http://www.luminance.org/blog/gruedorf/2009/06/19/content-pipeline-integration-and-deployment</link>
		<comments>http://www.luminance.org/blog/gruedorf/2009/06/19/content-pipeline-integration-and-deployment#comments</comments>
		<pubDate>Sat, 20 Jun 2009 05:35:33 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Gruedorf]]></category>
		<category><![CDATA[content pipeline]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[xna]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=504</guid>
		<description><![CDATA[During this past week, one of the problems I tackled was finding a way to deploy builds of my game. When dealing with deployment, an important principle is that the process should be as close to a single click as possible &#8211; a complex deployment process discourages you from getting customer feedback, and increases the [...]]]></description>
			<content:encoded><![CDATA[<p>During this past week, one of the problems I tackled was finding a way to deploy builds of my game. When dealing with deployment, an important principle is that the process should be as close to a single click as possible &#8211; a complex deployment process discourages you from getting customer feedback, and increases the likelihood that you&#8217;ll make a mistake and end up with a failed deployment, which wastes valuable time.</p>
<p><object width="640" height="385" data="http://www.youtube-nocookie.com/v/7eEEtvzOWMY&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/7eEEtvzOWMY&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><param name="allowfullscreen" value="true" /></object></p>
<p>For most of my previous projects, I&#8217;ve tended to take either a hands-on approach to deployment, or a completely hands-off one, either building an installer by hand using tools like NSIS, or deploying the project as a ZIP file full of binaries and expecting the end user to install the necessary dependencies and figure out how to get the program running. Neither extreme is ideal, really (though hands-off deployment can be amazing if you manage to set things up such that all the end user has to do is run your game &#8211; no install necessary).</p>
<p><span id="more-504"></span>I spent a little while considering options like WiX for building my own installer and deployment process, but quickly realized I could spend entire weeks trying to solve that problem and not be done. With my schedule I can&#8217;t really afford to waste time like that, so I had to go for something simpler. On the other hand, hands-off deployment isn&#8217;t an option here either &#8211; XNA games have enough dependencies that it&#8217;s nontrivial for a casual gamer or newbie computer user to get them working on a machine.</p>
<p>As it turns out, Microsoft&#8217;s ClickOnce deployment tool is extremely easy to use with modern versions of the XNA framework. For a simple game, you really don&#8217;t need to do anything other than build your project and click Publish &#8211; it spits out all the files necessary to install your game, and you can upload them somewhere on the internet. It even has decent support for automatic updates.</p>
<p>Unfortunately, &#8216;magic&#8217; deployment systems like this only work well if they have all the information they need to deploy your game. This means that your project file needs to accurately represent everything your game needs to run &#8211; libraries it uses, content it loads at runtime, etc. This ended up presenting the biggest challenge for me as far as getting ClickOnce deployment to work &#8211; I had to convince it to deploy the files my game needed, which meant including all my game assets into my project.</p>
<p>At first I considered some simple solutions to the problem &#8211; using post build steps to copy all my assets, or adding all of them to the content project by hand &#8211; But eventually I realized the right choice was to integrate my game with the content pipeline so that ClickOnce would know exactly where to find all my assets. As it happens, XNA 3.1 added some useful features that made this process considerably easier.</p>
<p>I&#8217;ve previously <a href="http://www.luminance.org/gruedorf/2008/12/15/one-way-barriers-and-serialization">shared some basic details about my approach to serialization</a>. Essentially, all the custom content in my game is described as simple graphs of objects, where each object in the graph is serialized by Microsoft&#8217;s built in XMLSerializer and the graph as a whole is serialized by my storage framework. This gives me a nice balance between the ridiculous simplicity of XMLSerializer (for simple data types, you basically just point it at them and you&#8217;re done writing your serialization code) and the flexibility provided by doing your own serialization.</p>
<p>Before XNA 3.1, to integrate with the content pipeline, I would have had to write four classes &#8211; an importer to read a tileset object from my XML graph format, a processor to convert it into a &#8216;processed&#8217; tileset blob, containing all the appropriate tile textures and information, a writer to convert that blob into the XNB format, and a reader to convert the XNB format back into a TileSet object at runtime. A lot of work, to be sure, and typically a lot of duplication as well. XNA 3.1 simplifies things by letting you omit the Reader and Writer classes &#8211; assuming you design your data types correctly, you can get extremely efficient reading and writing for free with the addition of a few attributes. Knowing that, the only classes I now need to write are the importer and the processor.</p>
<p>Some aggressive refactoring lets us simplify things even further: Since I know all my custom files are in my XML graph format, I can use the same importer for all of them, and implement all the unique code inside the processors. This means that I write a simple &#8216;raw XML&#8217; importer once, and then write a processor for each unique data type. Now the problem is extremely manageable: A little duplication (data type + processor), but hardly anything to get upset about.</p>
<p>However, one problem still remains: I&#8217;ve already got code for reading and writing these graphs from XML, and code for converting those graphs into the data structures I need at runtime. If I end up having to reimplement all that behavior for the content pipeline, I&#8217;m potentially wasting a lot of effort. Once again, however, refactoring comes to the rescue: By carefully moving around classes and dependencies, I was able to reuse the same serialization and initialization code in the content pipeline and in the game engine.</p>
<p>Moving things around in this way meant that I could make these changes incrementally, as well &#8211; instead of spending days with my game engine in a broken state, trying to bend my data to fit the content pipeline, I could swap out one bit of code at a time, since everything was built on the same fundamental infrastructure. So, I started by getting my Tileset format to properly build in the content pipeline, then changed the game engine to load the content pipeline&#8217;s version of the tileset instead of the source XML files. Once that was working, I did the same thing with the Sprite format. After that was done, I was free to make more aggressive changes, like enhancing my content pipeline processors to build all the necessary textures for a tileset or sprite into a single file for more efficient loading, or doing things like premultiplying my tiles during the tileset build process.</p>
<p>Since I&#8217;ve rambled on for a while now, I&#8217;ll just share some code so you can see how various pieces of the pipeline look now. If you have any questions, feel free to ask and I can elaborate more on how pieces of this work.</p>
<p>First, the raw file importer. This is a really trivial content pipeline class that handles turning one of my data files into a content object that can be handed to one of my content processors. The key here is that this makes things general so that I can reuse as much serialization/processing code as possible between different formats.</p>
<pre>    [ContentImporter(
        ".*",
        DisplayName="Raw File Importer"
    )]
    public class RawFileImporter : ContentImporter&lt;RawFile&gt; {
        public override RawFile Import (string filename, ContentImporterContext context) {
            filename = Path.GetFullPath(filename);
            using (var f = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
                var result = new byte[f.Length];
                f.Read(result, 0, (int)f.Length);
                return new RawFile { Filename = filename, Data = result };
            }
        }
    }</pre>
<p>As you can see, it&#8217;s really simple: Read the contents of the file being built by the content pipeline and turn that into an object that can be manipulated by a content processor. If I wanted to, I could even do XML parsing and graph loading here to take advantage of the similarities between my file formats.</p>
<p>The next piece of the puzzle is the content processor. For example, here&#8217;s the TileSet processor. It takes a raw file as input and spits out a processed version of my TileSet object that can be loaded at runtime.</p>
<pre>    [ContentProcessor(DisplayName = "TileSet Processor")]
    public class TileSetProcessor : ContentProcessor&lt;RawFile, TileSet&gt; {
        public override TileSet Process (RawFile input, ContentProcessorContext context) {
            var contentRoot = context.GetContentRoot();
            var resolver = new AssemblyTypeResolver(__LabyrinthModel__.Assembly);
            var textureParameters = new OpaqueDataDictionary {
                { "ColorKeyEnabled", false },
                { "GenerateMipmaps", false },
                { "ResizeToPowerOfTwo", false },
                { "TextureFormat", TextureProcessorOutputFormat.Color }
            };

            TileSet tileset;
            using (var stream = new MemoryStream(input.Data)) {
                var serializer = new XmlNodeSerializer { StreamOpener = (fn) =&gt; stream, TypeResolver = resolver };
                var f = serializer.LoadNode&lt;TileSet&gt;(null);
                f.GetCompletionEvent().WaitOne();
                tileset = f.Result;
            }

            var textures = tileset.TileStrips.Select((ts) =&gt; ts.Filename).Distinct().ToArray();

            foreach (var texture in textures) {
                var texturePath = Path.Combine(tileset.TilePath, texture);

                var itemPath = Path.Combine(contentRoot, texturePath);

                var sourceRef = new ExternalReference&lt;TextureContent&gt;(itemPath);
                var builtRef = context.BuildAndLoadAsset&lt;TextureContent, TextureContent&gt;(
                    sourceRef, "PremultipliedTextureProcessor", textureParameters, null
                );

                foreach (var ts in tileset.TileStrips) {
                    if (ts.Filename != texture)
                        continue;

                    ts.Filename = null;
                    ts.Texture = builtRef;
                }
            }

            tileset.TilePath = null;

            return tileset;
        }
    }</pre>
<p>There&#8217;s a lot going on in this class, so I&#8217;ll go over the important bits one at a time:</p>
<p>First, you&#8217;ll see I do some basic initialization before I start processing the content &#8211; setting up parameters for the texture processor and creating objects needed by the graph serialization code. Next, I take the raw file data and use the graph loader to convert it into the type I care about &#8211; in this case, TileSet. At this point, the TileSet object only represents the contents of the XML file; not the complete asset. Since this is the same serialization code I use at runtime, it runs in a background thread and I have to wait for it to complete before continuing.</p>
<p>Next, I walk over all the TileStrips defined in the file to build a list of unique texture files that this TileSet depends on. LINQ is handy for this sort of thing, and since our code is running in the content pipeline, we don&#8217;t have to worry about garbage creation like we do on the 360.</p>
<p>For each texture, we determine its fully qualified filename and use that to create an ExternalReference to it. Once we have that reference, we can pass it back to the content pipeline and request that the texture be built and loaded for us so that we can embed it into the result TileSet object. We pass in the parameters we configured earlier, along with the name of the content processor to use for the texture (in this case, it&#8217;s &#8220;PremultipliedTextureProcessor&#8221;, a special texture processor I wrote that premultiplies textures after running them through the standard content processor).</p>
<p>Once we have a built version of a given texture, we walk through all the TileStrips defined in the TileSet, and if they depend on that texture, we null out their Filename field and store our built texture into their Texture field. The important detail here is that while the TileStrip object has both of these fields, each specific file format only uses one of them &#8211; this is done using the appropriate attributes, like XmlIgnore and ContentSerializerIgnore. This sort of technique can be dangerous, since it makes your code harder to understand, but in this case, it allows us to get away with one type where we&#8217;d normally need two similar, but distinct types.</p>
<p>Finally, we null out the TileSet&#8217;s TilePath field, as a way of indicating that the tileset&#8217;s tiles do not need to be loaded from disk &#8211; it&#8217;s fully constructed. At this point, we return our TileSet object to the content pipeline, because it&#8217;s ready to be stored out to disk. Now the content pipeline takes over, and its automatic serialization code converts our TileSet to XNB and then back to TileSet at runtime.</p>
<p>The next step to making this work is pulling out the important parts of my object model into their own library, so that both the game itself and the content pipeline plugin can access them. As described in <a href="http://blogs.msdn.com/shawnhar/archive/2008/11/24/content-pipeline-assemblies.aspx">some of Shawn Hargreaves&#8217; blog posts</a>, getting the content pipeline right can be difficult. Moving classes like TileSet and Sprite into their own assembly means that both the Game and the Content Pipeline can access those types without needing to depend directly on each other &#8211; the game depending on the content pipeline would mean no XBox deployment, since the content pipeline doesn&#8217;t work on the XBox 360, and the content pipeline depending on the game would make building the game impossible, since there&#8217;s now a circular dependency between the game&#8217;s assets and the game itself.</p>
<p>Making those types loadable from both XML and XNB formats with the same code required altering them to implement a common interface with a few important methods:</p>
<pre>        public void Initialize (string contentRoot) {
            if (TilePath != null) {
                foreach (var ts in TileStrips)
                    ts.Filename = Path.Combine(TilePath, ts.Filename);
            }
        }

        public IEnumerator&lt;object&gt; LoadContent (IContentLoader contentLoader) {
            var tiles = new Dictionary&lt;string, TileInfo&gt;();
            Texture2D texture;

            foreach (var tilestrip in TileStrips) {
                texture = tilestrip.Texture as Texture2D;

                if (texture == null) {
                    var f = contentLoader.LoadContent&lt;Texture2D&gt;(tilestrip.Filename);
                    yield return f;
                    texture = f.Result;
                }

                tilestrip.GenerateTiles(tiles, texture);
            }

            Tiles = tiles;
        }</pre>
<p>In this example, you can see that the Initialize method takes the location of the game content as an argument, and uses it to convert any filenames from the tileset into fully-qualified paths. When loading from XNB, these filenames have already been cleared out by the content processor, so this method does nothing. When loading from XML, the filenames are populated from the raw XML, so converting them into fully-qualified paths means that we know the exact location of each texture on disk.</p>
<p>In comparison, the LoadContent method walks over all the TileStrips in the TileSet, and if they don&#8217;t already have a texture, it uses the provided ContentLoader to read their texture from disk. Once they have a texture, it generates the tile info from the TileStrip and the texture so that the game&#8217;s renderer has a list of individual tiles to use. Since the content processor initializes the Texture field, this function doesn&#8217;t have any content loading to do when working from XNB. When loading from XML, the Texture fields are all null, but (thanks to the Initialize function), each TileStrip has a fully-qualified path pointing to a texture. We can use the provided ContentLoader to read the texture from disk and populate the fields, so everything works as it would have if we were loading from XNB.</p>
<p>Using a custom interface for reading content here gives us the advantage of being able to reproduce the content pipeline behavior we care about (like premultiplying textures) without needing to drag in the entire content pipeline and build XNBs at runtime. We can provide a simple wrapper over the standard ContentManager class that knows how to premultiply textures after loading them and then hand them back to the LoadContent method.</p>
<p>The final step is to put this all together and use it to load both XNB and XML versions of our content at runtime. There&#8217;s a little duplication involved, but it&#8217;s not bad:</p>
<pre>        protected IEnumerator&lt;object&gt; LoadContentFromDirectory&lt;T&gt; (string directory, string filter)
            where T : IContentNode {

            var result = new Dictionary&lt;string, T&gt;();
            var filenames = Directory.GetFiles(directory, filter);
            var loader = new XmlNodeSerializer {
                StreamOpener = (fn) =&gt; File.OpenRead(fn),
                TypeResolver = Game.TypeResolver
            };

            foreach (var filename in filenames) {
                var f = loader.LoadNode&lt;T&gt;(filename);
                yield return f;

                var item = f.Result;
                item.Initialize(GetContentPath());

                yield return item.LoadContent(TextureAndContentLoader);

                result.Add(item.Name, item);
            }

            yield return new Result(result);
        }

        protected IEnumerator&lt;object&gt; LoadCompiledContentFromDirectory&lt;T&gt; (string directory)
            where T : IContentNode {

            var result = new Dictionary&lt;string, T&gt;();
            var filenames = Directory.GetFiles(directory, "*.xnb");

            foreach (var filename in filenames) {
                var f = ContentLoader.LoadContent&lt;T&gt;(
                    Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename))
                );
                yield return f;

                var item = f.Result;
                item.Initialize(Content.RootDirectory);

                yield return item.LoadContent(ContentLoader);

                result.Add(item.Name, item);
            }

            yield return new Result(result);
        }

        protected IEnumerator&lt;object&gt; LoadTilesets (bool compiled) {
            Future&lt;Dictionary&lt;string, TileSet&gt;&gt; f;

            if (compiled)
                yield return LoadCompiledContentFromDirectory&lt;TileSet&gt;(Path.GetFullPath(Content.RootDirectory) + @"\tilesets\").Run(out f);
            else
                yield return LoadContentFromDirectory&lt;TileSet&gt;(GetContentPath() + @"\tilesets\", "*.tileset").Run(out f);

            Tilesets = f.Result;
        }</pre>
<p>The IContentNode interface is the simple interface we defined that contains the Initialize and LoadContent methods, so that we can read and initialize our data without needing to know its specific type. The two different Load&#8230;ContentFromDirectory functions contain the necessary logic for finding all the content of a given type and loading it using the appropriate serialization code (for compiled content, Content.Load&lt;T&gt;(&#8220;foo&#8221;), for XML content, XmlNodeSerializer.LoadNode&lt;T&gt;(&#8220;foo.xml&#8221;).) Once I&#8217;ve loaded all the objects, I can walk over the collection and initialize them, and then wait for them to load any required content. You may notice that the loader for XML content uses a special &#8216;TextureAndContentLoader&#8217; object that knows how to read raw PNG textures in addition to XNB textures, where the XNB loader only passes in a ContentLoader that can read XNBs.</p>
<p>Given those two functions, I can write a simple function like LoadTilesets that works correctly for loading both compiled content pipeline files and raw XML content files. So when first loading my game, I can load my content like this:</p>
<pre>                yield return LoadTilesets(true);
                yield return LoadSprites(true);</pre>
<p>And then at runtime if the user presses the hotkey to reload content, I just call the functions again, passing false to load the content from XML:</p>
<pre>                yield return LoadTilesets(false);
                yield return LoadSprites(false);</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/gruedorf/2009/06/19/content-pipeline-integration-and-deployment/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Cutting and tuning</title>
		<link>http://www.luminance.org/blog/gruedorf/2009/06/12/cutting-and-tuning</link>
		<comments>http://www.luminance.org/blog/gruedorf/2009/06/12/cutting-and-tuning#comments</comments>
		<pubDate>Sat, 13 Jun 2009 04:53:28 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Gruedorf]]></category>
		<category><![CDATA[360]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[cuts]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[xna]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=446</guid>
		<description><![CDATA[As far as gameplay goes, the only major addition since last week&#8217;s post was a relatively complete implementation of player death, along with the &#8216;reunion&#8217; teleport that goes with it. Fairly simple at present, with some bugs to work out (including one related to the teleport location that you&#8217;ll see in the video below). Definitely [...]]]></description>
			<content:encoded><![CDATA[<p>As far as gameplay goes, the only major addition since last week&#8217;s post was a relatively complete implementation of player death, along with the &#8216;reunion&#8217; teleport that goes with it. Fairly simple at present, with some bugs to work out (including one related to the teleport location that you&#8217;ll see in the video below). Definitely helps get a better feeling for whether a given puzzle is too hard or too easy.</p>
<p><object width="640" height="385" data="http://www.youtube-nocookie.com/v/FXb9E23WxpQ&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" type="application/x-shockwave-flash"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/FXb9E23WxpQ&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><param name="allowfullscreen" value="true" /></object></p>
<p>Other than that, the only thing of note code-wise is the time I spent doing some performance tuning. My framerate had crept down over the past month or so, to the point that I wasn&#8217;t able to maintain a stable 60fps on the 360 anymore and my CPU utilization was approaching 30% on my desktop PC. Some of the optimizations were relatively obvious &#8211; for example, I was calling SpriteBatch.Begin/SpriteBatch.End for every on-screen object, for the sake of simplicity, which resulted in a lot of unnecessary draw calls.</p>
<p>Some simple changes to automatically begin/end batches when changing rendering settings reduced the number of draw calls per frame in most cases to around 30, which is perfectly acceptable, and reduced my CPU utilization by around 50%. After that, the rest of the optimization was pretty trivial &#8211; finding other hotspots in my profiler data and reducing the cost.</p>
<p>Well, it was trivial until I ran the game on the 360 again and noticed that the framerate hadn&#8217;t improved very much. Huh? I doubled my framerate on the PC, but on the 360, it barely moved an inch. What&#8217;s the deal?</p>
<p>Turns out, the 360&#8242;s pitiful floating-point performance was kneecapping me. Believe it or not, the primary culprit was the geometric shapes in the game&#8217;s HUD, for the circular health displays you may have seen in previous screenshots/videos. I knew the 360&#8242;s FPU was weak, but not THAT bad. Unfortunately, the only way to detect this is by manually measuring the performance cost of your code on the 360, by commenting out/toggling individual sections of your game code.</p>
<p>Tedious, at best. For now, I ended up just reducing the complexity of the geometry for the HUD elements and reducing the number of shapes I was drawing, which brought the 360 framerate much closer to what it used to be. As it happens, some design changes later in the week helped here too&#8230;</p>
<hr />The majority of my work ended up focusing on the game&#8217;s design: My schedule for this project is extremely aggressive (insanely so, really) and as such, I need to have a relatively complete playable demo within mere months for submission to a couple major game competitions. Being able to hit that deadline in my free time requires me to aggressively control the scope of the project, avoid feature creep, and do as little work as possible to get game mechanics implemented and content built.&nbsp;<br />
&nbsp;<br />
Towards this end, after getting one of my main mechanics prototyped and testing it out in content I&#8217;d built, I made the hard decision to cut the mechanic. The second controllable character you&#8217;ve seen in some of my previous videos is effectively gone, though I&#8217;m going to attempt to make use of the design and code effort for the revised design.&nbsp;<br />
&nbsp;<br />
Making a choice like this is always painful, especially when you don&#8217;t have an unchangeable deadline or overbearing boss pushing you towards it. But ultimately, I think I&#8217;ll benefit from making these cuts sooner rather than later. I wish I had started thinking hard about it a few weeks earlier, when my first prototypes were working, instead of waiting until the issues were obvious, but I&#8217;m still relatively happy with the turnaround. I was able to prototype a relatively unusual game mechanic in a matter of a couple dozen hours of programming time, and decide that it wasn&#8217;t worth pursuing, and cut it. Definitely an improvement over traditional Waterfall with long cycles, but not quite true Agile yet. <img src='http://www.luminance.org/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> &nbsp;<br />
&nbsp;<br />
For me, this underscores the importance of aggressive, early prototyping of almost every possible game mechanic and design, instead of focusing on a single section of game content or gameplay until it&#8217;s done. Previously I was used to having a rigid focus on a section of a game or application, working on it day in and day out until it was done and ready to hand off &#8211; but in many cases, this meant that I could sink days or weeks of my time into something that ultimately had to be thrown out.&nbsp;<br />
&nbsp;<br />
Just like a lot of Agile proponents will tell you, it turns out that failing fast means wasting less time. The chaotic feeling and loss of productivity to context switches can be painful, and I think being successful requires setting things up to avoid having to pay those costs too many times a week, but ultimately, it&#8217;s a great decision.&nbsp;<br />
&nbsp;<br />
<object width="640" height="385"><param name="movie" value="http://www.youtube-nocookie.com/v/AujBCa_R4tM&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0x2b405b&#038;color2=0x6b8ab6&#038;hd=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube-nocookie.com/v/AujBCa_R4tM&#038;hl=en&#038;fs=1&#038;rel=0&#038;color1=0x2b405b&#038;color2=0x6b8ab6&#038;hd=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object></p>
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/gruedorf/2009/06/12/cutting-and-tuning/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Prototyping week</title>
		<link>http://www.luminance.org/blog/gruedorf/2009/06/05/prototyping-week</link>
		<comments>http://www.luminance.org/blog/gruedorf/2009/06/05/prototyping-week#comments</comments>
		<pubDate>Sat, 06 Jun 2009 04:26:44 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Gruedorf]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[prototyping]]></category>
		<category><![CDATA[xna]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=420</guid>
		<description><![CDATA[The main thrust of this week&#8217;s work was gameplay prototyping. I spent the majority of my time prototyping gameplay &#8211; either by building new mechanics, tuning existing ones, or constructing small prototypes in the editor. Some of the more interesting things I built: I added support for attaching pieces of geometry to each other, so [...]]]></description>
			<content:encoded><![CDATA[<p>The main thrust of this week&#8217;s work was gameplay prototyping. I spent the majority of my time prototyping gameplay &#8211; either by building new mechanics, tuning existing ones, or constructing small prototypes in the editor.</p>
<p>Some of the more interesting things I built:</p>
<p>I added support for attaching pieces of geometry to each other, so that I could make composite objects for use in puzzle designs. In the following video, I&#8217;ve attached a Crank (a new variation on my existing Switch object, which I&#8217;ll describe a bit later) to a moving platform, and tied the crank to the platform&#8217;s velocity so that you can use it to move the platform:</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="385" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/bL_HvcVUTCE&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><embed type="application/x-shockwave-flash" width="640" height="385" src="http://www.youtube-nocookie.com/v/bL_HvcVUTCE&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>I also spent some time on the Assist mechanic, which allows the player to have abstract control over the inactive character by hitting a special button on the controller at appropriate times. Right now, it merely allows interaction with objects, but in the future, it will allow high-level orders (like &#8216;come here&#8217; or &#8216;stay there&#8217;) that will help guide the (currently unfinished) AI that controls the inactive character in order to keep it from getting left behind during platforming segments. In the following video, I demonstrate using the assist button to operate a crank with the inactive character while the active character makes his way past some spikes:</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="385" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/-sf97hbgCWE&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><embed type="application/x-shockwave-flash" width="640" height="385" src="http://www.youtube-nocookie.com/v/-sf97hbgCWE&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>The culmination of my work this week was constructing a larger puzzle prototype that combines many of the smaller elements I&#8217;ve built previously. It&#8217;s a puzzle that utilizes the Assist mechanic along with many of the mechanics and technologies I&#8217;ve built so far and stresses many of the limits of my current engine. In the process of building it I had to fix numerous bugs and performance issues in my game code and ended up discovering some serious flaws in my collision detection code, which I&#8217;ll no doubt have to address in the coming weeks. Nonetheless, it was quite satisfying to see it take shape:</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="385" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/zIF5NJCN0y8&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><embed type="application/x-shockwave-flash" width="640" height="385" src="http://www.youtube-nocookie.com/v/zIF5NJCN0y8&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>Finally trying it out made me realize that it was far more difficult than I anticipated, and that my UX needed significant improvement. I spent some time refining the puzzle and improving the game&#8217;s UI and was finally able to beat it myself:</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="385" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/XqBVjJQiNi4&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><embed type="application/x-shockwave-flash" width="640" height="385" src="http://www.youtube-nocookie.com/v/XqBVjJQiNi4&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>Naturally, a lot of work still remains, both in the art, design, and technology departments. But it&#8217;s nice to finally be able to build a piece of content this large without running into any showstopper issues &#8211; all said, it took me about 45 minutes to construct and tune this puzzle in my editing tools. Not as fast as I&#8217;d like, but more than good enough to get started on enough content to fill a playable demo.</p>
<p>One of the more surprising technical hurdles this week was the discovery that SpriteBatch.Begin was accounting for over 10% of the CPU usage in my game. This turned out to be due to the fact that each game object was responsible for setting up its own render state, so I was beginning and ending an individual batch for every object in the level &#8211; over a hundred spikes, dozens of moving platforms and doors, and hundreds of tiles. I invested some time into writing code to automatically manage beginning and ending batches, so that objects would no longer need to explicitly call End in their Draw methods, only Begin.</p>
<p>Once I had that working it dropped off my profiles entirely, and my framerate climbed back up to where it was a few weeks ago. On one hand, it&#8217;s nice to be able to see such large performance gains from little effort, but on the other hand, I&#8217;m a little embarassed that I didn&#8217;t think about it earlier. <img src='http://www.luminance.org/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  It&#8217;s likely that in the future I&#8217;ll end up writing a RenderManager class of some sort to automatically handle sorting objects based on their material and other parameters so that I don&#8217;t end up having to send thousands of batches to the video card every frame.</p>
<p>I ran into numerous minor issues with my collision detection code this week, which has me considering ways to rework and improve my current approach. The worst was a bug that I discovered where if I placed an object at negative coordinates (on either the X or Y axes), it behaved differently in collision detection than if it was placed at positive coordinates. Instead of diving into the math to try and figure it out, I ended up just relocating all the objects in my test level so that they had positive coordinates, but I can&#8217;t put solving this one off for too long.</p>
<p>Later in the week a friend stopped by and I had him test the game out on my machine. Not only did he have some good feedback, but he found two bugs within a matter of minutes! Always nice to get fresh eyes on your design and see someone else try out what you&#8217;ve built. I&#8217;m looking forward to having things at the point where I can start handing out test versions for people to bang on.</p>
<p>Finally, a question for anybody who&#8217;s reading on a regular basis: The Gruedorf weekly progress format is becoming rather difficult to work with lately, so I&#8217;m considering changing my approach for this development log. I&#8217;d greatly appreciate it if you let me know via the comments section which topics interest you the most, and whether you&#8217;d be interested in seeing multiple shorter posts during the week focusing on single topics.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/gruedorf/2009/06/05/prototyping-week/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Bits and pieces week</title>
		<link>http://www.luminance.org/blog/gruedorf/2009/05/29/bits-and-pieces-week</link>
		<comments>http://www.luminance.org/blog/gruedorf/2009/05/29/bits-and-pieces-week#comments</comments>
		<pubDate>Sat, 30 May 2009 07:41:36 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Gruedorf]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[platformer]]></category>
		<category><![CDATA[xna]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=406</guid>
		<description><![CDATA[Did work on various bits and pieces of the game this week. A rough overview: Added the first piece of level geometry that deals damage on contact (spikes) Overhauled my ComputeStandingY algorithm so that it takes an order of magnitude less time to run Implemented a new animation for surface mantling that includes camera control [...]]]></description>
			<content:encoded><![CDATA[<p>Did work on various bits and pieces of the game this week. A rough overview:</p>
<ul>
<li>Added the first piece of level geometry that deals damage on contact (spikes)</li>
<li>Overhauled my ComputeStandingY algorithm so that it takes an order of magnitude less time to run</li>
<li>Implemented a new animation for surface mantling that includes camera control</li>
<li>Moved jumping, ledge clinging and mantling from using tasks to using a combination of animation triggers and simple state machine logic</li>
</ul>
<p>So, I guess I&#8217;ll give each bullet point a little detail.</p>
<hr /><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="385" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/IpHoF-EeX5M&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><embed type="application/x-shockwave-flash" width="640" height="385" src="http://www.youtube-nocookie.com/v/IpHoF-EeX5M&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>Adding spikes was fairly straightforward. The largest challenges were getting the collision detection and rendering to work correctly. All the geometry I&#8217;ve added to levels before now has simple collision detection, in that the geometry remains relatively static and obstructs the player&#8217;s movement. Spikes, however, needed to allow the player to move through them but still detect collisions so that they could deal damage. Getting this to work meant some changes to my collision detection code, in order to correctly handle cases where a piece of geometry had no collision, and also meant that I had to add support for changing a piece of geometry&#8217;s collision on the fly &#8211; that way I could leave the spike with no collision by default, but assign it collision temporarily during each update so that I can perform a collision check to find the entities it&#8217;s touching.</p>
<pre>            _CollisionList = _DrawList;
            this.FindObstructions(this.InflictDamage);
            _CollisionList = Game.NullCollisionList;</pre>
<p>Rendering the spikes was a bit of a challenge as well &#8211; since they&#8217;re arbitrarily sized and can point in different directions, I had to do some work to figure out how to take an arbitrary texture and use SpriteBatch to align it with the spike&#8217;s geometry. After a lot of iteration, I ended up with something that properly scales, rotates, and aligns the sprite so that it lines up with the geometry &#8211; determining the proper inputs to a SpriteBatch.Draw call can be challenging when you&#8217;re rotating, scaling and translating all in one go, so it involved a lot of trial and error.</p>
<hr />Some investigation of issues I was running into with standing on surfaces revealed that my current approach was getting too complicated and fragile &#8211; previously, I was scanning over all the objects under the player, and then choosing arbitrary points along their surface (left edge, middle, and right edge) and casting rays downward at those points to attempt to determine where the player should stand on the surface. This ended up not working well for complex surfaces, like the uneven edges of the stone outcroppings created by the stone potion, and being unnecessarily expensive for simple surfaces like flat rectangles (which really only need a single ray cast). Furthermore, it had a negative performance impact, since I was issuing hundreds of ray cast calls per frame in situations where I might have gotten away with only a dozen.</p>
<p>The solution to this ended up being simple: Where previously, I&#8217;d issue ComputeStandingY calls on each object that the player could be standing on, multiple times to cast individual rays, now I would issue a single call for each object, telling it the location of the player&#8217;s left and right edges. This way each object could have its own implementation for handling uneven surfaces &#8211; simple rectangles could just return the Y coordinate of their top edge, while complex geometry could sweep over its vertices and do the necessary math to compute the Y coordinate. In some cases, the new handlers got a bit complicated, but in most cases, they weren&#8217;t actually any harder to write than the old ones &#8211; a pleasant surprise. For example, the handler for pressure plates required a complete rewrite, since a pressure plate is represented by a rectangle (in the middle) with two triangles on the corners to give it a smooth slope:</p>
<pre>        public override float? ComputeStandingY (float x1, float x2, float y) {
            var p = _CollisionList[0];
            if ((x2 &gt;= p[1].X) &amp;&amp; (x1 &lt;= p[2].X))
                return Anchor.Y;
            else if (x2 &lt; p[2].X)
                return RuntimeTriangle.ComputeStandingY(p[0], p[1], x1, x2, y);
            else
                return RuntimeTriangle.ComputeStandingY(p[2], p[3], x1, x2, y);
        }</pre>
<p>While other handlers, like Triangle, required only minor changes to account for the addition of a second X coordinate:</p>
<pre>        public static float ComputeStandingY (Vector2 slopeBegin, Vector2 slopeEnd, float x1, float x2, float y) {
            var minX = slopeBegin.X;
            var maxX = slopeEnd.X;

<em><strong>            if (x2 &lt; minX)
                return slopeBegin.Y;
            else if (x1 &gt; maxX)
                return slopeEnd.Y;</strong></em>

            var startY = slopeBegin.Y;
            var endY = slopeEnd.Y;
            var dX = maxX - minX;
            var dY = endY - startY;

<em><strong>            float x = (dY &gt; 0) ? x1 : x2;</strong></em>

            var d = (x - minX) / dX;

            var result = startY + (dY * MathHelper.Clamp(d, 0.0f, 1.0f));

            return result;
        }</pre>
<p>The end result is that ComputeStandingY went from around #10 on profiler results to well below #50 (always good to maintain a stable framerate), and a number of minor surface standing oddities went away. Future work involving complex surfaces should be much easier, as well, which will be important for some of the game content I have planned.</p>
<hr />Earlier this week I got the art for one of the player characters&#8217; surface mantling animations, so I decided to get it into the game. Doing this required throwing out most of the existing code for surface mantling, since I had previously animated it by actually moving the player character progressively from his old location to the new one. The new animation is simpler, in that the player switches instantly from the old location to the new one, but poses some interesting challenges: I have to realign the player such that his animation looks like it&#8217;s moving from his old location to the new one, without the jarring realignment of the camera that would normally accompany an instant relocation like that.</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="385" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/sVaumZskNek&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><embed type="application/x-shockwave-flash" width="640" height="385" src="http://www.youtube-nocookie.com/v/sVaumZskNek&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>The end result looks pretty good. The basic approach looks like this:</p>
<pre>        protected void BeginMantle (ICollidable mantleTarget, Vector2 targetPosition) {
            Jumping = false;
            JumpApex = false;
            LedgeClinging = false;
            Mantling = true;
            LockInput = true;

            var anim = PlayAnimation("Mantle");
            _MantleTarget = mantleTarget;
            _MantleStartPosition = Position;

            _LockCamera.Position = Position;
            _LockCamera.Weight = 1.0f;
            Game.CameraStack.Add(_LockCamera);

            Velocity = Vector2.Zero;
            Position = mantleTarget.Anchor + targetPosition;

            var rideable = mantleTarget as IRideable;
            if ((rideable != null) &amp;&amp; (!_Riding.ContainsKey(rideable)))
                BeginRiding(rideable);
        }

        protected void EndMantle () {
            Mantling = false;
            LockInput = false;
            if (StandingOn != null)
                _RidingPosition = Position - StandingOn.Anchor;

            Game.CameraStack.Remove(_LockCamera);
            Game.CameraStack.Add(new LookAtCameraController(
                _MantleStartPosition, 0.0f, 0.0f, MantleCameraPanDuration
            ));
        }</pre>
<p>A few things are going on here: When the player begins mantling onto a surface, I set some state flags in order to keep things sane, for example disabling the input, so that you can&#8217;t move left/right or jump while mantling is in progress. After that, I start the mantle animation and initialize some fields so that the player&#8217;s code can keep track of the surface it&#8217;s mantling onto and what the source and target positions are, for animation purposes. Next, I lock the camera on the player&#8217;s original position, so that it won&#8217;t move suddenly when I relocate the player to the new location. Finally, I move the player to his new position, reset his velocity, and if the surface being mantled onto is rideable, I set him as riding it.</p>
<p>The rest of the work mostly happens automatically: I tag the animation frames with markers so that the game knows what his origin is and where the top of his head is, so that his bounding box changes automatically along with the animation, and he appears to be climbing up onto the surface. When the animation finishes, it triggers a handler (EndMantle) to do the rest of the work &#8211; Cleaning up the state, and triggering a short camera pan from the old location to the new location so everything looks smooth. One final touch is that I play the &#8216;crouch to stand&#8217; animation immediately after completing a mantle, so that the player appears to quickly stand back up after climbing onto a surface.</p>
<p>In practice, this solution actually looks smoother and more realistic than the old one, despite the fact that the animation is simpler and the collision detection approach is simpler.</p>
<hr />And finally, this brings me to the task changes. As you might have noticed, previously I used tasks to structure &#8216;long-lived&#8217; pieces of player state, like mantling onto a surface or gripping onto a ledge. This was convenient since tasks could easily take parameters and have local variables that would last for their entire duration, allowing me to track things like the source and destination positions for a mantle without needing to define fields for them. It also simplified the state machines necessary for handling player input and motion, since states like &#8216;is the player mantling&#8217; could be represented entirely by the task responsible for them, and all the logic for updating during that task could be handled by the task itself, once per frame. Tasks also gave me an easy way to ensure that code ran at the beginning and end of a given animation, via the use of IDisposable, without having to manually track state and call Begin/End functions. Put together, all this was a huge timesaver initially, before the addition of my animation system and the simplification of my collision detection code &#8211; early prototypes contained some utterly terrifying state machines before I simplified things by switching to tasks.</p>
<p>The time had finally come to stop using tasks for this, though. The new animation system gave me a way to easily attach logic to onscreen animation, by responding to markers/triggers and to the beginning and end of an animation, and the conditional branching support in the animation format meant that the majority of my animation logic no longer needed to live in the code at all, alleviating most of the issues with huge state machines that I had before. So in the process of rigging up the new mantle animation, I converted jumping, mantling, and ledge clinging so that they used simple state machines and animations instead of tasks.</p>
<p>For the most part, the process was straightforward &#8211; I added boolean fields to track the player&#8217;s state where I previously used a task (so the player now has LedgeClinging and Mantling flags that he didn&#8217;t before), and created private fields for things that were previously stored in task locals (like the surface being mantled onto). Logic that needs to happen at the beginning or end now has its own handler (like the BeginMantle and EndMantle functions shown above), and in the event that I need to run some logic every frame during an animation, I write a simple function for it and insert it into the appropriate part of the state machine. Some of the code for handling player input is starting to get rather complicated, with chains of 5-6 if () else if () else if () else if () conditions, but it&#8217;s at least remaining relatively small and encapsulated.</p>
<pre>        protected bool BeginLedgeCling (out ICollidable clingTarget) {
            if (!CanLedgeCling(out clingTarget)) {
                LedgeClinging = false;
                return false;
            }

            Velocity = Vector2.Zero;
            LedgeClinging = true;
            _ClingDirection = GetInputDirection();
            if (clingTarget != null)
                _ClingPosition = Position - clingTarget.Anchor;
            if (_ClingTarget is IRideable)
                BeginRiding(_ClingTarget as IRideable);

            return true;
        }

        protected void UpdateLedgeCling () {
            if (_ClingTarget == null)
                return;

            var delta = (_ClingTarget.Anchor + _ClingPosition) - Position;
            ApplyMotion(delta);
            AutoUpdateBounds();
        }

        protected void EndLedgeCling () {
            LedgeClinging = false;
            if (_ClingTarget is IRideable)
                StopRiding(_ClingTarget as IRideable);
            _ClingDirection = 0;
            _ClingTarget = null;
        }</pre>
<p>During the process of moving things around, I actually found a few bugs in my implementation of ledge clinging, which made this refactoring quite worthwhile. Previously, I&#8217;d been depending on some bugs in my code in order to make the player remain stationary while clinging to a ledge, when I could have easily accomplished this with a single-line change in the right spot. I also discovered that rebounding off of a wall was actually intermittently broken before because the ledge clinging code had the ability to interfere by causing the player to begin clinging onto the ledge during the middle of a rebound. The new state machine approach made it much easier to address this problem by adding some appropriate checks, so that the player can&#8217;t even attempt to grip onto a ledge if he&#8217;s moving away from it.</p>
<p>All in all, a productive week!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/gruedorf/2009/05/29/bits-and-pieces-week/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Animation markers and triggers</title>
		<link>http://www.luminance.org/blog/gruedorf/2009/05/22/animation-markers-and-triggers</link>
		<comments>http://www.luminance.org/blog/gruedorf/2009/05/22/animation-markers-and-triggers#comments</comments>
		<pubDate>Sat, 23 May 2009 04:14:42 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Gruedorf]]></category>
		<category><![CDATA[animation]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[enums]]></category>
		<category><![CDATA[platformer]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[xna]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=394</guid>
		<description><![CDATA[One of the first things I did this week was implement support for scripted animation markers. Markers let me attach names to various parts of a sprite so that I can use them in animation and collision detection &#8211; for example, lining up a weapon with a character&#8217;s hand, or doing hit detection against a [...]]]></description>
			<content:encoded><![CDATA[<p>One of the first things I did this week was implement support for scripted animation markers. Markers let me attach names to various parts of a sprite so that I can use them in animation and collision detection &#8211; for example, lining up a weapon with a character&#8217;s hand, or doing hit detection against a character&#8217;s hand instead of his entire hitbox.</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="385" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/3-0tu2X40z0&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><embed type="application/x-shockwave-flash" width="640" height="385" src="http://www.youtube-nocookie.com/v/3-0tu2X40z0&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>Once I had some simple markers for the player&#8217;s feet added to his animation script, to test them out more thoroughly, I implemented support for attaching simple script triggers to a combination of a marker and a given animation frame, like this:</p>
<pre>    &lt;SpriteMarker typeId="2"&gt;
        &lt;Name&gt;Left Foot&lt;/Name&gt;
        &lt;Groups&gt;
            ...
            &lt;Group name="run"&gt;
                &lt;Frames&gt;
                    &lt;Frame anchor="tl" x="80"  y="170" index="0" /&gt;
                    &lt;Frame anchor="tl" x="61"  y="169" index="1" /&gt;
                    ...
                    &lt;Frame anchor="tl" x="132" y="143" index="6" /&gt;
                    &lt;Frame anchor="tl" x="99"  y="173" index="7" trigger="Footstep" /&gt;
                &lt;/Frames&gt;
            &lt;/Group&gt;
        &lt;/Groups&gt;
    &lt;/SpriteMarker&gt;</pre>
<p>Using the combination of markers and triggers, I was able to write a simple bit of C# to go with the animation script and spawn small puffs of smoke every time the player&#8217;s feet land on the ground during his run animation:</p>
<pre>    public void Footstep (string foot) {
        if (Jumping &amp;&amp; !JumpLanded)
            return;

        var pos = ResolveMarker(foot);
        if (!pos.HasValue)
            return;
        Game.SpawnSmokePuff(Position + pos.Value - GetDrawOrigin(Animator.Frame), 10, 0.5f);
    }</pre>
<p>The real motivation behind the marker system, however, was syncing animations with the game world &#8211; I wanted the player&#8217;s grappling hook to extend from his hand, have his melee attacks actually sync up with his animation frames, and have his collision detection change realistically while crouched.</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="385" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/_h20KUxmMXs&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><embed type="application/x-shockwave-flash" width="640" height="385" src="http://www.youtube-nocookie.com/v/_h20KUxmMXs&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>Essentially, where before I used hard-coded coordinates and percentages, now I &#8216;resolve&#8217; one of the player&#8217;s named markers. Resolving a marker either returns coordinates (relative to the top left of the frame) or null, which allows me to determine whether a given frame has a particular marker attached to it. Once I have coordinates for a marker, I compute the player&#8217;s origin (used for positioning his animation frames) and use that to compute the on-screen or in-world coordinates for the marker, based on the frame-relative coordinate I already have. Given that, I can sync up things like a grappling hook or a potion with the player&#8217;s hand:</p>
<pre>    public Vector2 GrappleFrom {
        get {
            var handPos = ResolveMarker("Right Hand");
            return Position + handPos.GetValueOrDefault(
                new Vector2(0, Obstruction.Y * -0.5f)
            ) - GetDrawOrigin(Animator.Frame);
        }
    }</pre>
<p>After using this technique to make the player&#8217;s bounding box change while crouching, I realized that by uncrouching, the player could become stuck in a ceiling. The solution to this ended up being a bit of a hack &#8211; before increasing the size of the player&#8217;s bounding box, do a quick collision check to see if the player&#8217;s <strong>current</strong> bounding box is able to move upward by that same amount. If the check fails, I now know exactly how far the player&#8217;s current bounding box would have been able to move, and I can constrain the growth of the bounding box to avoid making the player become stuck.</p>
<p>Once the player is out of a tight space, I can grow the bounding box to its full height, restoring sanity. It&#8217;s not perfect (and looks kind of stupid since it allows the player&#8217;s head to stick through ceilings), but it was relatively simple to implement. I suspect I&#8217;ll end up with a different solution in the final game &#8211; perhaps forcing the player to stay crouched if he can&#8217;t stand up in his current position.</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="385" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://www.youtube-nocookie.com/v/1zL721akH3o&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" /><embed type="application/x-shockwave-flash" width="640" height="385" src="http://www.youtube-nocookie.com/v/1zL721akH3o&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6&amp;hd=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></p>
<p>During the process of rigging up the player&#8217;s animations, I spent a lot of time fine-tuning things and working out issues. To make things move quicker, I ended up adding a couple new features to my engine:</p>
<p>First, I added support for reloading sprites and tiles at runtime. My existing game code already was designed in such a way that this wasn&#8217;t too difficult, but I still had to do some work in order to get the rest of the way. One of the biggest changes was that I had to change entities to store a sprite&#8217;s Name instead of storing the sprite itself, so that I could replace a given sprite instance at runtime after reloading it from disk. As a result, where before I had:</p>
<pre>    this.Sprite.Animations["Walk"].Run(this.SpriteContext);</pre>
<p>Now, I have something like this:</p>
<pre>    Game.Sprites[this.SpriteName].Animations["Walk"].Run(this.SpriteContext);</pre>
<p>A bit more verbose, but easy to abstract out using properties and helper methods &#8211; such that actual game code can just use convenience methods, like so:</p>
<pre>    this.PlayAnimation("Walk");</pre>
<p>And everything happens behind the scenes.</p>
<p>The other change I made was to overhaul my rendering model in order to make it easier to add debugging overlays, user interface graphics, and special effects without having to change the Game&#8217;s Draw function. First, I changed the signature of most of my objects&#8217; Draw methods, such that they now take an extra parameter:</p>
<pre>    public override void Draw (DrawFlags flags) {</pre>
<p>Then, the game code can pass a combination of flags to an object to specify which types of rendering to perform:</p>
<pre>    if (ShowHUD) {
        var flags = DrawFlags.HUD | (GlobalDrawFlags &amp; DrawFlags.DebugHUD);
        RenderGeometry(flags);
        RenderEntities(flags);
    }</pre>
<p>As a result, I have the ability to easily toggle off sections of an individual object&#8217;s painting code, without having to directly hook the logic into the Game object itself. This also nicely simplifies a lot of the code in my editor, since I can now do editor-related painting (like drawing bounding boxes, selection highlights, etc) in the Draw method of the object in question, instead of having to add a special function to the editor that draws those things manually, or having to add an &#8216;EditorDraw&#8217; method to the objects (like I had before in a few cases, unfortunately).</p>
<p>With the addition of a couple extension methods to simplify things, it wasn&#8217;t too hard to wire things up inside my game objects. For example, this is what SpriteEntity.Draw looks like:</p>
<pre>    public override void Draw (DrawFlags flags) {
        ...
        var drawPos = GetDrawPosition();
        var origin = GetDrawOrigin(Animator.Frame);

        if (flags.Check(DrawFlags.Entities))
            Draw(drawPos, origin, Scale, Color);

        if (flags.Check(DrawFlags.DebugEntities)) {
            Game.SetupRenderState(true);
            Game.DrawBox(this.Bounds, Color.White);
            Game.CleanupRenderState();
        }</pre>
<p>It simply checks for each of the draw flags it knows how to handle, and processes them accordingly, in a given order. This gives me the ability to do multiple draw passes at once, or do them individually if I want finer-grained control over draw order. A good example of this is the HUD pass &#8211; I want HUD elements to cover all the objects in the game world, so I draw them in a separate pass. But debugging overlays like entities&#8217; bounding boxes don&#8217;t need to cover everything, so I draw them in the same pass as the entities themselves.</p>
<p>For the curious, the extension methods I ended up writing look like this:</p>
<pre>    public static bool Check (this DrawFlags drawFlags, DrawFlags flag) {
        return (drawFlags &amp; flag) == flag;
    }

    public static DrawFlags Toggle (this DrawFlags drawFlags, DrawFlags flag) {
        return ((drawFlags ^ DrawFlags.All) &amp; flag) | (drawFlags &amp; (flag ^ DrawFlags.All));
    }</pre>
<p>They&#8217;re fairly simple, but having them tremendously simplifies the process of working with the DrawFlags enumeration. This is one thing that I wish C# had built-in support for, but it&#8217;s at least fairly easy to add with extension methods. Unfortunately, generic types and enums don&#8217;t get along, otherwise you could have generic forms of these functions instead of having to write them for each Flags enumeration in your game.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/gruedorf/2009/05/22/animation-markers-and-triggers/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Scripted animations and saved games</title>
		<link>http://www.luminance.org/blog/gruedorf/2009/05/16/scripted-animations-and-saved-games</link>
		<comments>http://www.luminance.org/blog/gruedorf/2009/05/16/scripted-animations-and-saved-games#comments</comments>
		<pubDate>Sat, 16 May 2009 13:33:59 +0000</pubDate>
		<dc:creator>Kael</dc:creator>
				<category><![CDATA[Gruedorf]]></category>
		<category><![CDATA[animation]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[platformer]]></category>
		<category><![CDATA[xna]]></category>

		<guid isPermaLink="false">http://www.luminance.org/?p=379</guid>
		<description><![CDATA[I spent some time this week building a new animation system to replace my old hard-coded player animations. Right now the player doesn&#8217;t look any different, but the new system is set up such that I can drop the animation frames my artist is working on directly into my Content folder and see them in [...]]]></description>
			<content:encoded><![CDATA[<p>I spent some time this week building a new animation system to replace my old hard-coded player animations. Right now the player doesn&#8217;t look any different, but the new system is set up such that I can drop the animation frames my artist is working on directly into my Content folder and see them in action with minor XML changes, instead of having to adjust large parts of the Player class.</p>
<p style="text-align: center;"><a href="http://www.luminance.org/wp-content/uploads/2009/05/sapphira_lines.png"><img class="aligncenter size-full wp-image-391" title="sapphira_lines" src="http://www.luminance.org/wp-content/uploads/2009/05/sapphira_lines.png" alt="" width="572" height="173" /></a></p>
<p>One of the main goals I had for the Player class was to separate the presentation-related aspects of the animations (number of frames, size, etc) from the logic-related ones. Previously, both were handled in the same C# function &#8211; to handle punching, I had an Animation_Punch function in the Player class that looked something like this:</p>
<pre>        protected Anim Animation_Punch () {
            _AttackShape = new DrawablePolygon(
                new Vector2[4]
            );

            using (Finally.Do(() =&gt; { ActiveAttack = Attack.None; _AttackShape = null; }))
            using (var a = Animation_OneShot(AnimId_Punch, 40 * Time.MillisecondInTicks))
            while (a.MoveNext() &amp;&amp; (ActiveAttack == Attack.Punch)) {
                float x = ObstructionWidth / 2.0f * Facing;
                float y = -ObstructionHeight + ArmTop;
                float w = ((Sprite[Animator.Group][Animator.Frame].Width * ScaleFactor) - ObstructionWidth) / 2.0f * Facing;
                float h = ArmHeight;

                _AttackShape.SetVertex(0, new Vector2(x, y));
                _AttackShape.SetVertex(1, new Vector2(x + w, y));
                _AttackShape.SetVertex(2, new Vector2(x + w, y + h));
                _AttackShape.SetVertex(3, new Vector2(x, y + h));

                yield return a.Current;
            }

            yield return new SetAnimation {
                Animation = (Jumping &amp;&amp; !JumpLanded) ? Animation_Jump_Fall() : Animation_Stand()
            };
        }</pre>
<p>As you can see, the presentation <tt>- Animation_OneShot(AnimId_Punch, 40 * Time.MillisecondInTicks)</tt> &#8211; and logic are mixed directly together. Also, it has hard-coded coordinates and sizes in it, in order to keep the collision detection in sync with the animation. My goal is to eliminate both such that the Animation_Punch function becomes pure logic and all of the presentation-related data lives in the animation file. The use of an animation file also eliminates annoyances like hard-coded animation IDs, replacing them with filenames.</p>
<p>The equivalent in the new animation file looks like this:</p>
<pre>            &lt;SpriteAnimation typeId="1"&gt;
                &lt;Name&gt;Punch&lt;/Name&gt;
                &lt;Group name="punch" /&gt;
                &lt;Frames delay="40" /&gt;
                &lt;NativeWrapper name="Animation_Punch" /&gt;
            &lt;/SpriteAnimation&gt;</pre>
<p>As you can see, it expresses the same information, though in some cases it is able to omit things that had to be explicit before. The Animation_Punch function still exists, but has a more clearly defined purpose:</p>
<pre>        protected Anim Animation_Punch (Anim inner) {
            using (Finally.Do(() =&gt; { ActiveAttack = Attack.None; _AttackShape = null; }))
            using (inner) {
                ActiveAttack = Attack.Punch;
                _AttackShape = new DrawablePolygon(
                    new Vector2[4]
                );

                while (inner.MoveNext()) {
                    var group = (SpriteGroup)Animator.Group;
                    var frame = group[Animator.Frame];
                    float x = ObstructionWidth / 2.0f * Facing;
                    float y = -ObstructionHeight + ArmTop;
                    float w = ((frame.Width * ScaleFactor) - ObstructionWidth) / 2.0f * Facing;
                    float h = ArmHeight;

                    _AttackShape.SetVertex(0, new Vector2(x, y));
                    _AttackShape.SetVertex(1, new Vector2(x + w, y));
                    _AttackShape.SetVertex(2, new Vector2(x + w, y + h));
                    _AttackShape.SetVertex(3, new Vector2(x, y + h));

                    yield return inner.Current;
                }

                if (Jumping &amp;&amp; !JumpLanded)
                    PlayAnimation("Jump_Falling");
                else
                    PlayAnimation("Stand");
            }
        }</pre>
<p>Oddly enough, the function actually got larger. Future refactorings will enable me to shrink it, but for now, it at least has less presentation mixed in &#8211; the actual animation itself is passed in via a parameter (inner), and the function is called as a result of being referenced by the animation file, instead of the other way around. The logic for pulling out the current frame is also abstracted out, which is another small but important improvement.</p>
<p>One of the other requirements for my animation system is the ability to set up simple triggers that cause one animation to switch to another. The way I previously implemented this was by checking the triggers every frame, using a convenience function in my C#:</p>
<pre>        protected Anim Animation_Stand () {
            return Animation_PingPong(AnimId_Stand, 50 * Time.MillisecondInTicks)
                .SwitchIf(Animation_Stand_to_Walk, () =&gt; Acceleration != 0)
                .SwitchIf(Animation_Grapple, () =&gt; Grappling);
        }</pre>
<p>Now, the entire animation lives in the file, more or less unchanged:</p>
<pre>        &lt;SpriteAnimation typeId="1"&gt;
            &lt;Name&gt;Stand&lt;/Name&gt;
            &lt;Group name="stand" /&gt;
            &lt;Frames delay="50" loop="PingPong" /&gt;
            &lt;Branches&gt;
                &lt;Branch name="Stand_to_Walk" if="Acceleration != 0" /&gt;
                &lt;Branch name="Grapple" if="Grappling" /&gt;
            &lt;/Branches&gt;
        &lt;/SpriteAnimation&gt;</pre>
<p>One detail of note here is that this means I&#8217;ve moved the conditions from compiled code (C#) to interpreted code (they&#8217;re now handled using the same expression evaluator I already use for configuring levels). This has a performance impact, but is worth it since it means I&#8217;m free to reload animations without having to recompile the game &#8211; particularly important if I&#8217;m trying to quickly fine-tune animations, since it cuts out the entire &#8216;Save, Exit, Compile, Start, Load&#8217; cycle.</p>
<p style="text-align: center;"><a href="http://www.luminance.org/wp-content/uploads/2009/05/frames.png"><img class="aligncenter size-full wp-image-388" title="frames" src="http://www.luminance.org/wp-content/uploads/2009/05/frames.png" alt="" width="576" height="479" /></a></p>
<p>Thanks to the fact that my animations were already represented as composited iterators (take an iterator that represents an animation, and then layer another iterator atop it that will play a second animation when the first one completes &#8211; and so on), the core animation code didn&#8217;t have to change at all, which was a big time saver &#8211; when I switched from the old C# animations to the new file-based ones, the animations all looked the same, so I didn&#8217;t have to spend any time hunting down minor differences.</p>
<p>One other advantage to this approach is that it&#8217;s now a reasonable idea for me to let my artist make changes to the game&#8217;s animations, instead of doing it all myself. Even fairly complex animations are understandable:</p>
<pre>        &lt;SpriteAnimation typeId="1"&gt;
            &lt;Name&gt;Jump_Falling&lt;/Name&gt;
            &lt;Group name="jump_fall" /&gt;
            &lt;Frames delay="70" first="-2" last="-1" loop="Repeat" /&gt;
            &lt;Branches&gt;
                &lt;Branch name="Jump_to_Walk" if="(Running) and (!Jumping)" /&gt;
                &lt;Branch name="Jump_to_Stand" if="(!Jumping)" /&gt;
                &lt;Branch name="Grapple" if="Grappling" /&gt;
            &lt;/Branches&gt;
        &lt;/SpriteAnimation&gt;</pre>
<p>As long as you understand XML, most of it is fairly easy to interpret. The equivalent C# would have been much harder to understand, and easier to break if my artist had to edit it to make changes.</p>
<p>The next thing I did was spend some time getting saved games working properly again. The addition of two-character support broke some parts of my saved game implementation, and it seemed like it was about time to fix them. The core problem ended up being larger than I expected &#8211; properly loading a saved game without a lot of hacks meant that I had to rethink the way I structured some of my game code.</p>
<p>Originally, objects like entities and geometry had both design-time and run-time representations. For entities, these were the LevelEntity and Entity objects. You constructed a LevelEntity with basic configuration information on the entity, and then added it to a Level. At runtime, the game would load the Level, and construct a RuntimeLevel object from it. Every LevelEntity would become a corresponding Entity in the RuntimeLevel. The core problem here was that constructing an Entity took a reference to the Game object, not to the Level or RuntimeLevel. So if I wanted to construct a new version of an entity (like a monster, or a player), I had no way to tell it which Level to use &#8211; it had to guess.</p>
<p>The first step I took was to rename Entity to RuntimeEntity, because it was getting pretty confusing. <img src='http://www.luminance.org/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  After that, I bit the bullet and changed everything such that constructing a RuntimeEntity required a RuntimeLevel instead of a Game. This meant I had to shuffle lots of things around, and update some code, but in the end, the payoff was worth it &#8211; now, I could load a new level from disk, construct all the entities and geometry, and swap it in for the current level, without any glitches. This was an important requirement for being able to undo actions like destroying walls, killing monsters, etc when the player loaded a saved game.</p>
<p>This change also helps kill off some technical debt I&#8217;d accrued in the design &#8211; lots of code in various places was jumping through ridiculous hoops, doing things like this.Player.Game.RuntimeLevel.Level.Entities[...]&#8230; in order to get at objects, so I clearly needed to rethink my dependencies.</p>
<p>One of my next goals is to add a way to place named &#8216;markers&#8217; inside my animations, so that the game logic can reference locations like the player&#8217;s left hand without having to do arithmetic every frame. Getting that working will go a long way towards shrinking the size of functions like Animation_Punch and allow me to add more detailed animations for things like footsteps and attacks.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.luminance.org/blog/gruedorf/2009/05/16/scripted-animations-and-saved-games/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

