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’ll pick a few to describe.
Posts Tagged design
Home stretch
Jul 30
Threaded Renderer
Jul 20
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’s post about the approach he uses for ordering draw calls. Some other useful sources of information were Tom Forsyth’s post about the cost of renderstate changes and Guerilla’s presentation on Killzone 2’s renderer from DEVELOP 2007. The Killzone 2 presentation is especially worthwhile since it describes the way they take advantage of concurrency techniques in their renderer.
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’s GraphicsDevice and SpriteBatch to render themselves, changing render states as needed and generating dynamic geometry where necessary (like for water).
Shipping a Brick
Jul 15
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’s quite impressive that modern games still run for the majority of users. But here’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.
A few years back I was doing design work on an MMORPG. Really satisfying work – come up with characters & 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.
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’t own the game to create characters and play for the duration of the weekend. Great idea – 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’s coming down the pipe because you’ve let them play it for a couple days.
I was pretty excited about it, since it was the first promotion of its kind that we’d run since I had started working there – 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’t even looked at the game since they had to pay for it first – and who can blame them, really?
Friday rolls around and I head home late and get some rest. The rest of the team does the same.
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’re both pretty enthusiastic about it and get started. A few minutes later, one of them says:
‘Why can’t I use any skills?’
What? What do you mean you can’t use any skills? Are there buttons on the bar at the bottom of the screen?
‘Yeah, but they have little lock icons over them. Nothing happens when I press them.’
Well, uh, s–t. That’s not supposed to happen. I emailed one of my coworkers to ask – uh, did anyone try creating a brand new account for the promotion to see if it worked? – and the answer is depressing: Nope. Luckily, it wasn’t a total loss – our existing customers were still able to participate in the event, because they already had working accounts. But for new, potential customers – the game didn’t work. They downloaded and installed our game, and it was mostly useless to them.
Read the rest of this entry »
Camera Constraints
Jul 15
As the level I’m currently building has gotten larger, it’s become obvious that I need a way to control the behavior of the camera – simply centering it on the player isn’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’t have anything in place for more advanced control of the camera, like constraining it to a region of the level.
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 – 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’t see any ugly empty space while the camera panned around.
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’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 – no point in showing boring repeated tiles to the player when we could be showing interesting parts of the level instead.
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 ‘drift’ away from the point. The end result was that I had a series of ‘rails’ the camera could follow through the level, of varying thickness depending on the radius of each point.
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 – a complex deployment process discourages you from getting customer feedback, and increases the likelihood that you’ll make a mistake and end up with a failed deployment, which wastes valuable time.
For most of my previous projects, I’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 – no install necessary).
Cutting and tuning
Jun 12
As far as gameplay goes, the only major addition since last week’s post was a relatively complete implementation of player death, along with the ‘reunion’ teleport that goes with it. Fairly simple at present, with some bugs to work out (including one related to the teleport location that you’ll see in the video below). Definitely helps get a better feeling for whether a given puzzle is too hard or too easy.
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’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 – 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.
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 – finding other hotspots in my profiler data and reducing the cost.
Well, it was trivial until I ran the game on the 360 again and noticed that the framerate hadn’t improved very much. Huh? I doubled my framerate on the PC, but on the 360, it barely moved an inch. What’s the deal?
Turns out, the 360’s pitiful floating-point performance was kneecapping me. Believe it or not, the primary culprit was the geometric shapes in the game’s HUD, for the circular health displays you may have seen in previous screenshots/videos. I knew the 360’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.
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…
The majority of my work ended up focusing on the game’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.
Towards this end, after getting one of my main mechanics prototyped and testing it out in content I’d built, I made the hard decision to cut the mechanic. The second controllable character you’ve seen in some of my previous videos is effectively gone, though I’m going to attempt to make use of the design and code effort for the revised design.
Making a choice like this is always painful, especially when you don’t have an unchangeable deadline or overbearing boss pushing you towards it. But ultimately, I think I’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’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’t worth pursuing, and cut it. Definitely an improvement over traditional Waterfall with long cycles, but not quite true Agile yet.
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’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 – 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.
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’s a great decision.
Prototyping week
Jun 5
The main thrust of this week’s work was gameplay prototyping. I spent the majority of my time prototyping gameplay – 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 that I could make composite objects for use in puzzle designs. In the following video, I’ve attached a Crank (a new variation on my existing Switch object, which I’ll describe a bit later) to a moving platform, and tied the crank to the platform’s velocity so that you can use it to move the platform:
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 ‘come here’ or ’stay there’) 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:
The culmination of my work this week was constructing a larger puzzle prototype that combines many of the smaller elements I’ve built previously. It’s a puzzle that utilizes the Assist mechanic along with many of the mechanics and technologies I’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’ll no doubt have to address in the coming weeks. Nonetheless, it was quite satisfying to see it take shape:
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’s UI and was finally able to beat it myself:
Naturally, a lot of work still remains, both in the art, design, and technology departments. But it’s nice to finally be able to build a piece of content this large without running into any showstopper issues – all said, it took me about 45 minutes to construct and tune this puzzle in my editing tools. Not as fast as I’d like, but more than good enough to get started on enough content to fill a playable demo.
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 – 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.
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’s nice to be able to see such large performance gains from little effort, but on the other hand, I’m a little embarassed that I didn’t think about it earlier.
It’s likely that in the future I’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’t end up having to send thousands of batches to the video card every frame.
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’t put solving this one off for too long.
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’ve built. I’m looking forward to having things at the point where I can start handing out test versions for people to bang on.
Finally, a question for anybody who’s reading on a regular basis: The Gruedorf weekly progress format is becoming rather difficult to work with lately, so I’m considering changing my approach for this development log. I’d greatly appreciate it if you let me know via the comments section which topics interest you the most, and whether you’d be interested in seeing multiple shorter posts during the week focusing on single topics.
Bits and pieces week
May 29
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
- Moved jumping, ledge clinging and mantling from using tasks to using a combination of animation triggers and simple state machine logic
So, I guess I’ll give each bullet point a little detail.
Adding spikes was fairly straightforward. The largest challenges were getting the collision detection and rendering to work correctly. All the geometry I’ve added to levels before now has simple collision detection, in that the geometry remains relatively static and obstructs the player’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’s collision on the fly – 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’s touching.
_CollisionList = _DrawList; this.FindObstructions(this.InflictDamage); _CollisionList = Game.NullCollisionList;
Rendering the spikes was a bit of a challenge as well – since they’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’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 – determining the proper inputs to a SpriteBatch.Draw call can be challenging when you’re rotating, scaling and translating all in one go, so it involved a lot of trial and error.
Some investigation of issues I was running into with standing on surfaces revealed that my current approach was getting too complicated and fragile – 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.
The solution to this ended up being simple: Where previously, I’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’s left and right edges. This way each object could have its own implementation for handling uneven surfaces – 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’t actually any harder to write than the old ones – 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:
public override float? ComputeStandingY (float x1, float x2, float y) {
var p = _CollisionList[0];
if ((x2 >= p[1].X) && (x1 <= p[2].X))
return Anchor.Y;
else if (x2 < p[2].X)
return RuntimeTriangle.ComputeStandingY(p[0], p[1], x1, x2, y);
else
return RuntimeTriangle.ComputeStandingY(p[2], p[3], x1, x2, y);
}
While other handlers, like Triangle, required only minor changes to account for the addition of a second X coordinate:
public static float ComputeStandingY (Vector2 slopeBegin, Vector2 slopeEnd, float x1, float x2, float y) {
var minX = slopeBegin.X;
var maxX = slopeEnd.X;
if (x2 < minX)
return slopeBegin.Y;
else if (x1 > maxX)
return slopeEnd.Y;
var startY = slopeBegin.Y;
var endY = slopeEnd.Y;
var dX = maxX - minX;
var dY = endY - startY;
float x = (dY > 0) ? x1 : x2;
var d = (x - minX) / dX;
var result = startY + (dY * MathHelper.Clamp(d, 0.0f, 1.0f));
return result;
}
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.
Earlier this week I got the art for one of the player characters’ 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’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.
The end result looks pretty good. The basic approach looks like this:
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) && (!_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
));
}
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’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’s code can keep track of the surface it’s mantling onto and what the source and target positions are, for animation purposes. Next, I lock the camera on the player’s original position, so that it won’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.
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 – 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 ‘crouch to stand’ animation immediately after completing a mantle, so that the player appears to quickly stand back up after climbing onto a surface.
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.
And finally, this brings me to the task changes. As you might have noticed, previously I used tasks to structure ‘long-lived’ 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 ‘is the player mantling’ 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 – early prototypes contained some utterly terrifying state machines before I simplified things by switching to tasks.
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.
For the most part, the process was straightforward – I added boolean fields to track the player’s state where I previously used a task (so the player now has LedgeClinging and Mantling flags that he didn’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’s at least remaining relatively small and encapsulated.
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;
}
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’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’t even attempt to grip onto a ledge if he’s moving away from it.
All in all, a productive week!
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 – for example, lining up a weapon with a character’s hand, or doing hit detection against a character’s hand instead of his entire hitbox.
Once I had some simple markers for the player’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:
<SpriteMarker typeId="2"> <Name>Left Foot</Name> <Groups> ... <Group name="run"> <Frames> <Frame anchor="tl" x="80" y="170" index="0" /> <Frame anchor="tl" x="61" y="169" index="1" /> ... <Frame anchor="tl" x="132" y="143" index="6" /> <Frame anchor="tl" x="99" y="173" index="7" trigger="Footstep" /> </Frames> </Group> </Groups> </SpriteMarker>
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’s feet land on the ground during his run animation:
public void Footstep (string foot) {
if (Jumping && !JumpLanded)
return;
var pos = ResolveMarker(foot);
if (!pos.HasValue)
return;
Game.SpawnSmokePuff(Position + pos.Value - GetDrawOrigin(Animator.Frame), 10, 0.5f);
}
The real motivation behind the marker system, however, was syncing animations with the game world – I wanted the player’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.
Essentially, where before I used hard-coded coordinates and percentages, now I ‘resolve’ one of the player’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’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’s hand:
public Vector2 GrappleFrom {
get {
var handPos = ResolveMarker("Right Hand");
return Position + handPos.GetValueOrDefault(
new Vector2(0, Obstruction.Y * -0.5f)
) - GetDrawOrigin(Animator.Frame);
}
}
After using this technique to make the player’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 – before increasing the size of the player’s bounding box, do a quick collision check to see if the player’s current bounding box is able to move upward by that same amount. If the check fails, I now know exactly how far the player’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.
Once the player is out of a tight space, I can grow the bounding box to its full height, restoring sanity. It’s not perfect (and looks kind of stupid since it allows the player’s head to stick through ceilings), but it was relatively simple to implement. I suspect I’ll end up with a different solution in the final game – perhaps forcing the player to stay crouched if he can’t stand up in his current position.
During the process of rigging up the player’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:
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’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’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:
this.Sprite.Animations["Walk"].Run(this.SpriteContext);
Now, I have something like this:
Game.Sprites[this.SpriteName].Animations["Walk"].Run(this.SpriteContext);
A bit more verbose, but easy to abstract out using properties and helper methods – such that actual game code can just use convenience methods, like so:
this.PlayAnimation("Walk");
And everything happens behind the scenes.
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’s Draw function. First, I changed the signature of most of my objects’ Draw methods, such that they now take an extra parameter:
public override void Draw (DrawFlags flags) {
Then, the game code can pass a combination of flags to an object to specify which types of rendering to perform:
if (ShowHUD) {
var flags = DrawFlags.HUD | (GlobalDrawFlags & DrawFlags.DebugHUD);
RenderGeometry(flags);
RenderEntities(flags);
}
As a result, I have the ability to easily toggle off sections of an individual object’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 ‘EditorDraw’ method to the objects (like I had before in a few cases, unfortunately).
With the addition of a couple extension methods to simplify things, it wasn’t too hard to wire things up inside my game objects. For example, this is what SpriteEntity.Draw looks like:
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();
}
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 – 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’ bounding boxes don’t need to cover everything, so I draw them in the same pass as the entities themselves.
For the curious, the extension methods I ended up writing look like this:
public static bool Check (this DrawFlags drawFlags, DrawFlags flag) {
return (drawFlags & flag) == flag;
}
public static DrawFlags Toggle (this DrawFlags drawFlags, DrawFlags flag) {
return ((drawFlags ^ DrawFlags.All) & flag) | (drawFlags & (flag ^ DrawFlags.All));
}
They’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’s at least fairly easy to add with extension methods. Unfortunately, generic types and enums don’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.
I spent some time this week building a new animation system to replace my old hard-coded player animations. Right now the player doesn’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.
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 – to handle punching, I had an Animation_Punch function in the Player class that looked something like this:
protected Anim Animation_Punch () {
_AttackShape = new DrawablePolygon(
new Vector2[4]
);
using (Finally.Do(() => { ActiveAttack = Attack.None; _AttackShape = null; }))
using (var a = Animation_OneShot(AnimId_Punch, 40 * Time.MillisecondInTicks))
while (a.MoveNext() && (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 && !JumpLanded) ? Animation_Jump_Fall() : Animation_Stand()
};
}
As you can see, the presentation - Animation_OneShot(AnimId_Punch, 40 * Time.MillisecondInTicks) – 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.
The equivalent in the new animation file looks like this:
<SpriteAnimation typeId="1"> <Name>Punch</Name> <Group name="punch" /> <Frames delay="40" /> <NativeWrapper name="Animation_Punch" /> </SpriteAnimation>
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:
protected Anim Animation_Punch (Anim inner) {
using (Finally.Do(() => { 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 && !JumpLanded)
PlayAnimation("Jump_Falling");
else
PlayAnimation("Stand");
}
}
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 – 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.
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#:
protected Anim Animation_Stand () {
return Animation_PingPong(AnimId_Stand, 50 * Time.MillisecondInTicks)
.SwitchIf(Animation_Stand_to_Walk, () => Acceleration != 0)
.SwitchIf(Animation_Grapple, () => Grappling);
}
Now, the entire animation lives in the file, more or less unchanged:
<SpriteAnimation typeId="1">
<Name>Stand</Name>
<Group name="stand" />
<Frames delay="50" loop="PingPong" />
<Branches>
<Branch name="Stand_to_Walk" if="Acceleration != 0" />
<Branch name="Grapple" if="Grappling" />
</Branches>
</SpriteAnimation>
One detail of note here is that this means I’ve moved the conditions from compiled code (C#) to interpreted code (they’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’m free to reload animations without having to recompile the game – particularly important if I’m trying to quickly fine-tune animations, since it cuts out the entire ‘Save, Exit, Compile, Start, Load’ cycle.
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 – and so on), the core animation code didn’t have to change at all, which was a big time saver – when I switched from the old C# animations to the new file-based ones, the animations all looked the same, so I didn’t have to spend any time hunting down minor differences.
One other advantage to this approach is that it’s now a reasonable idea for me to let my artist make changes to the game’s animations, instead of doing it all myself. Even fairly complex animations are understandable:
<SpriteAnimation typeId="1"> <Name>Jump_Falling</Name> <Group name="jump_fall" /> <Frames delay="70" first="-2" last="-1" loop="Repeat" /> <Branches> <Branch name="Jump_to_Walk" if="(Running) and (!Jumping)" /> <Branch name="Jump_to_Stand" if="(!Jumping)" /> <Branch name="Grapple" if="Grappling" /> </Branches> </SpriteAnimation>
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.
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 – 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.
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 – it had to guess.
The first step I took was to rename Entity to RuntimeEntity, because it was getting pretty confusing.
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 – 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.
This change also helps kill off some technical debt I’d accrued in the design – lots of code in various places was jumping through ridiculous hoops, doing things like this.Player.Game.RuntimeLevel.Level.Entities[...]… in order to get at objects, so I clearly needed to rethink my dependencies.
One of my next goals is to add a way to place named ‘markers’ inside my animations, so that the game logic can reference locations like the player’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.




