TRPG in JavaScript 2

[sandbox-demo url=”http://sandbox.irresponsibleart.com/projects/js-trpg-tutorial/part-2/” width=”100%” height=”420″ class=”demo-iframe” github=”https://github.com/aut0poietic/js-trpg-tutorial/tree/master/part-2″]

This is the second post in a series exploring the development of a Turn-based, Tactical Role-Playing Game (TRPG) in the vein of Fire Emblem or Disgaea — Think chess with different pieces and anime thrown in and you’ll have a pretty good idea. If you want the full run-down on what I’m doing or want to view the previous articles in the series, check out the Project Introduction.

At the end of the first post I had a few goals for this stage of development:

  1. Performance Metrics
    I had in mind using some old libraries I’d seen back when I was watching some other developers make the transition from Flash to JavaScript. However, a friend ( Eric J. / SaintJava ) pointed out, Google Chrome has more than sufficient performance tools, both in-browser and in console. I did end up stapling on a quick-and-dirty method for timing a method using console.time(), but for the most part, it’s all browser.
  2. Browser Dimension Aware ( aka Responsive )
    The previous version of the board was a fixed 750 x 400. The new one is not, and can be resized to any dimension up to a maximum of 20 x 10 tiles. The tiles are also now 50px x 50px. This turned out to have some serious implications for handling how things were rendered.
  3. Full-Size Game Board
    Hand-in-hand with the the responsive view, I implemented a larger world. 1000px x 2000px. That required that I build a “cursor” to allow you to scroll the board. It functions using the keyboard for now and you can scroll your view of the world using the up, down, left & right keys.

I spent quite a bit of time thinking about how this should be structured and in doing so came to several decisions. First up, Backbone & jQuery were removed from the project.

  • I had been using jQuery for custom events ( <= IE 9 has issues with native custom event names) and finding the canvas element in the DOM. It may make it’s way back in to the project for loading JSON bundles  (more on this later), but for now, there’s no real point.
  • Likewise, Backbone was a bad fit. Views are built around the idea of using Zepto or jQuery so they were out. Models were far too slow to be used as tile data storage and I had no need to sync them. So it’s out.

I did, however keep Underscore — well Lo-Dash ( same API, better performance ). Primarily, I’m using bind, throttle and extend for now, but I expect some of the other methods to come in handy once I start implementing AI. Hopefully.

But with Backbone out, I had to come up with another means of organizing the codebase. What I used is fairly generic and everything was bound within the primary namespace ‘trpg’. I’ll run em down briefly.

trpg.Utilities

I needed someplace to put a collection of shared functions. For now this only contains the performance timing method I mentioned earlier and a random int method. As the project progresses this is likely to grow.

trpg.TilesArray

Javascript does not support multi-dimensional arrays. Unfortunately, that’s the tool I need to manage a grid — I mean what else is a grid but a 2-d array of tiles. What JavaScript ( and ActionScript, where I learned this little tidbit ) do support is arrays of arrays. It’s sounds like a semantic difference, but in terms of memory management and speed of access the difference can be very real. The TilesArray is one of the single most frequently accessed structures in the game, so I chose to create a custom multi-dimensional array implementation:

trpg.TilesArray = function( ){
    this.NCOLS = 20 ;
    this.NROWS = 40 ;
    this.tiles = [] ;
};
trpg.TilesArray.prototype = {
    get : function( row , col ){
        return this.tiles[ row * this.NCOLS + col ] ;
    },
    set : function( row , col , value ){
        this.tiles[ row * this.NCOLS + col ] = value  ;
    }
};

// USAGE //////////////////////////////////////////////////////////
var cArray = new trpg.TilesArray() ;
cArray.set( 1 , 0, "Foo") ;
cArray.set( 1 , 1 , "Bar" ) ;

console.log( cArray.get(1,0) + " " + cArray.get(1,1) ) ;
// outputs "Foo Bar"

The TilesArray uses a single array and uses an offset location to store the values. In our example up above, we store “Foo” in [1,0] and “Bar” in [1,1]. In reality, “Foo” is stored in [20] and “Bar” in [21].

This is how the C-language handles multi-dimensional arrays and you’d be hard pressed to argue with C’s speed. In terms of our JavaScript implementation, the benefits are fairly minor: The C-style arrays were around 8% faster over 100,000 random writes vs. standard array’s of arrays. It’s not much, but considering every AI in the game will be accessing this structure multiple times a round, every little bit helps.

This structure, at the moment, is just stubbed in. It needs to be abstracted to a generic, reusable class, for one. In addition, I’ll need to add a few methods to extract grid sections as well for use with some of the AI algorithms — we’ll see if it is necessary.

trpg.Gameboard & trpg.Cursor

The Gameboard and Cursor are new in this iteration and fairly simple. The Gameboard has taken over most functions from the original Engine class in the first iteration, now owning the tiles array as well as all rendering of the board itself. The cursor is a simple CreateJS shape.

The Gameboard listens for keyboard events ( currently only arrow keys ) and forwards those on to the cursor, which uses them to move it’s position relative to the Gameboard. The Gameboard then repositions itself so that the cursor is visible on-screen.

trpg.Engine

The Engine class has lost much of it’s previous functionality. In this implementation, it’s little more than the responsive window to the Gameboard, resizing when the window is resized. It does, however, start the whole ball rolling, wrapping all the other classes.

Going Forward

There’s still a ton to do before even being close to playable:

Art: I desperately need character art for this. I’ve spent some time trying to find character images from old games, free games, anything at all and have had no luck at all. I figure I’m going to have to eventually break down and focus on some art. I dread this.

Abstraction, Data Import and Cleanup: The TilesArray needs abstracted as well as use real terrain data rather than random. I’d also like to monkey with the JS structure and move the methods and classes that have not changed out of the main file to better highlight the changes in the project.

Touch Events: I wanted touch events before and they were pushed out. Most of the libraries that support touch events require jQuery so this may mean I need to roll my own or add jQuery back in to the project. Off the top of my head, I need to support tap/double-tap/2-finger tap and swipe.

Characters: It’s time to add some basic character stubs in, render them and make them cursor aware. This means art ( even if it’s just stick-figures ), Class data ( as in character classes ) and character metrics. I’m looking forward to this.

Moveable-Area/Attack-Area and Character Movement: This is the first big milestone. I’ll need to implement fast, multi-level reusable Dijkstra method that returns a c-array of tiles — either to render as the area a character can move or attack in or for use by the AI for calculating their next move. Then there’s the A* implementation in a fast and cyclic version ( fast for calculations, cyclic to show character moving on-screen ).

Things are going fairly well on this project, but they could be better. I could use your feedback on the code in this project. Feel free to leave a comment, drop me a line or shout out on Twitter or G+ if you’d like to help me improve the code.

 

Leave a Reply

Your email address will not be published. Required fields are marked *