[ ]




Brian - September 6th, 2010 - Indie Game Jam!

It's been a long time since I participated in any time-constrained game development competitions, and with some free time (not really) available this weekend, I decided to attend the Triangle Indie Game Jam in Raleigh. It was a three-night event, so I'll describe the nights in order and then post screenshots of our final product. I'm going to focus more on the process and less on the game, which I will talk about in another post.

Friday:
Friday was 'planning night.' About 7 people showed up and pitched ideas for a game with a common theme: Placing Blocks. I pitched two ideas:
(1) A puzzle game where balls would constantly fall and you have to place blocks to get them to bounce to a goal.
(2) A tower defense/reverse Jenga style game where attackers are constantly weakening your tower, and you have to place pieces to keep it from tumbling.

Between the seven of us, about 18 ideas were pitched. I'm not going to enumerate them all, but in the end, the four that were picked are thus:
(1) A Rogue-Like where, instead of attacking creatures, you pick up blocks in the world and then place them elsewhere to try to avoid/manipulate enemies.
(2) A game where blocks of different colors constantly fall into gates, and you have to open/close gates strategically so that when the blocks pass through, they form an image.
(3) A reverse Jenga style game where you must build a structurally sound tower.
(4) A Lemmings-like where instead of assigning jobs to the Lemmings, you manipulate the environment to get them to appropriate positions.

I decided to go the Rogue-Like route, having a random dungeon generator already written and some interest in the genre. I was joined by Mike Lee and Mike Daly.

Saturday:
On Saturday development started in earnest and lasted from 9:30 AM until about 11 PM. We decided to break the project up into 4 distinct phases of development.

In Phase 1, we targeted standing up a lot of core code, get movement and (super basic) enemy AI in, allow creation and destruction of tiles, and put all the major state transitions (win, lose, main menu, etc) in place.

In Phase 2, we targeted picking up and dropping blocks properly, where blocks would be stored in an inventory. We wanted all the different tile types implemented. We also wanted random dungeon generation and a couple more enemy types. SFX were planned, but we cut those from the phase.

In Phase 3, we planned for race/class selection, limited vision, spells, and music.

In Phase 4, we wanted to implement all the enemy types and make things shine a little more, with multiple level themes and seamless graphics.

After planning the phases, we started some extreme programming for a couple hours, where we all huddled around Mike's computer and outlined the core code. There wasn't a lot - enough to get a solid Rogue-like simulation running, but it was a fair start and got us to the point where we could break up tasks.

Upon breaking up tasks, I initially spearheaded most of the rendering and level creation. As we pressed on and people finished tasks, we just started pulling things off a list that we were interested in doing. It was a fairly distributed bunch, with me on a lot of the rendering/map generation/level progression, Mike L on enemy AI/importing graphics/tile types, and Mike D on actions/menus/HUD. Which isn't to say that anyone had clear roles, since we all regularly grabbed arbitrary items out of the task list.

We blasted through Phase 1; Phase 2 had a lot of work in it, but even it went quickly. By the day's end, we were ramping up on Phase 3 and planning out our next (shorter) day.

Sunday:
Sunday development went from approximately 9:15-5:15.

Phases 3 and 4 blended into each other at this point - we compiled a list of all the things we wanted to get, a wish-list of things we knew probably wouldn't get in, and ideas for how to improve the gameplay. There was a lot of back and forth on how to make the game fun and how to make the concept work, and by the end we had a list of about 20 tasks to knock out.

So we just got to it. Though we prioritized the items, we jumped up and down the list regularly based on what each individual thought was important or wanted to work on.

And we got nearly all the list done. We did have to cut spells, SFX, and a bit of polish, but we spent the saved time adjusting stats and gameplay parameters instead; a rewrite of the control scheme, for instance, though not strictly necessary ended up making the game much more playable.

At 5:15, development stopped and people showed off their projects.

Recap
In the end, our little 3-man team made a fully-featured, well constructed game in just under 24 hours of work. Our code base is terrifying, but that doesn't matter.

Here are some (blurry) screenshots of our finished product!

Brixplorer Title

Brixplorer Character Select

Brixplorerer Play 1

Brixplorerer Play 2

0 Comments - Leave a Comment

