Saturday, 18 February 2012

Holes



Not an awful lot to discuss this weekend. The dungeon is now a multi-level affair; you can just see the hole in the ceiling in the ugly screenshot.

At the moment, you can fall down a hole by walking into it, but climbing up requires a few conditions to be met. You must be directly under the hole, facing a wall (against which I shall eventually rest a ladder, I suspect), and the hex on the upper floor directly above the bit of wall you're facing must also be clear of obstacles. These conditions being met, you scramble on to the upper floor.

I'm considering shrinking the vertical distance somewhat. To keep things simple, the hexes have a diameter of 1 unit, the player has a notional eye-height of 1 unit above the floor, and ceilings are 2 units off the floor. Whilst this mostly works, it means that even with a relatively wide vertical FoV (I'm using ~100 degrees in recent screenshots), it's hard to clearly see a hole you're standing underneath. I'm considering just halving everything in the vertical direction and seeing what it looks like.

I also finally knuckled down and properly categorised wall-tiles. Given a tile that contains a wall and that isn't completely surrounded by walls, you either have:
  • Zero neighbouring walls - a pillar.
  • One neighbouring wall, a length of wall comes to a stop here.
  • Two neighbouring walls - with the walls in ortho, meta, or para position (adjacent, with a one-hex gap, or opposite each other).
  • Three neighbouring walls - four possibilities here, either clumped together, in a Y shape, or two different chiralities of "two-blocks-together plus one block on its own".
  • Four neighbouring walls - equivalent to swapping the two-wall case for two-spaces.
  • And lastly five neighoubring walls, giving a little nook.

Someone smart would doubtless have done something clever involving symmetries; I just assigned each wall tile a binary number by starting at the hex due north and proceeding in counterclockwise fashion around neighbours, setting a 1 bit for walls and 0 for empty spaces. I created rough meshes for the thirteen interesting cases in Blender and named them according to this scheme (wall_00, wall_09 etc). Then it's just a case of extracting this categorisation number from the map data at runtime, rotating the bits to get the minimum number out of the given arrangement of zeroes and ones, and rotating the numbered mesh the same number of times before rendering.

So that worked quite well, apart from the tiny fact that it's looking like a real pain in the arse to author interesting meshes without leaving sparkly gaps. I'm considering welding the mesh as a post-process, either the whole dungeon or in chunks depending on poly budget, but by this point it almost feels more sensible to hand-craft a dungeon level as a chunk of unique geometry and then go around setting up the logical grid to match.

Alternatively, it should be easy to do something like calculate a large, concave polygon for all dungeon geometry and then extrude it, but this doesn't help make the walls interesting to look at.

None of these approaches save hand-crafting or something involving marching cubes/tets suggest anything for a more natural environment such as caves, either.

Think I'm going to try to get the 2D debug viewer working and maintain that alongside the project, so I have somewhere to test out things whilst wrestling with the demons of content creation.

Tuesday, 14 February 2012

Dense Bugs

"The reasons go back to perhaps the most important empirical result in software engineering, one we've cited before: the defect density of code, bugs per hundred lines, tends to be a constant independent of implementation language. More lines of code means more bugs, and debugging is the most expensive and time-consuming part of development." — Eric Steven Raymond, The Art of Unix Programming.

I rather dislike verbosity in code, so I would love the above quotation to be true. Unfortunately at the moment I'm running on received wisdom and gut feeling; I have yet to find any concrete studies on the subject. It certainly wouldn't be easy to perform such a study, given the moving target of popular languages, frequently poor distribution of languages in a given domain, differing fluency of programmers requiring large sample sizes, choice of how one enumerates bugs and when one chooses to do so... I'd hope that a language that makes high-coverage automated testing easier would have a somewhat sharper decline in extant bugs over time, but maybe that's simply wishful thinking.

There are limits to how far this pursuit of brevity can be taken, of course. The more conceptually dense the code the more wetware involved in expanding it to a form that can be understood, and humans are hardly infallible when it comes to such transformations. Misunderstanding an obfuscated chunk of code will lead to the introduction of bugs, and the point at which pleasantly concise turns into impenetrably terse will be different for each reader. Meaningful naming of intermediate values helps me unpack a series of functional transformations of a collection, so I'll fairly regularly expand a series of maps, filters and folds within a let expression, and if necessary interject comments (with small functional chunks of code producing values bound to meaningful names, it is rarely necessary). So far so standard.

On the flipside, various kinds of boilerplate that add nothing meaningful beside additional LOC are all too common, even when avoidable. To take a small example, as the quite lovely Effective Scala notes, there is little benefit to "syntactical ceremony" (I love that phrase) by way of superfluous braces on simple functions or control structures. Yet many languages do not allow for such details to be elided, and even if they do we have a curious tendency to enforce maximal syntactic salt. I have never yet worked at a game developer whose coding standards allowed the quite standard C++ convention of skipping the braces on single-line conditionals and loops.

