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.

 

TRPG in Javascript 1

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

This is the first 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, check out the Project Introduction.

With the first experiment, I stuck with the basics and simply set up a basic EaselJS stage and rendered out a sample of the game board background and grid. You can click the “Download JS” link above and try this yourself.

Let’s run down the code:

var canvas,             
    stage ,
    queue ,
    gridSquare = 25 ;

Here I’m setting up a few basic variables to store references to the canvas and stage elements, as well as the loading queue. I define the default size of tile in the gridSquare variable as 25 pixels.

As I talked about in the introduction, I’ve elected to not use jQuery for performance reasons, so I’m using window.onload rather than $(function(){}).

First, I populate my global variable,  initializing the CreateJS Stage object so that it’s drawing to my main canvas. You can think of the Stage object as a display list or a container of elements you want to render to the canvas.

canvas = document.getElementById( "game" ); // populate the global canvas var
stage = new createjs.Stage( canvas );       // populate the global canvas var
createjs.Ticker.setFPS( 24 );               // set frame rate to 24 FPS
createjs.Ticker.addListener( stage );       // set an event handler to update the stage

The Ticker is an object that is roughly equivalent to a setInterval or requestAnimationFrame loop. In this instance, the Ticker object calls stage.update() 24 times a second (or 24FPS).

The next part of the onload event was new to me, as the last time I worked with EaselJS there was no automated way of handling loading. PreloadJS and the LoadQueue class handle that now:

var manifest = [
    { src:"http://irresponsibleart.com/wp-content/uploads/2013/03/cropped-bg-small.jpg" , id:"gameboard" }
];
queue = new createjs.LoadQueue( false );
queue.addEventListener( "complete" , handleComplete );
queue.loadManifest( manifest );

Here, I’m creating a manifest of elements I want to load. For now it only holds a cropped version of the background using the id of “gameboard” which I’ll use later. I created a new instance of the LoadQueue, passing in false to tell the loader to use tags over XHR requests when possible. Why I’d need do this, I don’t know — it was simply a part of the docs and is something I’ll investigate.

I set a “complete” event handler that will fire when all elements in the manifest have been loaded and then tell the queue to begin loading.

function handleComplete()  {
    var img = queue.getResult( "gameboard" ) ,
        bitmap = new createjs.Bitmap( img );
    bitmap.x = bitmap.y = 0;
    stage.addChild( bitmap );
    drawGrid() ;
}

The handleComplete function is where I do all of the initialization of the game board visuals, demonstrating how drawing and animation work in CreateJS.

The Stage object is a reference to the Adobe Flash stage and serves as a keeper of stuff you want to render, like the game board. So for our little stub of a game, I grab the image data from the queue ( using that “gameboard” id set earlier ) and then creating a CreateJS Bitmap object. After setting the Bitmap’s position to ( 0, 0 ) , I  add it to the stage for rendering.

This is the heart of how EaselJS works: Add an element to the stage, then alter it’s properties. These changes are then drawn to the canvas when stage.update() is called transparently by the Ticker object once every frame (or tick), keeping your animation smooth.

Finally, I call drawGrid() a simple function that renders the grid lines on the page.

function drawGrid(){
    var grid = new createjs.Shape() ;
    grid.graphics.beginFill( createjs.Graphics.getRGB( 255, 255, 255 ) ) ;
    for( var i = gridSquare - 1 ; i < canvas.width ; i += gridSquare ){
        grid.graphics.drawRect( i  , 0 , 1 , canvas.height );
    }
    for( i = gridSquare - 1 ; i < canvas.height ; i += gridSquare ){
        grid.graphics.drawRect( 0  , i , canvas.width , 1 );
    }
    grid.alpha = 0.4 ;
    stage.addChild( grid ) ;
}

If you’ve done any pixel drawing in another language, this should be very familiar to you. Briefly, I create a new Shape object and in the first loop draw my vertical lines starting at gridSquare – 1 ( that’s 24px, in this instance),  and then one line every gridSquare pixels (25px). The next loop does the same thing, only horizontally. Then I set the transparency of the grid to 40% (0.4) so that the lines are simply a ghost on the game board. Add the shape to the stage, and the ticker will handle the rendering.