Brian - August 8th, 2010 - See the Light Android Sales Update

It's time for everyone's favorite foray into small numbers:

Trials - 1556
Sales - 25
Total Profit - I don't wanna think about it

Man: Are you Abe "The Rail Splitter" Lincoln?
Abe: Used to be. These days they call me Mr. President.

1 Comment - Leave a Comment

Brian - July 29th, 2010 - Abe Lincoln and the Velociraptor

I wrote up this pitch document late last night for a new game idea. The premise is that Abraham Lincoln travels back in time and meets a velociraptor, and the two fight crime together.

I don't like to brag, but it's solid gold.

Bugs remaining: 3.

3 Comments - Leave a Comment

Brian - July 25th, 2010 - A Look Into the Iron Heinrich Material System

Though all of Iron Heinrich's gameplay takes place on a 2D plane, the entire rendering system is 3D - think Viewtiful Joe or Shadow Complex. This allows us a visual style that isn't possible with 2D, and it also affords us lighting, shadows, camera tricks, and other neat things. It is, however, much more complex.

There are plenty of points of complexity, but in this post I'm going to focus on the material system. The material system is designed to allow the artist, Nate, to setup the visual style of characters and levels.

Requirements
The goal of the material system are as follows:
(1) Completely data driven. If Nate wants to change a shader or a shader parameter, he shouldn't have to talk to the programmers at all.
(2) It must support setting shader parameters that are hand-specified by the artist as well as parameters that the engine delivers.
(3) It must support multiple render passes to make things like full-screen post-fx simple and, again, data driven.

What it will not support:
(1) Dynamic shader generation. There's plenty of work that could go into writing uber-shaders or fragment based shaders, but our shader requirement is minimal (we hope), so for now Nate will be driving those all by hand.
(2) Rapid iteration - Nate will have to restart the application to see his material changes. We may be able to shoe-horn this feature in, but it's not in the design.

Materials, Material Passes, and Render Passes
There are three primary players in the system, which I'm going to overview briefly and then talk about in more complexity.

Materials are the top-level item, and each model has its own Material - for right now only a single Material, though that may change later. At their core, Materials are just a collection of Material Passes.

Material Passes are where most of the data gets specified. These specify the shader effect that gets used along with any parameters.

Render Passes represent each pass of the renderer. During a Render Pass, the Material Pass of the same name is evaluated. Render Passes themselves control the render state, the render target, and the current camera that gets used.

Now let's talk about each component with a bit more depth.

Materials
There's not much more to say about Materials. They are a collection of Material Passes, which do all the heavy lifting.

Material Passes
Material Passes do the bulk of the work. During the evaluation of a Render Pass, Material Passes of the same name as the Render Pass are selected to be executed - only if they exist. If a model doesn't have a Material Pass for the current Render Pass, it won't be rendered.

The Material Pass specifies two primary things:
(1) The effect (shaders) that will be used.
(2) The parameters that will get passed into the shader.

#2 requires more elaboration, since Material parameters take on a lot of forms. In general, there are two kinds of Material parameters:

The first kind is a hand-specified value. This could be a uniform float, the file name of an input texture, or a matrix of some kind. They're typed key-value pairs, where the key is the name of the shader parameter (the uniform) and the value is, well, the value.

The second kind is an engine-specified value, what I call an 'auto' parameter. This could be a dynamically generated texture, the current camera matrices, or the name of a light. These are just names of parameters that the engine handles, and when one is seen the renderer retrieves the appropriate value and passes it on.

Render Passes
A Render Pass is a single run at rendering the scene. During a Render Pass, the scene collects all the Material Passes of the same name for rendering, sets up the render state/render target, and renders all the models that have the appropriate Material Passes attached to them.

Render Passes keep track of the following:
(1) The render state. These are various parameters that are used to do things like turn on/off culling, change blend modes, etc.
(2) The render target. This is a named target that can be rendered to and then used later as a parameter specified in a Material Pass.
(3) The size of the render target. We don't want to always draw to screen-sized render targets, since sometimes that's a waste of memory.
(4) The camera. Each Render Pass can render from a different camera. This is necessary for doing things like good water rendering.

