Monday, November 30, 2009

hire me!

I'm a game programmer looking for work, in LA and willing to relocate. I'd like to do gameplay, audio or general programming. Here's my resume as a word doc.




I've been working on a little game demo, a roguelike. You can download the installer (run the setup first, it's a ClickOnce installer). Mike Tipul (a coworker) and I started it a year ago, and we collaborated on it then abandoned it until recently, where I dusted it off for release. There's a codeplex project for it, or you can download just the source (no project files, no artwork).



Features:
* Tile based pseudo-ascii rendering
* Visibility/lighting and shadows
* Procedural dungeon and forest generation
* Location-based damage and severed limbs affect gameplay
* Weapons and multiple damage types
* A tiny little mission where you clear out a forest of wolves, then a dungeon of goblins
* Lots of tutorials that walk you through the game (which is about 5 minutes long)

Monday, October 27, 2008

gravitybone

I am so impressed by gravitybone. Clever, funny, artful - and I'm not just saying this because Brendon's in this building. This is the sort of thing I wish our industry (and me specifically :) would produce.

I'll probably think of it every time I hear 'perfidia' (that and Wong Kar-wai) then play it again. It's worth your time (it's short and very friendly) and the hassle of fileplanet's download service.

Saturday, June 28, 2008

C++ is so baroque

Because of stuff like this. What's so crazy is that webpage is all good advice - a page of code to make a type safely cast to bool.

And here I am reading it all.

Saturday, June 7, 2008

natural intervals in programming

Don't read this, it's boring. I sometimes run into bugs dealing with the edges of intervals. Most of these bugs are because some code assumed an interval was inclusive at the top, and some other code assumed it was exclusive.

Most people seem to understand the convention for array sizes (ie a function called int getSum(const int* a_Array, a_Count) wouldn't touch a_Array[a_Count], and a two-parameter version getSum(int* myArray, int start, int count) would touch a_Array[start] but not a_Array[start + count]), but we don't always get it for floats / real numbers.

I think the "natural" way to split intervals is half-open, like [a, b). To include the bottom and exclude the top, and to do it this way for integers and real numbers. All your "is this number in this range" checks should be of the form fMin <= x && x < fMax, and this should be a convention you can use without really thinking about it.

The important part is consistency. If different parts of code assume a different convention, you're boned. There are a few reasons I think the best convention is the interval [min, max). It's the closest to how division and quantization work - an object at 20.0 gets put into bin 2, because 20/10 = 2. Any logic and math is consistent no matter how we're storing the positions (if they were meters in integers, floating point numbers, or 10s of meters in integers, whatever). The reason the interval has to be half-open is so that only one of two adjacent intervals gets the point (this is important for partitioning groups of things).

Most functions that deal with ranges of numbers exclude the top. Random usually returns [0,1), arrays can be accessed from [0, count), this is how quantization works (representing RGB with char values gives you the range [0, 1<<num_bits) for each channel), etc. This is so boring, so don't think about it - just use min <= x < max.

Sunday, April 27, 2008

boogs

This bug:


Looks kind of like this cellular automaton.

Friday, December 28, 2007

english muffin and egg

Serves one lazy bachelor, takes about 5 minutes, an egg, an english muffin, cheese and salsa.

  • Split an english muffin in half and start it toasting
  • While you wait, crack an egg into a bowl, and mix in roughly the same amount of salsa
  • Melt a little butter (for frying) and optionally cheese in a frying pan - low/medium heat on my range. If it starts sizzling before you're ready, turn the heat off or down.
  • When the muffins halves are done toasting, soak them in the egg batter, then drop them in the pan. The butter and cheese in the pan should be sizzling and bubbly by now.
  • Flip the soaked halves every few minutes. When they've browned a little on each side, pour in the leftover salsa-egg batter beside them in the pan - it will quickly fry into a sort of sloppy omelette. Flip it over once it's solid, let the other side cook, then take everything out of the pan together. I salt mine after I take it out - it's savory, not french toast.

Variations: If you don't have or want salsa, dilute the egg batter with something (milk worked for me) so it soaks into the english muffin better, and fries differently(?). Don't add spices to the egg mixture, because they'll just clump together in the liquid - put spices directly into the frying pan near the end (or else they'll burn in the hot oil while everything's frying). I used cayenne and ground ancho peppers.

Wednesday, September 19, 2007

hidden state vs. nondeterminism in games

Complexity
In certain types of games like chess, go, and checkers, there's a clear definition of the game's complexity (wikipedia entry). It's a measure of the branchiness and depth of the choices-tree that the players are building and exploring. In games that aren't combinatorial (ie. without a completely-known game state by all players), does it make sense to talk about complexity in the same sense? With either nondeterminism or hidden state, what happens to the players' mental model of the game tree?

Hidden Information
It makes planning harder, because you need to account for all the possible outcomes that depend on things you don't know: imagine deterministic poker with a sorted deck. Hidden information only makes planning harder to a limit, because if you know nothing at all then you can't plan at all. It seems like having a fraction of your game state hidden maximizes depth (or at least the difficulty of planning). Why don't more classical games have hidden state? Is it because hiding cards is easy, but hiding pieces on a board is difficult? It's hard to think of how, physically, you'd play checkers-with-secrets with someone... without easy cheating, anyway.

Alternately, imagine known-state poker, with face-up cards only. Hidden information is slightly intertwined with nondeterminism, though, because in deterministic poker there are no secrets to keep - everyone knows what cards you have, even if they're face down. To have secrets in a deterministic game, you need to make your choices secret (like fog of war in a deterministic RTS).

Nondeterminism
There are lots of games that depend on randomness for a similar effect on planning to hidden state, ie. any game where you draw shuffled cards or roll dice. It makes planning harder, because you have to think of multiple potential outcomes independent of each of your decisions. Hidden information is exploitable by the player who's keeping the secret, and adds lots of meta-game depth like bluffing and information management. I'm really interested in games where information management plays a key role, like in RTS games with fog-of-war, where visibility or radar coverage comes at a cost, and so does keeping secrets ("I could defend my main base if I use my secret cache of tanks, but if he know about my secret tank-producing base, he'd attack it from the air..."). It's like betting strategies in poker - they matter mostly because they reveal information, and the tradeoff is money, you're paying for information.

Complexity in Design
Why does complexity matter to us? If you did make chess-with-secrets, would it be a deeper game? Even if it was theoretically harder to plan your moves, chess doesn't need more planning complexity - it already maxes out our abilities. Only trivially shallow games need to be given more planning complexity. Nobody plays Go on an enormous board, even though it would be incredibly deeper. (Even increasing a 19x19 board to 21x21 would have a huge impact on complexity, but nobody would say it makes the game more fun).

Even without caring about planning complexity, nondeterminism and hidden states add a lot to a game. The boundary between determinism and nondeterminism starts to get fuzzier with videogames, where you have analog input and reaction times matter... it only makes sense to talk about it with respect to the actual decisions the player makes about the game, not the nuts-and-bolts physical input and output. It's at this level where a little bit of planning complexity is nice - deciding whether to silently walk or loudly run in counterstrike, whether to hide behind a wall in bf2142 or have a better line of sight on your enemies, or deciding when to reveal your strategies in an RTS or take pains to keep secrets. I think in almost any case in multiplayer games where you can give the choices to the other players (instead of making it random), you should. Instead of playing their own private slot machines in parallel, players enjoy dealing with each others' choices. It adds a social dimension to dealing with unpredictable outcomes where people can scheme and plot, and that adds metagame feedback where people need to anticipate and predict others' strategies.

Even without multiple players, the big thing about randomness is training players about rewards, with the Diablo/WoW style loot drops and Skinner-box feedback. Everyone claims to hate it, but its been proven to be effective (lucrative ;) design. Randomness softens the impact of losses on the ego, and gives the occasional reward to bad players to keep them playing - we're suckers for it. Giving people the chance to gamble their valuable resources on longshots lights up some primitive part of our brains - it's innately fun, even if it's only slightly related to the rest of the game.