Sunday, 11 September 2011

A New Direction

It's fair to say that development on XAGE has slowed in the last eighteen months. This has mostly been unavoidable due to external factors, though there has also been a technical culprit - a thorny design issue I'd been struggling to overcome.

XAGEScript, which previously powered the engine, was XML-based and completely crafted from scratch. I'm quite proud of how far I took it - essentially it became its own bona fide programming language, supporting standard programming concepts like loops, lists, expressions and a call stack.

The trouble was, the more I focused on AGS conversions, the greater difficulty I had in adding additional complexity, not just within the script itself but the editor and the engine too. The more hastily functionality was bolted on the messier and more unwieldy it became to maintain. A hack built upon a fudge upon a hack soon results in an unpleasant programming experience. When your free time is limited to the late evenings, you cannot afford to suffer any impediments to your motivation.

Fortunately a workable solution has presented itself. For a while I have been been toying with the idea of abandoning XAGEScript in favour of using C# as a pure scripting language. This was especially attractive as AGS already uses a C-style syntax and so would aid any conversion substantially. However, the plan was not without its sticking points:
  1. My original tests resulted in a large amount of garbage being generated. This is the bane of all Xna developers as it kills performance on Xbox and WP7.
  2. With a hand-built scripting system, iterating through each command was easy and therefore blocking a script (to, say, wait for a character to speak a line of dialogue) is reasonably trivial. Doing the same in a raw C# script would require some horrendously complex & difficult to debug multi-threaded solution.
Regarding the first issue, after some experimenting with the Remote Performance Moniter I discovered a means of calling methods in external DLLs without generating additional garbage, including on the Xbox.

Resolving the second issue has taken much more time, but has ultimately proved much easier than resorting to running multiple threads. The C# yield keyword is such a strange beast that it took some time to wrap my head around it. Essentially it allows us to iterate through a block of code in the same way we would an array or list. Using yield return we can indicate whether a script is blocked and provide a mechanism for resuming it at a later time.

However using this keyword does somewhat complicate the code, so with the aid of the NRefactory Library I've added an additional step which automatically copies & updates your C# script to handle blocking, and therefore be usable within the XAGE engine:


The upshot is that it will be a TON easier for me to add new functionality - all I need to do is provide an interface and then implement it in the engine. Previously I'd have to laboriously built a new class for each function and then wrestle with the editor code to provide a means for users to make their changes.

It is a shame that in dropping XAGEScript we lose some ease-of-use and perks of solely using the Editor for scripting (for example, clicking on a background to very quickly set up a series of sequential Walk & Talk actions), but I'm convinced the benefits are absolutely worth it. If you are familiar with any flavours of Visual Studio Express 2010 then you'll know they're excellent (and free) tools for writing code, plus C# and .NET will provide game developers with a great many more options and flexibility. Just being able to step through scripts one line at a time using the debugger is a tremendous boost to productivity.

All the above is still experimental and is subject to ongoing work, although I do have a working prototype. Alongside plugging the new scripting system into the XAGE Engine, there remain a few outstanding questions I've yet to tackle:
  1. Whether loading the script .dll at runtime will be supported on all platforms (iPhone & Android specifically).
  2. Whether the Iterators for the blockable scripts can be serialised in a satisfactory manner (i.e. loading and saving).
  3. How exactly performance will compare against XAGEScript (mostly likely it will far outstrip it, though I've not yet tested this explicitly).

No comments: