Archive

Zero to One Hundred Thousand Tests

When I started at StrongDM five years ago (woah), we had zero automated tests. Last year we had 50,000 tests. Today, around 70% of our code is covered by over 100,000 tests, most of which run on every pull request.

What follows is my personal opinion about what constitutes a “good” automated test based on my observation of this colossal increase in test coverage. The goal is not to convince you I’m right, but to draw some contrasts and provoke you to question assumptions and form your own opinions.

Catch Your Dream

When I was young, my dad had a Power Macintosh 6500 and a copy of a game called MechWarrior 2: 31st Century Combat. By my estimation, it was not very good. It was slow and boring and I mostly got confused and died.

However.

It had the absolute coolest intro cinematic of all time. It still gives me goosebumps.

After the intro and a minute or two of listening to the 12X CD-ROM drive spin, I had to face the menus. If I was lucky (what’s a “campaign”?), I would eventually blunder my way into the actual game and then the real frustration began. Nuclear submarines have more intuitive controls.

The start of a game development journal

I am starting a journal for my game development work because I spend a lot of development time thinking and staring into space, and those thoughts don’t always make it into the game. I need an outlet to direct those thoughts and hopefully make them more useful. The project I am working on is also personal and necessarily relates to my feelings about life and art and God, and I need a place to write those things down too. I may publish some of these entries on my blog.

The Identity Problem

Disclaimer: views expressed are my own and are not endorsed by my employer.

It’s a famous joke that naming things is one of the hardest problems in computer science. I think this alludes to a fundamental truth behind so many of the problems I encounter every day as a software engineer. Let me ruin the joke and reword it a bit.

The hardest problem in computer science is deciding whether two things are the same thing, or different. I don’t know if there’s already a name for this concept, but I’ll just call it the “identity problem”.

Waiting on Tests

Disclaimer: views expressed are my own and are not endorsed by my employer.

In 2019 we had roughly zero automated tests at StrongDM. We did manual quality assurance testing on every release. Today we have 56,343 tests.

Anecdotally, the rate of bugs and failures has not decreased by a commensurate amount. Instead I think it correlates with focused efforts we’ve made at various times to either ship big new features (resulting in many unforeseen bugs), or stabilize existing features (resulting in fewer bugs).

Making Games

Columbus, 2017

In March 2018, I had been a full-time indie game developer for four years. My heroes were Jonathan Blow, Lucas Pope, and Robyn and Rand Miller. I had 2,500 Twitter followers, an ambitious title under my belt with thousands of sales, and a free office in a hip coworking space near downtown Columbus, generously provided by some friends at a local game studio. I distinctly remember wondering why anyone would want to be something other than an indie game developer. I joked that I had a “disease” that compelled me to make games (my dad once told me that what people joke about speaks volumes). One month later, I was living in Los Angeles, working as a software engineer, and realizing I had just burned out of the game industry.

There and Back Again: GraphQL at strongDM

This post originally appeared on the strongDM engineering blog.

Once upon a time, strongDM had no dedicated frontend engineers. We backend engineers dipped our toes in the React frontend as infrequently as possible. It relied on dusty, bespoke, private REST endpoints that returned schema-less JSON blobs. We let these languish while we built a shiny new public API with code-generated SDKs in five languages. Occasionally I was forced to write a new private endpoint for the frontend. I did so with shame, dreaming of a future when the whole frontend would only talk to the public API. Then one day, we hired a frontend engineer, and everything changed.

How to Exfiltrate Code from Bitbucket

Every year or so, something compels me to start over with a fresh OS image. Most recently, that something was an unfortunate water bottle incident. Once again, I need to pull down my digital life from the internet.

The code and assets for this blog currently live in a 500 MB Git repository, which was hosted on Bitbucket until earlier today. Let's try cloning it!

evantodd@HW-0063 ~ % git clone git@bitbucket.org:etodd/etodd.io.git
Cloning into 'etodd.io'...
remote: Enumerating objects: 2237, done.
remote: Counting objects: 100% (2237/2237), done.
remote: Compressing objects:  99% (1885/1903)
# hang

No worries, we can clone over HTTPS!

The Poor Man's Netcode

The more you know about a given topic, the more you realize that no one knows anything.

For some reason (why God, why?) my topic of choice is game development. Everyone in that field agrees: don't add networked multiplayer to an existing game, you drunken clown.

Well, I did it anyway because I hate myself. Somehow it turned out great. None of us know anything.

Problem #1: assets

My first question was: how do I tell a client to use such-and-such mesh to render an object? Serialize the whole mesh? Nah, they already have it on disk. Send its filename? Nah, that's inefficient and insecure. Okay, just a string identifier then?

The Poor Man's 3D Camera

Each of us have our own giants to face. This is a story about one of my giants. Something I never imagined could make a grown man cry, until it did.

A 3D camera.

No one can face your giants for you. This is a story, not a walkthrough. Expect no useful information. For that I recommend 50 Game Camera Mistakes by thatgamecompany's John Nesky. His job title is literally "camera designer".

Thirteen Years of Bad Game Code

Alone on a Friday night, in need of some inspiration, you decide to relive some of your past programming conquests.

The old archive hard drive slowly spins up, and the source code of the glory days scrolls by...

Oh no. This is not at all what you expected. Were things really this bad? Why did no one tell you? Why were you like this? Is it even possible to have that many gotos in a single function? You quickly close the project. For a brief second, you consider deleting it and scrubbing the hard drive.

The Poor Man's Voice Acting

Allow me to regale you with an exciting tale: the birth of a janky dialogue and voice system.

I have a JSON file with all the localized strings in my game, like this:

{
	"danger": "Danger",
	"level": "Level %d",
	...
}

A preprocessor takes this and generates a header file with integer constants for each string, like this:

namespace strings
{
	const int danger = 0;
	const int level = 1;
	// ...
}

At runtime, it loads the JSON file and hooks up the integer IDs to localized strings. A function called "_" takes an integer ID and returns the corresponding localized string. I use it like this:

The Poor Man's Threading Architecture

The game industry hit Peak Advice Blog a while ago. Every day I read skim ten articles telling me how to live.

Fear not! I would never give you useful advice. This series is about me writing bad code and you laughing at my pain.

First Contact

Say you have some voxels which occasionally get modified. You regenerate their geometry like so:

voxel.Regenerate();

Because you are a masochist, you want to do this on a separate thread.

Ludum Dare 34 Postmortem

Friday 21:15

Fifteen minutes after the theme announcement, my friend Ben Homan walks through my front door. Not really my front door, I'm just a subletter. But this is a first. Normally he ignores our instructions to walk in without knocking. The first time, he texted me from the driveway.

21:30

Jesse Kooner walks in, also unannounced, bearing frozen pizza. Before he can even kick his shoes off, I loudly explain the theme: a never-before-seen tie between "growing" and "two-button controls".

One Weird Trick to Write Better Code

Developers hate him!

We'll cover some standard tips and tricks here, but we're not really interested in those. We're looking for the One Weird Trick to rule them all. Hopefully each trick we encounter brings us closer to coding Mecca.

In the beginning

The first video game I ever wrote was called Ninja Wars.

Yes, that is an HTML table of images. I changed the src attribute to move stuff around.

The Poor Man's Postmortem - Lemma

The big secret of our industry is, we don't actually enjoy making games. We slave away in obscurity for years in anticipation of one glorious day.

Not release day, no. The day we can finally write a postmortem full of pretentious anecdotes, bad jokes, and unsolicited advice.

Well I just finished a game, and doggone it, I am going to exercise my inalienable rights as a developer.

Lemma is immersive first-person parkour in a surreal, physics-driven voxel world.

Things to do when making a game

Ancient gamedev postmortem traditions mandate that this section be titled "what went right". Unfortunately, the game was so shockingly good and so many things went right that a full overview would stretch on endlessly.

The Poor Man's Character Controller

Let's say that, like so many of us, you want to make a surreal voxel-based first-person parkour game. You're trying to figure out a production schedule. What will take the longest? Graphics? Sound? Level design? I bet it will be the character controller. And I bet it will take 4½ years. Why?

That said, each game offers a few transferrable bits of wisdom. Here's my story.

Screenshot Saturday 213

It's the end of February and this game is supposed to be content-complete. In a sense, it actually is. All the levels are done. Twenty in all. I thought this month would never end!

Just so you know, there are sixty of those lights and I had to hook up each one individually. It fell just barely beneath the "worth it to automate" threshold.

Don't look too closely at this next one, it's a bit spoilery.

The Poor Man's Voxel Engine

This is not a tutorial. It's a story. A Voxel Odyssey.

The story starts with 19 year old me in a dorm room next to the Ohio State stadium. I don't have the repo from this stage of development (SVN at the time), but I remember the process clearly.

Photo by Kristen Sutton

XNA 4 comes out in September 2010. I immediately dive in. This turns out to be a poor life decision.

Screenshot Saturday 211

