Arriving in Damascus is an on-rails first-person hypertext interactive fiction (ORFPHIF), made as my One Game A Month, and produced to help battle-test “uTwine”, a Twine for Unity implementation I’ve been working on.
I started out planning to make a Dear Esther parody, but as I went along, I discovered that (1) not surprisingly, it had already been done, and (2) I was finding it difficult to make light of the original, given the subject matter surrounding grief and loss. So, I went for some parallel universe ‘fanfic’ instead, and tried to capture some of the atmosphere, extending the story in another direction. Here are a bunch of things I learned along the way.
The Unity Asset Store
Dirty little secret – I’m not particularly adept at 3D modelling. In fact, I’d go as far as to say I can’t really do it (lock me in a room with a months worth of food and water, my laptop and the Blender manual, and I might have a different story). Almost everything in Arriving in Damascus is based on free assets from the Unity Asset Store, and the Unity Standard Assets package. Sometimes I tweaked the textures to match the colour scheme, but otherwise they are just scaled, rotated, and used as provided (see the Credits in game for a listing). I did make some (spoiler alert) crazy scary trees myself, using ngPlant.
The music is Sonata for Cello and Piano – I. Prologue – lent, Claude-Achille Debussy, performed by Paul Pitman from Musopen. I was pretty happy when I discovered this particular site .. what an awesome resource !
The NavMesh hack (or, “How to use NavMeshes with LoadLevelAdditive”)
Unity Pro has a nice feature for baking and navigating via NavMeshes, so you can have NPCs (or in the case of Arriving in Damascus, an on-rails first person view), move from A to B taking the shortest path while moving around obstacles. In Unity Pro (4.x), a baked NavMesh is associated with a saved “Scene”. Most of the time, this is all well and good, but as others have discovered, sometimes this simplification / limitation poses a problem when you want to use LoadLevelAdditive. To solve this, I discovered a (hackish) workaround that involves associating a single baked NavMesh with two scenes, via editing the Scene file in text mode. I’ve put the details in it’s own post, for the benefit of search.
Grass texture artefacts
I had a lot of difficulty with artefacts in the grass textures when using Unity’s terrain engine (so much so that I didn’t end up using a grass texture I really wanted in the first release of Arriving in Damascus – I may fix it in an update). Many others have noticed these thin lines at the edge of grass textures before – it appears to happen because of the way Unity makes it’s texture atlas for all the terrain detail textures. Lots of suggested solutions sometimes appear to work (changing texture Wrap Mode to Clamp, Aniso Level to 9, turning off Mip maps, changing import size), but none work reliably. Sometimes one of these MAY work partially, particularly changing the texture import size – this is simply because Unity repacks the texture atlas, and by chance, you get an arrangement that avoids the artefacts. For a while I thought this was a Unity bug (and I honestly still regard it as a ‘usability bug’), but it turns out the right way to make grass textures is buried in the documentation (but not linked from the main section on grass). A texture simply bordered with transparency isn’t enough, and the Alpha Channel of the image needs to be more carefully constructed. Unity’s documentation is Photoshop centric – thankfully there is this guide for how to setup grass textures in the GIMP for those that refuse to get stooged by Adobe’s “Creatively Priced Cloud”. I’m not sure exactly how Unity’s terrain atlases work internally, but other tools like NGUI and SmoothMoves have options to add some padding between subtextures in an atlas – it’s a shame Unity itself doesn’t have this option too, since I presume it would solve the issue.
Another issue which I didn’t get around to solving was detail meshes (shrubbery) that blow in the wind tending to slide along the surface of the terrain rather than swaying. Sometimes, on slopes, they can even disappear under the terrain at one extreme of their oscillation (now when you play the game you’ll spot it immediately :P). It’s highly likely that this is my fault … possibly something to do with bad pivot points on the detail meshes ? To work around this, I replaced some of the particularly wrong looking plants with static non-terrain versions in certain places. These don’t blow in the wind, giving the impression of a much more hardy rigid shrub.
Anyhow, it was fun to play around with creating ‘realistic’ landscapes – it’s not a Unity feature that I expected I would get much use out of, but many of the bells and whistles the come with the engine are clearly designed to streamline production of “first-person in realistic setting” games, and it gives me pause for thought. Certain types of game I would have never attempted to produce in the past are now accessible, so I need to rethink what my next big project will be, after the current ones are done and dusted.
Task queue system for game events
In order to cleanly chain together timed actions with dependencies in the game, I came up with my own little task queue system (eg, Walk to tree, then look at Moon, wait 5 seconds, show text). Without going into all the gorey details, every ‘action’ is created as a subclass of QEvent which has a Run() method, an Action() method (as a coroutine) and a Finished() method. Action() gets overridden by the subclass to carry out a specific action, and calls Finished() when it’s done. QEvent keeps a list of dependencies (dependsOnList, that contains other QEvents that must finish before it begins) and downstream events (the onFinishedList) which it calls Run() on when it is finished. Just to complicate things, I decided to also allow blocking and non-blocking QEvents (chained together like qevent.Then(nextQevent) or qevent.And(parallelQevent) ), so tasks can run in parallel or in series. The topology is defined on how they are chained together with And() and Then().
I also made a helper class (ActionChainer – which acts a bit like a factory) to simplify the syntax for creating and chaining actions – the idea being that even inexperienced users should be able to pick it up and use it for their interactive story. The default chaining mode is Then() (ie blocking actions in series). The result is that I can write something like:
q = ActionChainer.New(); q.DisableLinks(); q.HeadFollows(); q.LookAt("LookForward").And().WalkTo("HillByHouseWaypoint"); q.HeadFree(); q.LookAt("SeaMarker").And().FovTo(60f, 5f); q.EnableLinks(); q.Go();
and mostly things would work as expected. This will probably be part of the first version of uTwine when it’s ready for release – that said, I’m not 100 % happy with it and I wonder if I’d be ultimately better off adopting someone else’s lightweight task queue for C# + Mono + Unity.
One alternative: https://github.com/dkozar/eDriven – has a nice looking Task queue system, eDriven.Core.Tasks. I might try this in the future – it seems smaller and cleaner than my attempt.
Build Report Tool
Finally, something I found very handy for this project after going on an Asset Store binge was the Build Report Tool by @Anomalous Underdog. It gives a nice summary of used and unused assets, and their sizes. This was really useful in tracking down textures that were being imported at high resolution – I was able to reduce these selectively for the Web Player build, and was able to halve the size.
Beyond the technical
This being a postmortem, I should also make some effort to reflect on the game itself. Setting aside all of the programming related aspects of the project – how does it succeed as a game ? As a little tech demo for uTwine, I’m fairly happy with it. At least one of the commenters on GameJolt seemed to like it (once they got it), but it’s destined to be the type of small experience that gets poorly rated on the wilds of game portals, since it will too easily reel in players with the pretty graphics, only to disappoint them when they can’t shoot anything and are forced to read. I played through most of Dear Esther for a second time to remind myself of the details, and I think I did an okay job of capturing the writing style, albeit with a deliberate change in tone. Still, I bet if I read it over in a week I’ll find typos or phrasing that I want to change. The English accent of the narrator in the original really helps though, so if you play Arriving in Damascus, try reading it aloud with an English accent (preferably within earshot of others – bonus points if you’re not from the UK). When Dear Esther was (re)released, it stirred up all the boring old arguments about the definition of a game. Some people might say Arriving in Damascus is more of an interactive visual novel than a game. I did however explicitly include one very lightweight ‘puzzle’, mostly so I had some ammunition to fire back at the not-a-game camp. In my mind, it’s a game – just one that’s very very low on gameyness.
So … a postmortem for LAST MONTHS game ~10 days into this month … I haven’t started my #1GAM game for July yet .. better get cracking !