Friday, April 21, 2006

Game, Set, Vyde

I've been dating a girl named Heather since last Christmas, and she's pretty cool.

She's pretty cool for lots of reasons, but mostly because she plays tennis.

See, when we started dating, I seemed to run out of time for anything else. So no work on Vyde! She got hooked on Lost, so lots of our free time has been taken up catching her up from the beginning. We have Netflix to thank for that.

I don't play tennis. This is important, because it means that I can watch her play tennis instead. I find that watching tennis is a lot more fun than I thought it'd be. It's especially fun when she plays, 'cause she's a power hitter, and there are some ESPN-worthy moments when she's diving for the ball or returning it in a way that makes me glad I'm not in the ball's path.

She plays tennis 2-3 times a week, and I have a laptop. This represents a dilemma, because I can either watch her play tennis, which she likes, or take the opportunity to prototype some Vyde ideas outside in the spring air.

She seems to like me being there either way, so maybe it's not as much of a dilemma as I think. After all, she's been bugging me to mention her in my Vyde ("veed", she says) blog. I wonder if I throw her some props now and then if she'll continue to be OK with me working on a laptop while she plays tennis...

Monday, April 10, 2006

Over-engineering

So BlackTigerX says in his most recent comment that what I described in my last post is a case of over-engineering (with a hyphen, 'cause that's what turned up the most results when I Googled it). He's very right, and not being acquainted with me he probably has no idea how funny his observation is.

My tendency to over-engineer is dramatic. Always has been. Perhaps it's a character flaw, but I tend to like to figure things out before I attempt them.

I will often spend a significant amount of energy just thinking about a problem. I suspect many folks look at me and think, "Why doesn't he just try something? Anything?"

The answer is this: because when I do that -- try something just to see what happens -- I invariably throw out the result. The reason is always the same, too. Invariably, without digression, I run up against that "something I didn't think about" that causes my whole mental model up to that point to collapse.

Mix that behavior pattern into the feedback loop where it combines with over-engineering, and you will have undoubtedly spent twice too much time trying something that proved useless.

I've done this too many times to repeat it anymore, so now I tend to just think about the problem. That way, I reason, I will run into those showstoppers in my head, where the cost of failure runs no more than that of a still-maleable mental model modified.

But I adjusted my strategy lately. I'm trying to make a concerted effort to break problems down into more manageable chunks. I'm doing it both at work and at play. Some of the results have been encouraging: I find that I'm spending more time working on Vyde now that I have a more concise set of immediate goals. But I also find the results a little troubling: with less design and more attempts, I've found that I'm throwing out solutions and then repeating those mistakes in a different way later. Though rejected attempts seem to spur a new line of reasoning, I think it may be an illusion, as the new path tends to run up against the same problem more often than not. You'd think that taking a different approach would lead to at least a different kind of problem, but no, the problem I didn't take the time to think through the first time shows up again. I think this lends some credence to the idea that design really is worth doing, and over-engineering is something to reduce, not eliminate.

I've noticed a similar pattern at work. There come times when my complicated designs get the better of me. Today, for instance, I all-of-a-sudden felt overwhelmed by the complexity of my current project. Specifically, my ability to unit test has reached a plateau: building in layers seems to lead to testing procedures for higher-level constructs requiring a lot of low-level legwork. That is, if an instance is created as a product of low-level code, my unit tests for higher-level operations on than instance require building the instance from scratch.

Wait. I'm doing it again, aren't I?

Thursday, April 06, 2006

Perfection is the Enemy of Completion

It's true. So why must perfection be so damn attractive?

I've been thinking a lot about Vyde despite the lack of blog posts. The problem is that I'm wrapped up in creating an elegant system that I'm losing interest in building a game around it.

This is a trend that's showing up a lot lately. I'm finding I have to keep myself in check lest I get lost in problems that I arguably create myself.

Most recently, in Vyde's design, I've been wrestling with something that most other game developers would probably find trivial: a tiling system. How do I want to represent the tiles that makeup Vyde's playfield? How do I want to generate random patterns? How do I want to persist generated maps to disk?

OK, so those are the simple problems. Then I stem off additional problems from those: should tiles be composable? Should I be able to zoom into a tile and have it generate its own innards in a pseudo-fractal fashion? Could such a system be used to allow the camera to zoom into the insects crawling along the cave walls, allowing the player to see how the insects dig?

How should I build the system that generates and connects parametric, randomized geographic features? Considering I want to be able to hand-craft special rooms and have the game consume them, and that I want to be able to apply "random" features as the game chooses, does that demand a common superclass? Assuming it does, do I need to come up with a "painting" paradigm that is analagous to the way you paint onto a Bitmap object using the Graphics class? Should I develop an "applicator" class that applies features from a factory into a region I specify?

How are regions connected? Do hand-crafted rooms need to have connector regions specified so that the random tunnel generator knows where to "connect" to the room? And how to I plug in different tunnel generation strategies into the generator? Is this a job for a factory pattern or a strategy pattern? Or both?

And if a room is placed on a seam between two sectors, is it the applicator class's job to figure out what to draw in one sector and what to draw in another?

And what happens if the room has some kind of special behavior attached to it? How do you reconcile the room being split into two pieces on the map if it spans multiple sectors? If the tiles are composable and every tile has its location specified as an offset from its parent tile's upper-left corner, then is a room really a subtile located at some offset from its parent? Does this demand variable-size sectors?

And if so, what are the implications of drawing graphics if their coordinate system is variable? If the world runs in all directions infinitely, how do you specify a coordinate system using finite numbers, and how can you nest coordintae systems to facilitate the zooming mentioned above? The "world tile" might have to be parented on-the-fly when the player crosses the edge of the last available tile...

Oh wait... how do you make a tiling system?