Last Saturday we had the Short North gallery hop. Hundreds of people came through our gallery to see art. The guys helped me set up the Oculus and a projector on the wall.

Sometimes I had to go out and pull people in, but most of the time, there was a line. My favorite customer by far was this kid:

He jumped right in and played like a pro. The mother (recording video) was super supportive and excited.

Screenshot Saturday 210

I finished last week's map. It has some spinny things.

Then I made this week's map.

Who knew purple and green could look so... not terrible?

Anyway, this puts me ahead of schedule. There are three levels remaining. My goal is to for the game to be playable from start to finish by the end of February. It's ambitious, but I'm confident I can do it!

Screenshot Saturday 209

This week was crazy productive. I finished last week's level, finished another level, which looks like this:

...which also included some story-related writing and scripting, and actually started working on NEXT week's level, which looks like this:

I seem to be on a purple streak lately. Actually, purple may rise unintentionally to be the most prominent color in the game. Also, this last level is apparently a subconscious ode to Monument Valley.

Screenshot Saturday 208

This week's level is not quite done yet, but I have an excuse! Power was out at the incubator for two days, and the internet didn't come up fully until just yesterday.

Still, the level should be done some time this weekend and is already looking pretty good.

I finalized the promotional graphics and published the game to Steam in "coming soon" mode. I'm incredibly grateful to Sam Gebhardt for contributing his Hollywood artistic talent!

Achilles

This past weekend I participated in the CivicHacks "Game Jam for Good". The goal was to raise awareness of the global water crisis and ultimately promote PackH2O, a Columbus-based startup that designs water backpacks for developing water-stressed regions.

The jam lasted 48 hours. My entry is called "Achilles".

Achilles is a multiplayer text-based simulation. You the player must manage a village in a third-world country experiencing a water crisis. You can play it here (bit.ly/waterjamachilles) assuming I haven't stopped paying for the cloud server.

Screenshot Saturday 207

Records continue to be broken. This week's map was actually done on Wednesday!

Although most of Lemma is a strange hybrid of natural and alien-looking architecture, my design calls for a few "industrial / man-made" themed maps. For story reasons, and also because I just want to parkour through a skyscraper.

So on Monday I asked Twitter this question:

Screenshot Saturday 206

I moved my office into an incubator / art gallery this week.

The move is mostly for my own sanity. Turns out, working alone in your apartment for 9 months isn't the most fun in the world. It's a Herculean effort just to stay motivated. I also lost all semblance of a disciplined sleep schedule.

Productivity has been great since the move, and I'm back on a normal sleep schedule. Having people around is great, even if I mostly tune them out to focus on work (sorry guys).

Screenshot Saturday 205

For the first time in the history of Lemma, I'm actually keeping up with my self-assigned pace of one new level per week.

These past two weeks I made two more frost levels. The plan calls for one more frost level, then it's on to the other two biomes.

Both of these levels have interesting quirks and unique features. They're probably too tough right now, but I'm scheduling plenty of time to playtest and sand down the sharp edges.

Screenshot Saturday 203

Big update this week!

My voxel renderer now has the capability to overlay everything with any texture I want. I'm using it on a new set of interconnected winter levels. This way I don't have to manually come up with a frosty version of each texture.

Without giving away too much, this week I built a new system that has implications for both puzzle solving and movement mechanics.

Screenshot Saturday 202

I've come to several realizations this week.

  1. Lemma is going to be good, but not great. I have to accept my limitations and finish the thing to the best of my ability.
  2. Lemma is more of an experience than a traditional video game.

With these two ideas in mind, I am focusing the next few months on making Lemma the least frustrating, most enjoyable experience I can.

So I'm trying to come up with puzzles that seem difficult but are actually simple to solve. The wonderful Monument Valley did a great job of this.

New blog, new app, new screenshots

Lots of stuff going on this week.

New dev blog

First off, my website got a much-needed overhaul. The horrible slowness of Wordpress.com was driving me nuts, so I switched to a custom-built site.

I used Jekyll, which is a static site generator. It spits out a bunch of HTML files which you can upload to a server, as opposed to Wordpress, which generates fresh HTML every time someone loads your page.

Advantages:

Screenshot Saturday 199

"Level design for days" has been my motto for several months now, and this week is no different.

Behold, new challenge levels! These are timed, bite-sized maps with simple goals that can be completed in under a minute. They're the kind of things you can create in the level editor and share on Steam.

I need to find a new texture for that garish green material.

Lots of other things are happening, but they're more like a million tiny updates rather than a few conveniently screenshot-worthy ones. So that's it for this week! Thanks for reading.

grepr - 7DFPS 2014

I survived 7DFPS, barely. Here are some fascinating statistics:

I'm happy with the result, though. Jack did a great job on the audio as usual, although at the last minute I had to throw in some clunky placeholder sfxr sounds. Blame me for those! Maybe we'll replace them later.

7dfps work in progress

I'm participating in 7dfps this year, which means I'm making an FPS game in 7 days. Here's what I've got so far:

In Soviet Russia, you are bullet.

In my 7dfps entry, moving and shooting are the same thing.

Here's my favorite form of humor: physics glitches.

Here's me getting killed:

Here's a better shot of the city:

Lots to do still.

Screenshot Saturday 196

This past weekend I exhibited Lemma at the Ohio Game Dev Expo. It was an awesome time. Extra Life raised over $9,000 for charity (yes, it is in fact over 9000).

The Oculus Rift was a huge hit!

I worked on various improvements right up to the expo. First, some new textures for moving platforms and doors:

This is the first texture I've created that has any kind of directional meaning. The reason is that until this week, I had no control over how the textures mapped to the voxels. It was all procedural. So if I put an arrow graphic in a texture, there was no guarantee which way it would face.

Screenshot Saturday 194

Just a quick update this week to confirm that I am in fact alive. The iOS contract game is just about done. I'm pretty happy with it.

Now it's back to work on Lemma:

I'll be running a booth, speaking, and participating in a panel at the Ohio Game Dev Expo next weekend! Come on out and hang with us!

Shaders: How Do They Work?

Yesterday I gave a talk at Dev Workshop Conf introducing the basic concepts of vertex and fragment shaders. Unfortunately I don't have a video, just this one potato picture:

It's probably for the best, because Chrome locked up on me halfway through. The slide deck is pretty cool though. It includes over 20 interactive WebGL samples, complete with source code. Check it out and let me know what you think!

Screenshot Saturday 190

Well friends, Lemma is still on pause while I do some contract work. I also have only a few slides done for my shader presentation next week. This whole month is crazy. But I thought I'd hijack this dev blog to show you the game I'm working on, because it's starting to look kinda cool!

It's a top-down iOS survival shooter designed as a sort of franchise tie-in. The budget is pretty low so most of the assets are pulled from the Unity asset store. I've only done a few models myself, mostly just weapons.

Screenshot Saturday 188

I'm taking September off to work for some clients, so Lemma is temporarily on the back-burner.

HOWEVER. Wednesday night a certain something arrived in the mail.

I immediately tried it out with Half-Life 2 and was shocked at the massive improvement over DK1. I was so impressed that I've spent pretty much every waking minute since then trying to get it working in Lemma.

Current status? It's very, very close. The VR itself is 100% functional now, I just need to make some UI tweaks. The Oculus SDK makes an incredibly difficult thing as simple as it possibly can be. For Unity users it's almost plug and play, but because I'm still stuck in 2008 with XNA I had to rip out the Unity plugin and hook it up on my own (similar to what I did for Wwise). I discovered that it's very easy to get a somewhat passable result that's actually incorrect. You have to learn about crazy things like chromatic aberration and time warping to get the best result.

Screenshot Saturday 185

Hello friends. Yesterday I finished the 5th level! It took much longer than anticipated because it's actually 10 separate maps connected together. It includes some simple but hopefully interesting puzzle mechanics.

It also advances the story through notes and several text conversations scattered throughout.

It's hard to see in screenshots, but I added a subtle cloud shadow effect as well. It doesn't respond to the actual clouds, so in a sense it's slightly faked. Because of that I was able to do the projection easily with a ray-plane intersection rather than a full matrix multiplication. Here's the shader code, edited for clarity:

Screenshot Saturday 184

This week was a lot of level design. I'm working on a group of "fractured" but interconnected worlds that the player has to progress through.

Here's a screenshot:

Here's the thread where I got that rock texture. It's a gold mine with a bunch of totally free diffuse, specular, normal, and even displacement maps.

Unfortunately that's all I have time to talk about today. Thanks for reading!

Screenshot Saturday 183

I hit a milestone today.

Three of the four levels so far in Lemma (Rain, Dawn, and Forest) have undergone at least one massive redesign in their short lifetimes. This week I finally gave the same treatment to the fourth level, Monolith. It is aptly named. Let me try to convey just how monolithic this level is now.

This is a perfect example of my patent-pending Design by Trial and Error™ process.

Screenshot Saturday 182

What's that you say? You didn't even notice the absence of Screenshot Saturday last week? How convenient. Let's pretend it never happened. Or rather, pretend that it did. Whatever.

MGDS was a huge success! There was almost always a line to play the game, and I got a ton of useful feedback. Here are some pictures:

Most of the feedback was related to level design. I came home with a phone full of "todo" items. Here are some screenshots of overhauled or brand new sections that resulted:

New trailer!

Gearing up for Midwest Game Developers Summit this weekend. Tune in next week for my first expo post-mortem.

In the mean time, the old trailer was looking woefully outdated, so here's a brand new one!

Screenshot Saturday 178

Small update. This week was bug fixes and more improvements to the level editor (more on that here).

In other news, we were grateful to get some coverage from Monday Night Indie! Unfortunately the stream highlighted some pretty major issues with the tutorial, so...

Brand new level design!

That's it for this week. Thanks for reading.

Screenshot Saturday 177

Our animator Antonio has been hard at work on new animations. Check it out!

Guys, the level editor is really close to being done. Here's some cool features:

You can link entities together. For example, you can have a door open when the player enters a trigger volume. Or have a light turn on. Or both.

The UI now displays buttons for all available commands at any given moment, and their keyboard shortcuts. Different commands are available depending on what mode you're in, and what entities are selected.

Screenshot Saturday 174

First, a couple project updates. I pre-ordered an Oculus DK2! Come August, Lemma will have Oculus VR support. Huzzah!

I also got a sign for our booth at the Midwest Game Developer summit . Got it from eSigns, whom I highly recommend! Insanely cheap, fast, and high quality.

I am currently scrambling madly to complete a build for the Indie Megabooth submission deadline on Sunday. Stuff that's done:

Screenshot Saturday 173

Last week was a huge update, so this week is a bit smaller.

First, we're hard at work on the animations. Here are some early WIP animations:

There are also a ton of new player sounds to accompany those animations, but those aren't very screenshotable. :)

I also vastly improved the god ray effect from last week, so everything is much smoother. Here's another 4K screenshot of it:

Screenshot Saturday 172

Big update this week!

First, I updated the logo. I rotated the cubes 45 degrees to try and convey a better sense of speed and movement. What do you think?

Next, I added support for 4K screenshots. Now I can hit Alt-S and my renderer resizes all of its buffers to 4096x2304 (biggest 16:9 resolution supported by XNA), renders the scene, saves it to a PNG, then resizes everything back to normal.

The Poor Man's Dialogue Tree

As some of you may know, Lemma has an interactive dialogue system that lets you exchange text messages with an AI character.

I implemented every conversation manually in code (well, scripts) until this week, when I got fed up and decided to automate the process!

Like the last article in this series, my system has all the hallmarks of a Poor Man's solution: developed in-house, tailor-made, simple, and based on free and open source software.

Screenshot Saturday 170

Hello and welcome to another week of Lemma development progress updates!

This time I did a lot more work on the player character. I spent a ton of time in GIMP working on the texture map. I didn't skimp on memory space, it's a full 4096x4096. The GIMP file is over 150MB.

I also split the model into three distinct materials: a shiny one for the chest, neck, and pants, a less shiny one for the hands, and a completely dull one for the hoodie. I stored the mappings for these materials in the texture's alpha channel.

Screenshot Saturday 169

This week I finally implemented SSAO! It's pretty basic, but it works.

Check out the effect source code here.

It's a big deal for me because I tried it once before and it came out like this:

I'm also still working on the player model. I think it's close to being in a usable state. What do you think? Is that a ponytail, or a brain slug?

Screenshot Saturday 168

This week was a ton of performance optimizations and graphics upgrades.

Cascading shadow maps! Basically that means all the shadows are much sharper. It was surprisingly easy to implement and barely impacts performance.

Here's a screenshot showing off the new shadows, plus a new character modeling experiment. Just testing things out for now. What do you think?

Turns out, Blender has something called Rigify that can automatically generate an absolutely kick butt IK rig for your character, complete with blend weights for skinning. It's not perfect, especially when there are separate disconnected pieces (eyeballs, for example), but the few problem areas are easy to correct manually. Here's the character animated with the default calculated weights. I haven't touched them at all yet:

Screenshot Saturday 167

With the Kickstarter finished, it's back to our regularly scheduled programming!

I am in the middle of a major graphics engine upgrade. This whole time I've been using fake HDR. Basically I divide every color by 2 when storing it in a texture, then multiply it by 2 whenever I read it from the texture. It works but you end up with lower color fidelity.

Now everything is done in full 64-bit floating point textures. Here's an exaggerated before/after shot so you can see the difference. Notice the color banding on the left.

Final hours

Here we are folks, counting down the last remaining Kickstarter hours!

I'm happy to announce that regardless of the Kickstarter outcome, production of Lemma will continue.

To be honest, I originally planned to cancel everything if the campaign failed. I figured a failed Kickstarter would be a sign that people aren't interested, and that I should cut my losses (nearly 4 years of work) and move on. But in the past month I realized a few things:

FINAL WEEK!

We are now in the midst of the final week of Kickstarter funding! With the campaign nearing the end, I thought I would give you another development update.

First, I spent a few days completely rewriting every bit of text in the game to support multiple languages. You can now change the language from this nifty selector on the main menu, and the whole game instantly switches:

Now all we have to do is translate ALL the things!

GREENLIT!

From the Kickstarter:

It's not every day you see this email in your inbox.

It's not every day you see this email in your inbox.

WE ARE ON STEAM! Thanks everyone for your votes! We were part of a batch of 75 titles, even though we hadn't reached the top 100 yet. Go check out the other games that were greenlit today!

Here are the statistics for anyone interested:

Cheat your way through life

From the Kickstarter: Just an update on development progress for Lemma! Thank you so much everyone for your support. I'm still getting tons of useful feedback from people playing the demo. Levels have been tweaked, bugs have been fixed, writing has been edited, and graphics have been tightened. Expect a new build very soon! Here's some new features to look forward to:

First, a minor technical detail. Saved games do not carry over between builds. If you run a newer build, all your old saves will be lost. It's a major drag for beta testers, which is why I've added a new CHEAT menu to skip parts you've already mastered!

Player model and animations

An update from the Kickstarter:

One concern that pops up a lot on Greenlight is the low quality of the player model and animations in Lemma. The reason it's so bad is that I did all of it myself, and I'm not a character artist. People ask, "but couldn't you just try harder? What's so hard about modeling and animating a character anyway? Also, couldn't you just borrow an existing public domain model?"

Movement in-depth

Update from the Kickstarter: I know it's only been 24 hours since the last update, but Lemma is now over 61% of the way to the top 100 games on Greenlight with well over 4,500 yes votes. Thank you all for being a part of this project!

I realized that the 30 seconds of gameplay from the Kickstarter trailer is not enough to really see what's going on, so here's a more in-depth video explanation of the movement in Lemma. Skip to 2:15 to see an explanation of the magical wall-creating, environment-modifying bits.

Looking forward

From the Kickstarter, a quick status update before I talk more about Lemma:

Okay, let's talk about future plans!

Greenlight update + streaming tomorrow

Hello!

First: I wanted to thank everyone for the amazing support you've shown so far. We're already over 24% funded, which is more than I was expecting this early, so thank you!

Second: A quick update on the Greenlight campaign. We are 26% of the way to the top 100, with 1,918 "yes" votes! Keep on voting, we'll be on Steam in no time.

Third: If you wanted to see more gameplay from Lemma but didn't have time to check out the demo, several YouTubers have posted "let's play" videos of the demo. Draegast has a good one right here.

Lemma: first-person parkour demo

After an unexpected 24 hour delay, the demo is finally out, and the Kickstarter is live! I'm running on 3 hours of sleep, but here's some things you might not have seen since the last release:

The bouncy cubes are now more like crumbly cubes. They crumble when you touch them.

Screenshot Saturday 162

The Kickstarter for Lemma launches on Monday! Keep an eye out, and tell your friends!