I call bullshit on this kind of ruling. In fact, I am not at all convinced by coding standards beyond a way to record naming conventions, formatting of comments to generate valid automatic documentation, and very general guidelines for style where the choice might otherwise be non-obvious (e.g. avoid using interfaces for small data-structure objects used in an inner loop, those vtable jumps add up quickly). When it boils down to the dictation of salting levels, especially favouring more rather than less, such documents cease to be useful.

In my opinion, anyway. I'm sure someone disagrees, because the bloody things never cease to be a pain in the neck.

Long story short, death to large codebases and coding standards that promote them, no matter how small the increment.



Game progress ticks along, I'm currently investigating dual quaternion skinning and fiddling with the relationship between the game logic loop and the renderable representation of logical entities. In particular, it was deeply confusing having multiple monsters performing multiple actions all at once, so I've fallen back on the model used by Wizardry 8 (among other games): wait for animations to complete before letting the next logical entity take a turn. I am worried that this will become painful for large groups of monsters, so this will doubtless require iteration.

I'm also going to have to check how to better push animation state onto renderable entities. At the moment it's just inferring that a "hurt" animation needs to play because the entity has less health than it had last turn, and so on. This is simple and makes sense in some cases, but does preclude having a "stagger backwards from explosion" animation that is unique from a "walk backwards carefully" animation, for example.

Thursday, 9 February 2012

I Hate Rigging

As the title says, I really don't like rigging models. I produced exploding poly-soup many many times before finally getting a pose that is... well, crap, but without too much in the way of broken bits. (Edit: Collapsed joints? Totally don't count.)



I also don't like making limbs. Torso and head... well, I can just about cope with them. Ah well, at least Suzanne has been replaced as the test mesh. This one is even amenable to animation, when I fix the topology and terribly broken rig and write an exporter for animation data and the relevant shaders and... and... look, it's not urgent OK?

Annoyingly, I have found whilst doing this that xNormal doesn't cope terribly well with small meshes (defined by it as those with a bounding sphere radius less than 2.0 entirely arbitrary units). I have chosen one length-unit to be approximately one meter, hence all my meshes are prone to dodgy results when fresh from Blender. I got around this by exporting massively scaled up versions for normal and AO map generation, although I'm pretty sure I actually fluffed applying the normal maps...

I suppose something more automated, and possibly entirely sourced from Blender itself, would be preferable anyway.

Other things: entities that bump into each other now perform an attack. This makes the target flash red and removes one hit point... baby steps, baby steps. When an entity dies, it causes each entity on its 'recent attackers' list to gain 1 XP.  Although I cannot think of a good reason to allow Guild Wars-style levelled monsters, it was easier to just implement this in a uniform way, and as there's no level-up mechanic it hardly matters in any case.

Tuesday, 7 February 2012

Floating Monkey Heads

With sincere apologies to Suzanne, basic entity logic is working. You can pilot your own floating monkey head around, colliding with walls and other entities. The only actions supported are 'wait', 'move' and 'turn', each with its own time cost. Now that the obvious bugs are worked out of the action timing, it will be nice and easy to extend these.

I switched to a free camera for debugging, and enabled geometry for the player. You control the green disembodied primate noggin in the screenshot:


Nothing interesting to report, except that the effect of a bunch of floating monkey heads drifting around is... distinctly creepy. I am very unnerved.

Oh, yes, ugly textures too. Did I mention those?

Monday, 6 February 2012

Sunday Progress

A few really minor features added over the weekend:

  • Mouselook. Trying out an implementation where you can only look around in a limited arc, and having the view direction automatically rotate back to the default when you start moving or turning your character. Not sure on this, might be more useful to have your character's direction change once the view rotates sufficiently. Danger here is that I'd like to have facing be an important tactical concern within the game, so character rotation is a distinct action that you don't want to trigger by accident.
  • Textures! OK, this was a ten minute bodge-job hooking up javax.image.ImageIO to grab JPG and PNG files, and they don't even have mipmaps yet. But it works, and as I have a working DDS export implementation... getting DDS import in place shouldn't be too hard. Then they can even be properly compressed textures with pregenerated mipmaps and all kinds of... ancient, unremarkable technology.
  • Tangents! And Bitangents! I'm just generating these at load-time from the data in the .obj files. I'm fully aware that at some point I'm just going to have to face the Python and create a Blender export script to a more sensible format, but... bleck, Python.


As a consequence behold the power of really, really ugly normal and diffuse maps:

More importantly than all this minor tech progress, and thanks in no small part to the aid of He who is called Fhtagn, the game actually has a design document! And the design is, at least for now, inspiring. It's good to have a direction. We're currently lumping everything in a few shared google docs, which is a nicely asynchronous way of working.