So at this point I have a fairly good base for building the game. I do see some things that will need to be improved.

  • First and foremost, I need to build in some methods for giving me performance metrics. It doesn’t have to be anything comprehensive, just something that says “this many milliseconds has expired.” I have to have some way to evaluate the performance of each feature as I add it to the game.
  • Next, I need to build this so it’s canvas dimension agnostic. If you’re viewing this on a smaller screen, you’ll notice that the canvas overlaps the right menu or continues right off screen. Some of this is to be expected, especially if you’re looking at this on a cell phone. But there should be an easy way of dealing with this.
  • The game board I’m using here is cropped to the size of the canvas. I’ve got a massive game board to move around on, need to build this so that the canvas serves as a view port and you can scroll.
  • It’s early yet, but I need to allow for touch events, rather than just keyboard and mouse. I’ll consider multi-touch at a MUCH later date.
  • My tools prevented me from using Backbone in this initial build so I couldn’t evaluate whether it was appropriate for a canvas/EaselJS project. I enjoy how it can be used to make my code easier to work with as well as it’s collection & data classes. Still, there’s nothing in it that I can’t live without.
  • The preloading manifest likely needs to be broken out into a separate method — it’ll get a lot more use in future versions of this experiment.

I must also mention that the background image is a cropped section from the work of Cartographer’s Guild member Pasis. The work is used with only implied (non-commercial, attribution) permission from the original post, so this may come down if Pasis isn’t okay with my use of his work. We’ll find out if/when I get in touch with him.

Next: Part 2 – OOP and the Gameboard & Cursor

 

TRPG in Javascript

Articles in the series:

  1. Getting Comfortable with CreateJS
  2. OOP and the Gameboard & Cursor

I love Turn-based Tactical Role Playing Games — that is TRPG’s — especially those in the vein of Fire Emblem. I enjoy how simple it is to play. The mechanics are easy to grasp: You have units, they have a movement rate, they have a fixed or ranged attack. Simple.

You can think of them like a game of chess with more personalized pieces. Each piece has a story and different capabilities. Like chess, the individual pieces are simple, but taken together create a game with multiple, layered strategies.

The medium lends itself to telling stories between and around the battles, even hiding slivers of the story in the battle itself, handing them out in small nuggets when the player accomplishes certain goals.

I’ve always wanted to build one of these games. Honestly, it was my wife who gave me the idea — a way for us to bond over a shared project. What could go wrong?

This post, and the ones to follow, represent my experimentation with building a simple TRPG. I don’t expect an actual AAA game to be produced from my random mutterings. Rather, I expect to develop a few new skills and a bit of knowledge in using HTML Canvas and the toys that go along with it.

I plan to use is CreateJS  which includes:

  • EaselJS  for flash-like canvas manipulation
  • SoundJS for managing and playing sounds in HTML
  • TweenJS for animations ( if needed )
  • PreloadJS for loading and managing assets ( if needed )

I’m also considering using Backbone and Underscore / Lo-Dash — though I understand that any of these tools may be rejected simply because of performance. What you may notice missing is jQuery. My early experiments found that it was far too large of a performance hit to use it in any intense canvas rendering. YMMV.

The experiments themselves will be built using a custom plugin I’m calling “Sandbox” — basically a codepen-like piece of software that runs within WordPress and stores all files locally. I may or may not share the plugin, depending on if there’s any interest.

Which brings me to the final thought of this little introduction.

Calling these articles “Tutorials” is overstating it. By miles. These are my blind wanderings and clumsy fumbling around the art and technology of game development.   All the examples are open source and covered under the MIT license ( which will accompany the JS files ). That means you can use them however you want. However, if you’re able, I would appreciate a link or a shout-out — if only so I can justify to my wife the time spent on these little experiments.

Thanks for reading and I hope you find these experiments useful.