Prepare yourself for tons of giant GIFs. You can click each one to watch a much faster HTML5 version (can't wait until the internet ecosystem finally lets us embed HTML5 gifs...)

This week I revamped the materials... again. Check it out:

It had some interesting implications for the "snake" enemy:

Screenshot Saturday 161

This week I finished what will probably be the last map in the Kickstarter demo. It teaches the player about the "extended wall-run" ability, demonstrated here:

Normally, you hold Shift to wall-run. Now you can just keep holding Shift after you run out of wall, and you'll keep going.

I also fixed the water bugs from last week, so it looks much better now:

I've been worried that I don't have time in the demo to introduce every idea I have at a reasonable pace, so I'm thinking of including a "sandbox" map that just enables every ability and throws every idea at the player and lets them play around.

Screenshot Saturday 160

This week I finally fixed my water code to allow finite bodies of water like this:

(It's so dark because I still have a pesky rendering bug)

I also realized I accidentally had pre-multiplied alpha turned on for my cloud texture. Here's what it looks like when you use pre-multiplied alpha incorrectly:

And here it is fixed (I also made the clouds fade in over distant objects):

Screenshot Saturday 159

This week I overhauled the menu. It's very Valve-ish now:

I also distributed a number of mysterious notes around the levels to help flesh out the back story. They're actual 3D objects rendered and lit in the game world.

WHAT COULD IT MEAN? THIS REVELATORY NOTE HAS ADDED HEFTY NUANCE TO THE PLOT AND SIGNIFICANTLY INCREASED MY IMMERSION IN THE STORY.

Other than that, just lots of level design iteration, scripting, and tweaking.

The Poor Man's Gameplay Analytics

You don't want to take time away from your awesome game to write boring analytics code. So you either call up some friends, hire playtesters, integrate some 3rd party SDK (ugh), or just do without.

WRONG. You roll your own solution. Here's why.

Why you don't do without

The OODA loop models the way human individuals and groups operate. It goes like this:

After the initial act of creation, game developers operate under the same principle. You play the game and observe it, orient that data in the context of your goals, decide what to do, open your IDE, and put your plan in action. Rinse and repeat.

All Ahead Full

Progress report. Sir, we have inbound screenshots from the first two weeks of full-time development. Bearing zero nine five, range three hundred. Prepare countermeasures.

I added motion blur around the screen edges when the player is at their maximum speed:

The phone has returned, but now it's in full 3D glory:

Some parts of the levels now build up dynamically when the player reaches them.

Ramping Up

I'm sorry, I've been terrible at keeping everyone up to date with Lemma. If you want to see what I've been up to since Alpha 3, my TIGSource DevLog has a few posts you might have missed. Starting now I'll be focusing more on blogging, so expect more posts in the coming days!

Here are some highlights from the past... gosh. Seven months? Wow.

This is just the beginning. As the title suggests, I'm getting ready to ramp up development in a big way. As such, I found it necessary to upgrade my workspace. I've been using a standing desk at work, and I love it so much that I decided to build one of my own out of $200 of IKEA parts:

Auto-generating JSON serialization code in Objective C

I wrote this article for the Sidebolt company blog. Reposting it here for your reading pleasure!

Our latest game Skyward Slots makes extensive use of JSON. We send Gigabytes of it flying back and forth haphazardly between client and server over a WebSocket connection. At first, we wrote code by hand to pack and unpack each message. Later on we decided that life is too short for that.

In the beginning, we just dove into the JSON right where we needed it.

Simulating UIScrollView in Cocos2D

I wrote this article for the Sidebolt company blog. Reposting it here for your reading pleasure!

We publish our games on both Mac and iOS. Since UIKit is not available on Mac, we have to build all of our UI by hand in Cocos2D. One of the hardest parts to get right was emulating the UIScrollView bouncy scroll formula. Here it is in action:

There are tons of implementations available in nearly every language and framework, but few of them nail all the important properties of the UIKit scroll:

Lemma - Alpha 3 Ready to Play

After seven months of hard work, Alpha 3 is ready to play!

Some interesting statistics:

Incidentally, most of that is open source! If you're a developer, check it out on GitHub.

Quantity Brings Quality

As I suspected, I have an almost insurmountable case of coder's block after a full day at work. Nevertheless, things are getting done. In fact, this might be the best thing that's happened for Lemma because it's forced me to cut a lot out of the design and focus on core things. It's the only way I'll ever finish.

Screenshot below gives an idea of the new direction. I've dropped any pretense that the game occurs in our world as we know it. It was a restriction that existed only to service the story, and it was limiting the gameplay and visual style a lot. Now I'm free to do a lot more, and I'm not precluded from telling a story just because it's fantasy rather than sci-fi.

Anecdotes ahoy

A smorgasbord of anecdotes carefully compiled just for you, dear reader. This is #2 in a series of three posts which were originally one, before I decided I just had too dang much to say.

OpenStack

I spent a few weeks at work building a fully operational death star OpenStack cluster. What does that mean? Basically, we have our own little private version of Amazon Web Services. We can create virtual machines, virtual hard drives, even virtual IP addresses, all with just a few clicks. It also includes an S3-alike called Swift.

My Biggest Fear for the Future of Human-Computer Interfaces

I recently had to install and configure an 18-node OpenStack cluster, a process which involved a lot of SSHing and text-editing in terminals. I thought about learning Vim, but I was afraid of the incredibly steep learning curve, so I made do with GNU nano. It's not at all powerful, but it's easy.

Eventually I realized, "This is my job. This is what I do every day. Why am I holding off on learning something now, thinking it will slow me down, and that I'll have time to learn it later? It's not like I'm anticipating a major career shift any time soon."

Internet is Back

I just got internet back after being without it since before Christmas. It was a tearful reunion, to be sure. Turns out, I was actually more productive than usual without internet. There's a one-word explanation for that, and it rhymes with "edit".

ANYway, here's what got done:

Analytics

When you finish a play session, you'll see something like this:

 

I haven't figured out the server side of this system yet, but all it really needs to do is accept plain text file uploads. Once I have the files, it's easy to load them into the editor, yielding data like this:

Progress Report

Lemma has been radio silent recently, but that does NOT mean things aren't happening! I've been able to do a ton of work almost every day these past few weeks. Here's what's going on:

  1. Did some massive surgery on the very first tutorial section after getting some feedback from a limited alpha release. It introduces, jumping, climbing, vertical wall-running, and rolling/crouching.
  2. Added a second, underground section that introduces horizontal wall-running, wall-jumping, and some important story elements.
  3. Added a THIRD section, which you will see in a moment, that reviews everything and introduces the flying kick move.
  4. Wrote a small chunk of dialog for the text-message system. It's harder than I anticipated, making the conversations truly interactive without having the dialog tree explode exponentially in size.
  5. Simplified and consolidated the controls. Everything is on Shift, Spacebar, and Control now, should be very intuitive for FPS players.
  6. Overhauled some of the animations and added new ones for some new parkour abilities.
  7. Made the menu a lot more user-friendly.
  8. Committed approximately 15 million bug-fixes and tweaks.

TL;DR: Things are happening. Here's a video that shows one of several ways to get through the third tutorial section in quick fashion.

Mac and Linux Support

How's everyone doing? I'm doing okay. It's a Monday. Hope you're doing okay too. Surviving Sandy aftermath, school, work, and whatever other forms of oppression you may be under.

I don't have anything pretty to show for the past... wow, it's been three weeks. I've been working on a very lofty addition to Lemma's feature bullet list. And that is Mac and Linux support, via the awesome MonoGame project.

Don't get too excited. There is a ton of work left to do before this becomes a reality. But after a few weeks' work, I do know a few things:

Voxel Levitation and Rain

I present to you, "Voxel Levitation: a Step-by-Step Guide".

Step 1:

Step 2:

 

Step 3:

 

Step 4:

 

Also, check it out. Hurricane Sandy has spilled over into Lemma. It's raining!

That is all.

 

 

Allocating large arrays in .NET

I experienced a strange memory issue with Lemma this week. Memory usage skyrocketed each time I loaded a level; it never dropped back down.

Now granted, I am definitely the garbage collector's worst nightmare. (I'll just say this: closures. Closures everywhere.) But at this point I am setting fields to null all over the place and manually calling GC.Collect() after unloading a level, all to no avail.

Enter the .NET Large Object Heap. See, the .NET garbage collector actually compacts the regular .NET heap by relocating small objects to fill the fragments. For exceptionally large objects, it's simply too expensive to relocate them, so the runtime allocates them on the Large Object Heap, which is not compacted.

Slowmo! Stamina! Sprint! Socialism! What?

Stamina and Sprint

I finally realized that speed is perhaps the most important resource in a Parkour game. Up until now, Lemma hasn't really understood the concept of "faster" and "slower"; you were always going the same speed. Acceleration from a dead stop was almost instantaneous and the Parkour moves didn't change your speed (with the exception of wall-running).

With this in mind, I decreased the acceleration a lot and made all the moves preserve your momentum. To make a longer jump, you'll need a running start. I also put in some simple combos. For example, doing a roll immediately followed by a jump lets you jump a lot farther.

Scary Monsters and Nice Clouds

Nice Clouds

I got sick of my old pixelated skybox powered by Google Images and decided to make a real one. I used Spacescape to generate a sufficiently trippy outer space skybox, chopped up some cloud photos in Gimp, fought with my code for a couple hours, and wha-la:

Scary Monsters

What's that glowy green thing you say? It's the new monster I just added, creatively named "the vine". See that string of dark blocks coming out of it? It snakes its way to you and basically tries to constrict you to death. Here's another screenshot of its handiwork after running for a minute or two.

Now with 100% more frame buffer distortion!

Flying in the face of midterms and other IRL issues, Lemma boldly marches on!

Spawn Point Graphics

I realized you need a way to know where you'll respawn if you die, so I added some spawn point graphics. Got the idea from Borderlands. Actually can we talk about Borderlands? Man, every time I play a good game I have to resist the urge to start incorporating its ideas into my projects. If I ever announce that Lemma will feature randomly generated weapons, just slap me until I snap out of it please.

Story Design and Loading/Saving

I now have the complete backstory and in-game story options written out!

After the initial tutorial, you'll get to a central area of the island which connects to four other areas. At that point, you'll be able to leave the island whenever you want, or you can visit one or more of the four adjacent areas before leaving. In each area you'll have to make a yes/no decision. You'll get a different ending depending on which decisions you make and at what point you exit the island. Your choices also affect how many parkour abilities you unlock. There are 5 major possible outcomes, and each outcome has a number of variations, for a total of 15.

Lemma Release 2

Here's an extremely cut-down demo! No tutorial, no story, no explanation, just showing off new moves, new enemies, and the new weapon.

Download it here for free. Please let me know what you think!

Super-Awesome Change List

Stuff To Look Forward To

Brace yourselves

Everyone pretend this blog didn't die for six months, okay? Okay. Here's a brain-dump of random things I've learned while not blogging.

Life's been busy, but this last semester is pretty easy, so I've had lots of time to work on Lemma. No time to talk about it now, but keep an eye out for a juicy trailer / alpha download soon. For now, I'll just tease you with this!

Finals week

Sorry, no news to report on Lemma this week. School is keeping me busy. But I thought I'd share some of the projects I'm working on for school, since they're kind of cool and actually somewhat related to Lemma. First up: a 3D rapid prototype of the original toon-style Parkour Ninja!

Here's the model rendered in Cinema 4D:

And here it is printed out in 3D:

Alpha feedback

Thanks so much to everyone who made the alpha a great success! I'm blown away that people were able to look past the bugs and crashes and clunky controls and somehow get a positive experience out of it! It gives me hope and motivation to press on.

I got a ton of very useful feedback. Here's a quick summary of what I learned:

I've already set to work fixing a lot of these issues, especially with the controls and physics. My number one priority is getting the player animation and movement perfect, which is a pretty long way from where we are now.

Lemma Release 1!

It's finally here! Alright I'm just going to dump everything here. Prepare for face melting.

Windows MSI Installer (60 MB)

Note: You might get a malicious file warning. It's because I can't afford a code signing signature at the moment, so the installer has not been signed.

If you're NOT reading this on the shiny new website, did you know that you COULD BE? It's right here: lemmagame.com

Please play the alpha and leave your comments! Your feedback is greatly appreciated!

Help me pick a logo!

I'm going to try and post smaller, more frequent articles. This whole "two months between massive walls of text and screenshots" thing is not working out.

So, the alpha I promised is *still* inbound. I'm working as fast as I can! And I think it's paying off. For a while I was very worried about performance. In my last post I talked about how I optimized the renderer, but there were still issues with the physics engine. I was putting each cube into the physics space as a separate entity, which was making it absolutely crawl, even on my eight core i7.

Global Game Jam 2012 Liveblog

Update: Snakes in a Tower is complete! Downloads with source available for Mac and PC.

Friday 4:59pm

This is my first Global Game Jam. Super excited. So I'm going to liveblog it. I'll be working on a MacBook, so I decided to port the essentials of my XNA component entity system over to MonoGame. Here's what I got so far!

Breathtaking, I know.

Saturday 12:20am

Opening meeting was awesome. Heard some fantastic keynotes from fantastic people. We got to hear some great insight from Ian Schreiber before starting (I'm at the Ohio State jam). The theme has been given to everyone by now, so I'll go ahead and say that the theme is this:

Quick update - Alpha inbound soon!

This week was a lot of under the hood improvements. The voxel engine got a TON of performance optimizations, which allow my Nvidia GTX 260 to render my test scene at 100-200 FPS.

Screenshots:

New features:

  • Rough-draft tutorial level with instructions and whatnot.
  • Fullscreen toggling on-the-fly by hitting F11
  • Rudimentary fog effect

Performance optimizations:

  • Voxels are now rendered as surfaces, rather than complete cubes. This lets me cull a lot of unnecessary geometry.
  • Voxels are now split into chunks. This lets me easily implement frustum culling and view distance, which helps tremendously with shadow map rendering as well.
  • I fixed some bugs in the voxel modification code, making voxel modifications of up to 100-150 cells practically instantaneous.
  • Shadow maps and reflections are now rendered every other frame. It's a hack, but the important thing is that the gameplay is responsive.

My biggest development challenge was my battle with fullscreen toggling and graphics resource management. Switching from fullscreen to windowed mode, the entire XNA GraphicsDevice is invalidated, along with every vertex buffer, texture, shader, everything. So that was interesting.

Digital art, Facebook 3D Graph Explorer, and more Project Lemma

My last two posts focused on general game development topics, but no longer. It's the end of the year, time to look back and review before looking forward to the new year!

Digital Art

First off, some fun diversions. In my pursuit of an art minor at Ohio State, I took a digital art class autumn quarter. The instructor let me use software I was already familiar with, so I didn't learn much. But the class gave me the motivation to plonck my butt down and make some art, which is all I really wanted.

C# for scripting - runtime compilation

I set out to add scripting support to Project Lemma the other day. End result: I can recompile C# scripts on the fly and cache the bytecode in DLLs. The best part: there's no special binding code, and no performance hit.

There are a lot of .NET scripting solutions out there. Here's a few I found in my research:

  • IronPython. Fully dynamic, kinda slow. Requires marshalling of some kind between the script world and .NET.
  • CSScript. Very well supported, includes Visual Studio extensions and shell extensions. Compiles C# to bytecode at runtime, with caching. Scripts cannot be changed once loaded.
  • Lua. The industry standard in scripting. From what I understand, a little challenging to get working with .NET.

I decided to try out C# runtime compilation. Really, C# is the best scripting language I could ask for. If I succeeded, I could keep writing the same code I've been writing, but I could recompile it and see it in action with a keystroke instead of restarting the game!

Tools are everything

You've probably heard the whole "don't make engines, make games" shtick. As I progress I am learning another important lesson: tools are the most important aspect of any project, game or engine. Whether you're rolling a custom engine or shopping around for middleware, tools should be absolutely top priority. Seriously.

The question should not be "how many shiny graphics techniques can I incorporate?". It should be "how easy is it to create content for this game?". Content is the center of every game, whether that content is an AI algorithm, a map layout, or an art asset. If the content pipeline is even a little inefficient, it will prevent you from making the game you want to, whether you realize it or not. If you have to jump through hoops to create a new level or script a story sequence, you're going to put it off and focus instead on adding another feature that provides tangible results, like a new lighting technique. Problem is, those features don't make the game. Content does.

Physics and lighting fun

Sorry to post two videos in quick succession, but this was too fun not to record!

Parkour Ninja update: first-person camera, physics, deferred rendering

Parkour Ninja is still alive! And it's looking more like Mirror's Edge now, complete with first-person camera. The old direction of the game just had too much frustration and not enough fun. Hopefully things will change now.

I re-integrated a physics engine, this time BEPU physics, which is a screaming fast open-source XNA physics engine with unbelievable support. I was able to get my existing block simplification/rendering code to work with BEPU, so now you can add/remove blocks to/from existing objects on the fly. One cool side-effect of this ability is that I can also blast objects into smaller chunks... full-blown destruction is #1 on my list right now.

As promised: Component Binding "BEHIND THE SCENES"

In the wake of this brief description of my component binding system, I was asked to provide more details on its implementation. This article is my best attempt to do so!

This is a tale of intrigue, excitement, and wonder, in which I try to implement a component-entity system in C#, and stumble upon a remarkable paradigm that merges components with data binding.

Note: If you don't have at least a vague concept of component-entity design, read this article first.

Game dev job, Macs, and re-focusing my project

Apologies for the lack of Parkour Ninja updates. I do have fresh info about it somewhere in this post. But first! A list of potentially interesting goings-on of late:

  1. School's out for summer! And I'm one year closer to a Computer Science & Engineering undergrad degree from Ohio State. I'll graduate in about a year and a half, right around my 21st birthday actually. I haven't the foggiest idea what to do after that. I'm looking at grad school, but I've heard it's not as important for CS people.
  2. I got a job making iPhone games! I'm working for a small studio in Columbus with three other interns. The original plan was to have the four of us collaborate on a single game, but now they've given us each a separate project (at various stages of development) to work on. I wish they had kept us together because a) I doubt we'll finish all the games now, and b) I need experience collaborating on a game instead of my usual lone wolf habits; I was hoping this job would put me out of my comfort zone a little. On the other hand, where else would I got almost full control over every aspect of a professional title? That's pretty cool.
  3. On a random note, I'm getting into shooting this summer. After a few more weeks of saving up I plan to buy an assault rifle (still researching what to buy there) but until then my buddy is lending me his AR-15 for the summer. :)
As a consequence of number 2, I now spend 40 hours a week working with Apple products. IT IS KILLING ME SLOWLY AND PAINFULLY. My Twitter feed is now steadily filling up with complaints about these products. Let's look at some comparisons to see why.
Resizing windows on Windows. To maximize you can click the button, double click the bar, drag it to the top of the screen, or heck use the little system menu on the app icon. Reverse the operation and it returns to its original size. You can tile windows, you can stack them, you can use Aero snap, you can resize them by grabbing any edge or corner.
Resizing windows on Mac. Okay, to maximize all I've got is this tiny little button, but no biggie... wait, I can still move the window when it's maximized? Crap, now the ONE AND ONLY tiny resize widget is off the screen! No wait, I can see it through this ridiculous translucent dock thing...
Moving files on Windows. Ctrl-X. Up one level. Click into different directory. Ctrl-V.
Moving files on Mac. Command-X. Back. Click into different directory. Command-V. Nothing happened?? Great, gotta open a whole 'nother Finder window...
GIMP on Windows. Ugly but functional. At least it sort of fits in with the system chrome. The usual keyboard shortcuts work and the multi-window setup doesn't get in the way too much.
GIMP on Mac. Well it took five minutes to load, but it looks okay... wait Command+N pulls up a bash prompt?? And now I've switched focus to some weird X11 app?? Okay back in GIMP now... wait ALL THE SHORTCUTS STILL USE THE CONTROL KEY. Well okay, at least I can zoom... oh wait, NOPE. *facepalm*
Visual Studio on Windows. Open a project... ah, there's all the files. Oh cool, I can completely customize the layout here... and oh yay, tabs!
Xcode on Mac. Waiiiit... are you sure this isn't iTunes?
C# on Windows. Whoops, looks like you have a syntax error here. You probably forgot a brace right here. Or perhaps you're missing an assembly reference? Let me help you with that. Would you like to refactor this a bit while we're at it?
Objective C on Mac. ERROR: (*) MAY NOT RESPOND TO (*). UNDEFINED TYPE "bool". INVALID ATTEMPT TO ASSIGN TO READ-ONLY PROPERTY "int main()". 30,000 ERROR THRESHOLD EXCEEDED. COMPILATION STOPPED.
TortoiseSVN on Windows. One right click, and you've got the repo browser, blazing fast logs, instant comparisons with syntax highlighting, single-click blaming, merging and branching, etc., etc...
SmartSVN on Mac. Import existing working copy. Okay, repository browser. What's the URL? I dunno, you tell me. Fine, view log then. You want me to set up a log cache? I don't know where to put it, save it in the application folder. Okay, here's the log. Wait, wrong folder. Back to the repo browser. Navigate weird tree folder structure... there we go, view log. WHAT? SET UP ANOTHER LOG CACHE?
Sorry, I just needed to get this stuff off my chest. Granted, some of these complaints have to do with free software. Seems you have to shell out at least $20 to get a half decent app on Mac.
ANYWAYS, about that Parkour Ninja update. I've made progress since the last update. There are more animations, more features, more coolness! However, I finally took the time to build a somewhat larger map, and the gameplay is just... frustrating. And not fun. I've spent many hours tweaking the existing moves, but I still spend the majority of the time careening off the map into oblivion or fighting the game to make it do what I want.
The problem is, the game in its current form is very different from the game I originally designed. I originally envisioned a heavily physics-based game, where the main draw was the destructible/constructable environment. It was going pretty great for the first month or so (I still think this early video is pretty sweet), and then I installed it on my friend's Xbox. Thing crawled like molasses. Turns out, Xbox live indie games basically can't have physics, because the CLI floating point performance is absolutely abysmal. I was shooting primarily for the Xbox live indie game market then, so I decided to axe the physics and use simple collision and movement code for the player. The rest is history.
The object lesson here is: don't axe your core gameplay mechanic! Notice that one unpolished early video has 1,500 views while the other more polished videos (post physics engine lobotomy) have about 300 views apiece. I think that proves a few things: a) people love watching physics engines at work, and b) if the game concept is fun, people will like it even if it's extremely unpolished.
So the bottom line is, I am no longer targeting the Xbox market. For now at least, Parkour Ninja will be a PC-only, singleplayer-only game. I will be bringing back the physics and focusing more heavily on that aspect. I may have to re-do the whole Parkour Ninja thing to reflect this shift in focus. I mean, I'm considering making the player character a cube right now, I don't think I can make that look like a ninja. Fortunately, I probably won't have to scrap much code, thanks to the nifty component system. So this project is far from dead, but it's going to take a different direction in the coming months. It's a tough decision to make, but I think it's necessary, and the sooner it's done the better.
Whew, that was long. Thanks for reading!

Pistol: Part 2 - Texturing

And here's episode 2 of the Sig Sauer Saga! In which I attempt to UV map and texture the model from Part 1. And do lighting and compositing for a decent somewhat photo-realistic render. Take a gander. Feedback appreciated!

Pistol - Part 1: Modeling

Poking my head in here to confirm that I am in fact not dead. I humbly offer this nifty time-lapse video as proof.

Started a small project to brush up on Blender skills. Modeling a Sig Sauer P220 in Blender 2.57. The model is low-poly and incomplete (need to finish the other side, the magazine, some bullets, etc.), but it's close. Next up, textures, materials, lighting, rigging, and animation!

Parkour Ninja Alpha 1

It's here, and it needs lots of play-testing! Please help me out and play it. You'll need a Windows machine with a Shader Model 3.0 graphics card.

I'm anticipating some technical issues with this release (it is an alpha after all), so if you run the game and no window appears and the process dies, please do the following:

  1. Run the game in administrator mode.
  2. In the game installation folder (C:\Program Files (x86)\Parkour Ninja\) open the file "Lemma.log" in Notepad, copy the contents, and send it to me! I need bug reports :)