Use Case #1
That's a big wall of text and no doubt hard to grasp, so I'm going to provide a couple use cases so you can see how this all plays out.

This first use case will be rendering a scene to a color buffer and then applying a post effect to do a blur. It's not terribly hard:

We have two Render Passes with the following parameters:
Render Pass RP1:
Render State: Default
Render Target: TextureA
Camera: Default Scene Camera

Render Pass RP2:
Render State: Default
Render Target: Screen
Camera: Orthographic Screen-Sized Camera

At this point, the entire scene is filled with normal entities. These entities all have very generic Materials, where each Material has a single Material Pass - named RP1, which designates that generic rendering will occur during the first render pass.

There is also a special item in the scene - a full-screen quad with a Material possessing a Material Pass named RP2, indicating it will only be rendered during the second Render Pass. This Material Pass has some special parameters:
Texture: TextureA
Effect: BlurEffect

Thus, after the entire scene is rendered, the quad will be rendered to blur TextureA (and since it is part of RP2, the result of that blur will go to the screen).

Use Case #2
This will be a toon effect and has the following Render Passes:

Render Pass RP1:
Render State: Default
Render Target: TextureA - a color texture
Camera: Default Scene Camera

Render Pass RP2:
Render State: Default
Render Target: TextureB - a normal texture
Camera: Default Scene Camera

Render Pass RP3:
Render State: Default
Render Target: Screen
Camera: Orthographic Screen-Sized Camera

The Materials are largely the same as the first use-case. Even the full-screen quad is nearly identical, though it gets passed in both TextureA and TextureB and has a different effect.

Conclusions
The system has room for improvement. A shader fragment system would be nice but is a bit beyond our needs. It also necessitates writing Materials just to throw in test objects, which can be cumbersome (we have a 'test' Material to slap on for those instances). Binding Material Pass Names and Render Pass Names together is perhaps a bit of a mistake but works for our needs. Documentation also needs to be in place to remember all the different effect parameters and such.

Flaws aside, the system has been treating us pretty nicely. Nate can autonomously add complicated shader effects and change the rendering system at his whim. Later, it shouldn't be hard to write tools to make the process even smoother.

I hope you don't mind, we've reinstated your license to kill.

0 Comments - Leave a Comment

Brian - July 17th, 2010 - Recycle Array

When I was writing Word Duelist, I was scrambling for a way to improve performance and reduce garbage generation. One area where this was prominent was the particle system, a system which would repeatedly generate lots of light-weight objects and discard them soon after.

After doing a little research, I stumbled upon a handy little data structure that works like the following:
Creation: Create a fixed pool of memory (with a maximum size) with pre-allocated 'dummy' objects.

Addition: Get an item from the next free spot in the pool and let the caller fill that item out appropriately. One important side-effect is this may involve exposing more of your object than you'd like since you won't be using the constructor again.

Removal: Swap the item to be removed with the last valid item in the array and decrement the size.

The data structure has the following characteristics:
(1) All memory is allocated up-front.
(2) O(1) item "addition"
(3) O(1) item removal
(4) O(N) search, O(1) random access
(5) No garbage generation. We're working with a fixed pool where items don't actually get deallocated until the array is destroyed.
(6) Unstable - the order of the objects will change

#6 is worth mentioning - the data structure does not provide any guarantee that the order you add items will be the order those items are in at any time. Thus, this is best used for something where you don't care about the order, like a particle system.

Here's a (admittedly rough) mockup implementation:

Just something I slapped together in 20 minutes, so there's clearly room for improvement. If someone has a better name than "Recycle Array" I'd be happy to change it - I'm not terribly happy with the name.

Found some awesome games in the XBLIG playtest queue.

2 Comments - Leave a Comment

Brian - July 16th, 2010 - See the Light (Android) Breaks 1000 Trials…

...Still only 16 sales.

Boo.

2 Comments - Leave a Comment

Brian - July 5th, 2010 - One Step Back, 1.5 Steps Forward

PVRTC for the iPhone/iPad sucks, but it's a necessary evil.

PVRTC is a texture compression format. It's a fixed-ratio block compression format meant to be decompressed by graphics hardware, hence allowing you to store more texture data in the limited texture memory available on the hardware. PVRTC also has the distinction of being the only compressed texture format available on the iPhone & iPad.