In between writing the code and reducing the inspiration quotient of the document, I've been playing a bunch of CRPGs (I blame finding The CRPG Addict's blog archive). In particular: Morrowind, Wizardry 8, Temple of Elemental Evil, Neverwinter Nights, and Neverwinter Nights 2. Flitting about between these is playing merry hell with my ability to keep track of quests, but the contrast is fascinating.

Thursday, 2 February 2012

Fragile Worlds

Why do certain programmers - myself included - keep returning to procedural content generation in games?

It's so easy to get it wrong. Too homogeneous, too random, too formulaic... humans seem to be wired for pattern recognition, and most procedural content consists of layered patterns. Even worse, it sometimes gets used in games where we perceive a narrative bent, games where there is an overarching reason why the world is the way it is... but the why of such generators is always 'because Perlin' (or whatever). We can layer procedural details over a narrative world, but unless they remain harmless, forgettable greebles attached to the background or strictly bounded by the requirements of the story, the tension between that story and random numbers can irritate.

I think we've also gotten used to a small army of architects and landscape designers marching just ahead of our progress through game worlds, artfully arranging every detail where it matters and gently eliding where it does not. The generators do not care. They may produce breathtaking scenes, as nature is wont to do, but equally produce a hodgepodge of clutter and boring expanse. Worse, they might have the audacity to produce these at exactly the wrong time, leading us away from the golden path through the game. The horror, not only do we have choice in where to go rather than marching through a linear series of cutscenes and set-piece battles, we might not even have a flashing neon marker to follow when we wish to rejoin the railroad plot!

So that's why we shouldn't use them, except as a time-saver for little, tedious details that an artist or designer would be wasted upon.

Except.

What such generation produces, at least to a good approximation, is a unique world. As mentioned, the massively chaotic systems of the real world are quite capable of creating something inspiring, terrifying, engaging, and explorable. We're aware on some levels that this world is all we've got, for the span we get to walk upon it. Whether this remains true, for now I think that the worlds which are unique and fragile resonate the most with us.

Roguelikes get brought up often in discussions concerning PCG, along with the hazy nimbus of somewhat similar games. These are important not just because they operate at a level of detail which we're happy to accept procedural content, where we're free to elaborate upon it internally (of course all these corridors aren't alike! They're just rendered with the same ASCII characters, despite being replete with details and variations that conveniently use no disk space or polygon budget), but also because of the permadeath mechanic. It makes everything so much more interesting if you know that not only are you breaking new ground, but that something wonderful might be around the very next corner that you never, ever get to see because you just died to a pitfall trap. And along with your character, the world is gone. The new one will be broadly similar of course, but you'll never find out what was around that corner. Instead, you get a universe of fresh new corners, that you might die before you have the chance to peek around them.

Unless you savescum. We don't discuss such perverse habits in polite company.



This rant dates from sometime in the middle of last year, when I was exceptionally bitter about some linear game or other. Skyrim has once again struck this nerve, at once hurling me into a wide open world (woo!) and poorly designed (if very, very pretty) linear dungeons (boo!). Many games do offer very compelling procedural worlds, roguelikes not least of them. Minecraft and Terraria leap to mind as in addition to a large and potentially interesting random world, they offer huge player agency in effecting changes to those worlds. It's a potent mix.

So, this is maybe a tad angrier than I feel is appropriate right now, but it was mostly complete. And I still feel strongly that fragile gaming experiences, unique procedural worlds and the divisive permadeath mechanic all have their places.

Unpretty

It wasn't pretty, but Leiningen is now generating a large .jar containing almost everything required to run a chunk of stuff excised from my "random clojure braindump" folder. So now I can in theory show my tiny vestigal 3D roguelike/turn-based Dungeon Master/hex-based Legend of Grimrock clone to people! People that don't have Clojure installed!




So, yay for progress! It's not pretty yet, but that's... mostly a case of sorting out my miniature asset pipeline: exporting from Blender in a slightly richer format than .obj, generating tangent and bitangent vertex data, normal and displacement maps, and associating this all together with diffuse and specular info. Some gruntwork to finish recreating the deferred rendering setup in clojure. Mostly simple stuff, although there is a lot of it.


Enough of that, random question time:

How do people approach cross-project hacking at a small scale? In this case, I just grabbed my nascent main file, vector math and rendering files, and a bunch of utility stuff and copied it into an empty project directory, but I would really like to bounce the data back and forth between hacking at random ideas and this (theoretically) slightly more stable project...

I suppose nested Mercurial repositories would be one approach, split all the 'engine' crap into a subfolder with its own repo and use that to keep everything in sync. Anyone have any experience with this approach? I guess using the magical .hgignore file to elide the 'engine' stuff from the main project repo would work in theory.