Download here! (hosted on MediaFire for now)

Back on track

I finished refactoring with components, added a reflection-enabled editor and XML serialization, finally got real PCF shadow filtering, and started experimenting with a somewhat cel-shaded visual style. I've been busy.

The refactoring had a lot of positive side effects. Serialization is now relatively easy, as the state of each component is determined by its properties, which are usually simple, easily serializable value types. One interesting side effect of serialization is that object creation is now split into two parts: initialization, and binding. When creating a new object at runtime, a factory performs the initialization. When loading objects from XML, the XmlSerializer performs initialization. In both cases, the factory creates the necessary bindings between properties afterward.

Refactoring with components

Update: check this article for more in-depth details on Component Binding!

I've been refactoring my engine with the component-entity model, and things are turning out quite nicely. The one problem I always had with components was the way inter-component dependencies were handled. In the article I linked (one of the classics on the subject), the author says his components originally referenced each other through a component manager, but eventually they allowed components to store pointers to each other for performance reasons. In my mind, that's way too many concrete dependencies.

Prepping for alpha release

[These posts are now being mirrored on my GameDev.net developer journal. Check out their new revamped site, it's pretty sweet.]

I am getting ready for an alpha release soon, very basic, with one tutorial level and a level editor. So looking at installer options for XNA games, this WiX XNA installer appears to be the best choice. It's designed for SharpDevelop, and it creates an installer that checks for all the required libraries and even the required shader model. Unfortunately it's kind of a pain to set up. There's a massive XML file that needs a reference to every single file in your release.

Parkour Ninja animations

I'm going to poke my head in here to reassure everyone that the game is making steady progress. The environment now turns transparent when it gets in the way of the camera, and the player has some nifty new moves and mechanics, plus a very shnazzy looking power bar to indicate how much "juice" you have to perform special moves. The latest addition here is the skill roll, which prevents you from slowing down or dying when falling long distances. Take a gander!

December 2010 Tech Demo

I finally got animations working! I'm using a Blender to FBX script, along with this fantastic multi-take FBX importer. Apparently XNA depends on the actual FBX API for importing, and the API changed drastically just before XNA 4 released, so they didn't have time to get multiple takes (animation clips) working in one file. This importer automagically splits out the takes from the FBX file, processes them independently, then combines them into the original model. I encountered a bug with the Blender to FBX script, but as of today it's been fixed and committed. You can get the Blender export script here and the importer here. (edit: here's a sample project, including a .blend file, .fbx file, and all necessary code)