So then why does it suck? Two reason:

(1) PVRTC is not good with gradients or sharp edges. Uhhhhh. OK. This may leave you with the question, "Well, what is it good with?" And I present to you my answer: "I don't know." Depending on what compression tool you use, PVRTC compressed images can be OK or they can be unbearably bad. I find the official Power VR tool for Windows to be reasonably good and not too slow.

(2) PVRTC only supports square power-of-two (pot) sized textures. This is the big one. The pot texture restriction has been common-place for some time now. The square restriction, however, is a bit of a problem.

Allow me to expand on #2. The problem comes when you're dealing with a sprite based game. Sprite based games tend to have various sprite sheets that contain all the animations for the sprite - or alternatively (and badly) each frame of animation is its own image. In either case, you very rarely have images that fit neatly into a square pot-sized image.

You have a couple of options here:
(a) You can pad the images to the nearest available size.
(b) You can break apart your sprite sheets so that they're close to available sizes, and then pad those.
(c) You can devise a clever scheme for packing images together to get the packed images close to an available size and then... pad those.
(d) You can resize your images to make them larger/smaller. And then pad as necessary.

Unfortunately, pretty much all of these solutions have accompanying problems.
(a) You're likely to end up with some pretty big images and a pretty huge waste of space. If your sprite sheet is, say, 512x1024, it now becomes 1024x1024. It doubles in size.

(b) Breaking apart sprite images can be pretty time consuming. Especially if you're doing it after-the-fact; by the time you actually run into a memory problem, you've created a lot of work for yourself.

(c) In all likelihood, you'll be loading more in a section than you need to. If you pack two images together and you find that you only need one during the level, you don't have the option of only loading the one. Plus this has the same problems as (b) - it can be a lot of work.

(d) No artist wants to see his carefully crafted image scaled unnecessarily, losing detail. And in this case you're either losing detail or using more memory, none of which you want.

If we ignore added workload, most of these drawbacks come back to the same bit of text that repeated itself while I presented the options - "pad the images." Whatever you choose, you're likely going to be padding images significantly - making them powers of two may not be a huge deal, but making them square will likely be painful. You're looking at doubling a given dimension for a lot of images. Ew.

How bad is this really? Well, obviously when you're fighting for every bit of memory, it's very far from the ideal. It may, however, not be a deal breaker. It turns out that in terms of FILE SIZE, padding a PNG and then compressing it using PVRTC can do anything from make it slightly smaller to slightly larger (depending on the amount of padding, of course). Taking a 512x1024 PNG, padding it to 1024x1024 (ew ew ew), and then running it through the Power VR compression tool will usually generate a larger image; I don't remember numbers off-hand, but I think it was about 300KB - 500KB larger.

In terms of MEMORY USAGE, though, you're likely to still get a big win. PNG gets completely decompressed before going to hardware. I took a 2MB PNG and decompressed it in GIMP to export an 8MB raw image. PVRTC does not get decompressed in the same fashion, so if you have a 2MB PVR image, the hardware is receiving 2MB. Of course, that win is bigger when you don't have to add a huge empty buffer onto your images, but it's clearly much better than nothing.

I do look forward to the days when Apple drops the square size restriction.

Did I inadvertently sign up for a Becca-themed newsletter?

0 Comments - Leave a Comment

Brian - July 1st, 2010 - Scalable Art Via Manifests

In a lot of code - my code even - you see statements like this a lot:

DrawImage(x, y, image.width, image.height)

Basically, draw the whole image. This seems like a perfectly harmless statement, but it doesn't scale. The problem portion is that we're keying off the image's size.

"But Brian," I hear you start as I look upon your pouty face, "I want to draw the whole image. What else would I do?"

The answer is that you'd still specify the asset's source rectangle ala some manifest file and keep that file up to date.

"But Brian," you continue, that ugly expression still present, "That's extra work for no perceptible gain."