Further deets

Okay, it's time to shed some light on this project.

First off, my goal is to release on Xbox and, if possible, Steam (if not, I'll be looking at other online stores). I figure these are the two largest, most practical target markets. The release price will be between $1 and $5, with 100% of the proceeds going to charity (more on this later...).

There are two main themes I want to nail in this game. The first is giving the player freedom to alter the game world; to literally change the world geometry by performing sweet parkour moves (jumps, flips, slides, etc.). The idea is, to create a wall, you simply jump into mid-air and perform a wall jump as if the wall was there, and poof, it's there. Need to get through that annoying concrete barrier? No problem, slide right through it like it's butter.

Back at it!

That's right kids. I's back with a new game project. I will post these two tantalizing morsels for you. Let the wild speculation begin!

I realize the chill music in the video doesn't exactly match the motif of the above image, or the whole game really, but hey, it's just a tech demo. No need to start murdering people just yet.

Tricksy closures

Do not be fooled by the elegant simplicity of the mighty closure! Behind its shiny dynamic veneer lies a powerful machine capable of destroying your immortal soul. Behold:

function GetOutputFunctions()
    {
        var outputFunctions = new Array();
        for(var i = 0; i < 4; i++)
        {
            var x = i * 2;
            outputFunctions.push(function() { alert(x); });
        }
        return outputFunctions;
    }
    var functions = GetOutputFunctions();
    for (var i = 0; i < functions.length; i++)
        functions[i]();

This will not output the first three multiples of two, as presumably expected. Instead it will output "6" three times, because the variable "x" is only allocated once.

Phew

Well, I submitted A3P to IndieCade on Friday. It's also currently in QA testing for an online gaming portal (BigPoint, still free of course).

I won't say that A3P is done, but I think it's pretty stable. I need to do a bit more work on the connection establishment process (it seems a little fragile), but other than that, there's not much else to do. I also packaged the game into a standalone version available here: Windows (68 Mb) and Debian Linux (77 Mb). Speaking of packaging, if anyone with a Mac is interested in creating a Mac installer, please contact me. It should be pretty easy, the only reason I haven't done it is because I don't have a Mac.

Moar physics entities

Drop pods no longer sit in one place, they now roll around, freely dispersing their monetary goodness among the citizenry. They're quite light too, which means a single grenade can send one flying across the map, with your bots following in hot pursuit. Speaking of maps, Sector X is just about done! It's definitely our most massive map to date, and it has some interesting moments. So far the ring around the top has been great for sniping.

More maps

The main menu now has a global chat room, powered by some simple PHP/MySQL. The tutorial has been updated (it looks a LOT better), and the website received a makeover too! A lot of behind-the-scenes updates have been happening as well... the network code is becoming increasingly bulletproof, and several more physics bugs have been addressed.

And now for the fun stuff... more multiplayer maps! The first one is called Gold, it's adapted directly from the gg_halo_gold CS:S map. It's basically already done, and it promises to offer some intense 4-player action. The other two are works in progress, but both are looking like they could facilitate some epic battles.

Feedback from beta 2

Hey everyone, it's me again. I'm happy to report that Beta 2 turned out pretty well! We got a bit of publicity for the final release, and more importantly, some valuable feedback. It sounds like people had trouble with the browser plugin, so in addition to the browser-based game, I'm also going to release a stand-alone version with a self-contained installer. This also re-opens the possibility of LAN parties in the absence of an internet connection.

Beta 2 is out!

 

A3P Beta 2 is live, go check it out! This release has a whole slew of new features, some of which have been covered on this blog. To recap:

  1. New camera angle and aiming methods. Should be familiar to fans of Gears of War and loads of other third person shooters.
  2. New money system (the return of drop pods!) with a whole new UI for purchasing items to boot.
  3. Massive AI overhaul using navigation meshes rather than waypoints.
  4. A whole new game type called Survival. Think Nazi Zombies or Dawn of War 2's Last Stand, although maybe not quite as awesome.
  5. Three new fabulous maps created by the excellent Bobpoblo. Seriously, check out his CS:S maps, he's a genius with Hammer.
  6. The molotov cocktail is the latest addition to our assortment of weapons available. Use it wisely.
  7. Revamped online lobby complete with a nifty global chat box.
  8. At least 3.7 million other tiny little updates and bug fixes. Like the spawn points and home bases, which have been modified to be much less annoying.

So go hang out in the lobby and check out the new features! This will be the last beta release before the final version, so get your feedback in now!

Meshes of navigation

Update 8/23/2011: the source/executable for the navigation mesh .obj exporter is here. Import a mesh, set up the parameters (only simple mode is supported right now), and have it generate the mesh. It should output a .obj file in the directory where it was executed.

The AI system has finally received a massive and desperately needed update: support for navigation meshes. That means the bots shouldn't get stuck running into walls all the time, or running back and forth between waypoints like machines. I think this was probably the biggest weakness of the game up until now; the AI is still something of a problem, but it's much better.

More stuff!

We are closing in on a new release here... in the mean time a lot of new features have been added!

First, and most notably, I'm experimenting with a new camera strategy. If you've played the excellent Just Cause 2, it's very similar. By default your character is off center to the right, with a wide, inaccurate crosshair on the screen. You can right-click to zoom in and increase your accuracy and damage. So far I think it's a major improvement over the old system.

Drop pods are back

And they're much more interesting now. Instead of delivering reinforcements, they now act as cash dispensers. So rather than receiving a flat sum every match, you'll have to earn your money by remaining near a drop pod. Currently, the pod doesn't make you wait and then dump all the cash on you in one transaction; the money is deposited in $10 increments every second. We'll see whether that changes or not.

New maps, new weapon, new money system, new game mode!

I've been silent here for a while, but that's just because I've been busy getting some glamorous new features in! Things are really starting to shape up.

First things first. Bobpoblo has joined the team as a mapper/tester! He's been working hard on some new maps made in Hammer, textures courtesy of [-B-]. The original maps will likely be remade as well.  Unfortunately the content pipeline is a little convoluted: I open the Source map in Crafty, export it to Wavefront OBJ format, and import it into Blender. From there I fix import errors, remove degenerate triangles, apply lightmaps, etc. before exporting to .egg format.

New command system and social portal

Quick update just to keep this blog alive. I've made some improvements to the command/AI system. It's now much simpler and easier to tell your units to attack a specific enemy. The closest enemy you're aiming at is highlighted, and you can hit Q or E (depending on which one of your two units you want to command) to order an attack on that enemy. Special abilities are also mapped to Q or E, when tapped twice in quick succession.

Spawn points and more networking

Networking has received yet another performance boost. I discarded Panda3D's network classes in favor of Python's sockets. I also switched to a single-threaded, non-blocking system that performs significantly better and clears up the messy Panda3D threads that were acting very strangely. I also improved the connection process; both the client and server now send packets to each other while connecting, in an attempt to punch through even the most draconian of NAT schemes.

Finally, online multiplayer!

I've updated the browser plugin to finally support full online multiplayer! Go try it! I think the plugin is now stable enough that I am promoting it as the officially recommended method of playing the game. :)

Of course, there are still some problems. Namely, in Internet Explorer the mouse control doesn't work. Testing so far has shown Firefox 3 and Chrome (on Windows) handle the game very well.

So give it a whirl, and please post any errors or bugs you get, along with your OS and browser!

Update

Not dead... just really busy. Been doing a lot of network debugging and optimization; I added zlib compression to the network packets, which cut down network bandwidth by about a fourth. I also streamlined a few network issues, added a simple network performance logger, and implemented simple client-side interpolation; everything moves much smoother now, even if there is a slight delay. It's basically a fact of life these days in online games; as long as hit detection is still accurate, a small delay is practically unnoticeable.

Gameplay trailer

Finally got sound working in these videos, yay! New features in this video include the aforementioned shadow mapping and reloading, a brand new three player map called Orbit, and heavy modifications to the original Impact level.

I really cannot wait to get the multiplayer up and running, and get people playing the beta. Next on my to-do list are a few standard online features: basic match-making, in-game chat, etc.

Without further ado:

Reloading, shadow mapping

Thanks to the Panda3D 1.7.0 shader generator supporting shadow mapping, and the awesome new BuildBot service set up on the Panda3D website, A3P now supports basic shadow mapping! Actually, the sun is just implemented as a giant spotlight with a 2048x2048 shadow buffer. Definitely not the most efficient or high-quality method, but certainly the easiest, and the results are acceptable.

Also new in SVN is a reloading mechanic. The shotgun, chaingun, and sniper rifle all have to be reloaded, with varying clip sizes and reload times. Of course, reloading units are highlighted as vulnerable, and they also beep furiously to make it perfectly clear they need to be shot at.

Schedule delays

It's time to face the facts. While the game is progressing at an incredible pace, it's not going to be ready by January 9, or even the end of January. So, I guess I failed to meet my deadline.

But! I'm not giving up. I'll still be releasing regular updates, and especially once the multiplayer lobby server is set up, things will start getting a lot more polish. My new goal will be to finish the game before school lets out for the summer. Of course it will be online and playable well before then, but I won't consider it "finished" until I'm satisfied.

v0.5a released

That "a" stands for "not quite ready yet". This is sort of an intermediate release that focuses mainly on online multiplayer, which is largely functional, but needs more testing. Aside from polish and bug fixes, the only other things I'm going to add are more weapons and special abilities. And maybe a new level. We'll see.

This release went much smoother than the last two, as I used Panda3D's built-in packpanda to make the installer. I also cut the installer size down by scaling images, deleting unused files, and resampling music and sounds into the Ogg Vorbis format. It's incredible what Ogg Vorbis can do; without sacrificing any quality at all, I cut down the music size by about 20%. With a bit of downsampling, it was about 50%. The final installer is 80 Mb, a far cry from the 176 Mb v0.3 installer!

New name: A3P

Goodbye Stainless, hello A3P. I spent a good chunk of time creating new A3P material and switching everything over to the new name. Unfortunately, SourceForge's UNIX rename feature is down, so I created a new project for web hosting purposes only. The code and file releases are still on the Stainless SourceForge project. Which, to be extra confusing, I renamed as well, but again, I couldn't change the UNIX name.

New gameplay

Sorry for the distinct lack of updates this blog has. A lot is happening right now with Stainless, and most of it's good. :)

First off, Stainless is going to have online multiplayer! Woot. Thanks to the fabulous work by the guys over at Panda3D, it may even live in a browser plugin on the SourceForge website. Either way, I came across a problem I never anticipated with online multiplayer: NAT punch-through.

Stainless v0.4

Available on the new website: stainless.sf.net

There's a whole bunch of new stuff in v0.4 that I don't have time to talk about. So check out the website to see the new HD trailer.

Replay functionality, new icons

Yes, you can now view the last five games you played as a spectator! All I did was save each network packet that's sent out into a big list, then use Python's pickle module to serialize the list to a file. Each packet has a timestamp, so I just read the packets back in order, checking the timestamps to make sure it reads the packets back at the right speed. Fast forwarding is not implemented, but it would be pretty easy. Rewinding/seeking would be more difficult, so I'm not sure I'll get to implement those.

November update

This month's release will start to show more of the Real-Time Strategy side of Stainless. One new feature that unfortunately will exclude a section of the target audience is speech recognition. I'm using the MS Speech API, which obviously only works on Windows. Sorry Linux and Mac users. :(

Still, it's going to be worth it. Right now the level design and AI are not quite advanced enough to benefit from speech commands, but the potential is there. Also, the game has a new system for money management, which means players will have to start rationing their money and deciding which units to buy. Basically, you'll buy the right to use a certain unit for one round in a game, and no matter how many times that unit dies that round, he'll respawn for free. But then the next round, you have to buy all new units.

Stainless v0.3 beta released!

Along with an HD trailer. Free download here!

Prepping for first release

Less than one week away from release! Looking at the to-do list from last week, I actually haven't worked a lot on the items listed. I've been ironing out a lot of bugs and adding polish. The multiplayer scoring is now working, and you can see everyone's scores on the top of the screen, conveniently color-coded. I killed the ugly black boxes around the scores and added drop shadows instead, and I moved your current balance to the right side of the screen, to avoid confusion. Take a gander:

Production schedule

Yes, I have a schedule/deadline now. I'M SO NERVOUS. :)

Here's the plan. And when I say "forum", I am of course referring to the fabulous GameDev.net forums.

  1. October build - Release 0.3, Oct 31 - with the following AI droids: shotgun, sniper, shield, cloaker, melee, chaingun. Virtual file system, XML map format, working multiplayer with scoring and simple "game over" condition. No ability to choose units yet. First forum announcement.
  2. November build - Release 0.4, Nov 30 - implement unit suppression from grenades and melee jump jet. Complete match/round logic. Simple squad orders. Unit selection screen at match start. Rough draft YouTube trailer. Forum announcement update.
  3. Official release - Release 0.5, Jan 9 - special abilities, finalize multiplayer maps, finalize YouTube trailer, overall polish, official website goes live. Image of the Day post / official forum announcement.

January 9 final release! Which means Stainless will have been in development for exactly one year! Quite impressive for a guy who never seems to finish these things.

More shiny!

Three updates, one in graphics and two in gameplay.

Graphics: new water shader! Thanks to Panda3D's new built-in support for user clip planes in the shader generator, the reflections were a piece of cake. It's a very basic shader that simply deforms the render buffer and the reflected render buffer, then blends the results 50-50. No fresnel, no lighting, nothing. It works, though.

Using the distortion shader from my last post, I added a shield droid that puts little shields around team entities in its vicinity. The shields decreases ranged damage by 25%.

Panda3D distortion sample

For any Panda3D users out there, this is an improved version of the frame-buffer distortion sample currently shipping with Panda3D 1.6.2. Whereas the original sample just samples a wave texture to offset the frame-buffer sample location, the shader in this version actually uses normals from the Egg model. It also gives a slight tint to the object. You can easily adjust the color and intensity of the tint at the top of the "distortion.sha" file.

New artwork

Yeah, I'm back to art now. I am ashamed. But I'm starting to get the hang of this Blender stuff. Check it out:

New weapon model. This is a Blender Render, not in-game.

And here it is in-game. Don't worry, I fixed the clamped textures on the bottom after I took this screenshot.

Here stands the inanimate metallic ball, ready to kick butt and take names.

And now for something completely different...

I actually planned a full-fledged single-player campaign for Stainless, before I came to my senses and downgraded it to a much simpler multiplayer game. However, I'm still considering a short (2-4 hours) campaign. What I have in mind is similar to Valve's strategy with Left 4 Dead: a short, highly replayable campaign designed for 2-4 players. With one catch: the players are fighting against each other.

With my limited marketing and branding skills, I have dubbed my idea an "anti-cooperative campaign". It would be best with 1v1 or 2v2, but regardless of the player count, the computer would balance the teams by bestowing various power-ups. Which means, if I ever add an online component beyond LAN, matchmaking would be unnecessary.

Network system description

As promised. :)

First, a small disclaimer. This network system is designed for a very specific task: handling networked physics/gameplay over a LAN network. The structure described here might be useful in other scenarios, but the actual Python code is certainly not fit for much else.

The system follows a modified Model-View-Controller pattern that focuses on two main types of objects: Entities and Controllers. The "View" part is split between the Entity and Controller. Entities handle most of the assets tied to a standard object in the game world: namely, the physics geometry and graphical representation. Each Entity has exactly one Controller, which handles all (and I mean all) actions the Entity can perform. The Entity will not move at all without a Controller.

Perfunctory postage

Wow, so many updates to cover. I've been without internet for awhile, so... deal with it. :)

Let's start with a list of new improvements:

  1. Networked gameplay is now fully functional. Weapons, grenades, springboards that propel players around the map, it's all there. I'll make a bigger post one of these days that describes the whole system in more detail. It was quite educational for me, and I'll still be modifying it for awhile.
  2. The main arena level has received an upgrade in the form of a massive tower thing in the middle, with bridges going out to springboards on either side. Which makes it now completely incompatible with my primitive AI system. Oh darn.
  3. I'm using a nifty particle effect when the player spawns and to highlight the springboards. Kinda slow without the Panda3D MeshDrawer class though.
  4. The generic physics object, known as "Block" has received a visual overhaul. This was my first experiment with dirty textures, and it turned out not too bad. Textures were done in Inkscape and Gimp (with a normal map filter plugin).
  5. There is now a functional main menu! Well, more like 50% functional. Still on the to-do list: allowing the user to specify what server to connect to (possibly with a server auto-detect function), and allowing the host to choose which map to load. Also farther out on the roadmap is usernames and logins. And can anyone tell me how to deal with Blender's ridiculous smooth/solid mesh setting!? I can't get the continents to be smooth-shaded without screwing up the normals on the edges. It's passable for now though.

Behold!

Networking and better particles

Network code is working reasonably well now. The server generates a unique MD5 hash (only six characters) for an entity, then broadcasts a packet to the clients instructing them to spawn an entity of the correct type, and assign the same hash as its ID. From then on, the server turns over the reigns to the entity's controller, which can send any information it wants in its own sandboxed data packet.

Done with art for a while

I've spent way too much time fooling with the Blender-Panda3D content pipeline, so I'm moving back to working on gameplay and coding.

That being said, the art was fun while it lasted. Here's a sample of the results:

Wrestling with Blender pays off sometimes.

All art in this screenshot was created by me. The arena geometry enclosing the map was created by extruding individual faces of an icosphere. The texture maps were drawn in the excellent Inkscape, then touched up in the lightweight-but-useful Paint.NET, then crunched by the incredibly flexible and powerful CrazyBump for the normal maps. The whole process is recorded here for posterity:

First major update

Mmm. Been a while, hasn't it.

Latest and greatest feature list:

  • Nifty particle effects for bullet impacts
  • Decent AI pathfinding
  • Grenades don't go through walls any more :D
  • New test map with spiffy baked lighting courtesy of Blender

Custom-made photoshop rusty grunge metal texture.

Current project: revamping the orbital dock model seen on the front page screenshot. First up: my first shot at a rusty grungy metal texture. Made from scratch in Photoshop in about a half hour with four layers of noise, airbrushing, blurring, burning, and dodging.