And here's where I talk to you about the perceptible gain:
Things go wrong. One day you're going to run out of memory or you're going to want to port the game to some other platform. You'll find that your images really need to be square powers of 2 for your texture compression to work (stupid PowerVR), and so you add some padding only to find that your previous code does not support the change. You'll find that you need to pack a lot of little images into one big image to help with compression or load times or texture thrashing or whatever, and so you do that only to find your previous code does not support the change. You'll find that you want to move to a platform that doesn't support large images and so you have to break up your big images into smaller ones, and so you do that only... you get the point. Now you're faced with a lot of extra work and a lot of potential bugs.

"But Brian," you're really irritating at this point, and I just want to slap you, "an extra file means another place to forget things and add errors."

That's reasonable but not terribly burdensome. If you need to add files to the manifest before you ever see them in-game, then when you forget to add a file you'll spot it almost immediately (assuming you test like a good engineer). If it's really too much for you, there are certainly ways to auto-generate the manifest depending on how you do texture packing/padding.

My next post will be on PowerVR and why it sucks.

Entering Apple Bashing mode...

2 Comments - Leave a Comment

Brian - June 29th, 2010 - See the Light Android Gets a Good Review!

See the Light: A twist on Puzzle Games at Android Headlines.

I'm glad they enjoyed it. They did point out some glitches, a few of which flew right under my radar, but luckily nothing I think is too severe.

While I have your attention, two updates on the See the Light front:
(1) It just received a temporary price drop to 0.99 until Friday. This is for a limited time. If you were waiting to purchase the game but $2 was just too much, you're in luck.
(2) Laura's working on a dedicated site for the game. Should be finished in a couple days.

"This game is a must download if you are into puzzle games."

0 Comments - Leave a Comment

Brian - June 28th, 2010 - A Super Simple Maya Level Exporter

I don't want to write tools for Iron Heinrich. Period.

Let me expand on that: writing tools has its charm, but I'm more interested in making games. I've spent the bulk of my professional game industry career working on tools in some fashion. I know they're a lot of work, and you can easily get lost in them without ever actually producing a product. I don't want that. I want to release a game.

This leaves two options for us:
We could hand-write all our data. Or we could use tools already available to us. Spend about 12 seconds hand-writing an XML file and you already know option #2 is the correct one.

This is no more true than when creating level data. Levels get pretty freaking big, hence a lot of data needs to be generated. Writing level editing tools is not by any means a trivial task - after working on two at Emergent and one at EA, I can safely say it's a hefty undertaking that could easily swallow an engineer's entire development bandwidth during a project.

Luckily, if you're developing a 3D game, you've got a level editing tool staring you in the face. It is your 3D modeler.

Nate has access to Maya. Maya is a complicated, complicated, beast that does a gagillion things. "Level editing" isn't natively in its repertoire, but it's not a huge leap. You can edit geometry. You can reference external models and move/morph them around. You can tag nodes with extra data. And you have all those lovely tools the Maya engineers have already written to help here, which can save you tremendous amounts of time.

There's some leg-work, no doubt. You'll probably need an export step to send the data out in the exact format you want, and this will mean writing a plugin or a script. Depending on the 'extra data' you need to tag your entities with, you may find yourself wanting to create custom Maya dialogs to streamline editing. This isn't hard necessarily, but it's still work. Work I'm currently looking at.

Thus, I present you with a super simple maya level exporter:

This guy is about as trivial as it gets. All it does is iterate over your external references and spit out their node name and transformation information. In Iron Heinrich, 'node name' translates directly to 'entity template name,' which is where all the extra data gets specified. We can bring in arbitrary entities or even drag in spawn points and triggers. Run this script and separately export the level geometry and you've got a good portion of the level specified with only a small amount of work.

Of course, this is oversimplified and won't reflect the final export step, but it's a start. We'll definitely need to have a way to specify lighting, camera cues, and assorted random bits, but that will come as we go. For now, I'm happy having the ability to edit levels in under an hour.

This won't be the solution for everyone. Your game may require special tools that don't integrate well within Maya. It's hard to get Maya to integrate with your game to do things like rapid iteration. You don't get a perfect visual of how the game will look in-engine without exporting and running. These are all things that a custom tool can do more easily. However, a fully in-Maya approach is perfectly valid (I have witnessed it used by professional studios to varying degrees of success), and at the very least, I think it will be good enough for Iron Heinrich.

Next on the agenda: enemy interaction

0 Comments - Leave a Comment

Previous Entries