Wednesday, December 20, 2017

Making Evil Gnome’s Revenge

Before I get to my game overview a brief update on my 2600 project. The assembler is functional now and while I do want to add more directives to it, will start on implementing the 6502 emulation adding new directives to the assembler as needed. I have a number of articles on my 2600 assembler ready and will be posting them next year. Now back to the evil gnome.

Evil Gnome’s Revenge was my 2012 game jam entry for Ludum Dare #25 which had the theme “You are the Villain.” At the time I really didn’t want to go down any of the dark paths that I had thought of and having had created both Santa’s Search and Santa’s Snowball years earlier I thought this would be a light-hearted way of making the player the villain without having them do anything outrageous. I can’t say that the herding concept was original as there are a number of games that have a similar mechanism with Munch’s Oddysee probably being the biggest influence.

The development time on this port was pretty abysmal as I made the cardinal mistake of working on it while watching TV. While I know that the human brain is not designed for multitasking, the lackluster performance I had while coding this clearly emphasizes how poor we humans are. The strange thing is that I normally have podcasts or other background noise playing so I had expected to have my normal development speed. When coding, however, I tend to tune out what I am listening to while the TV tended to take most of my attention as I got caught up with my shows before losing the contents of my PVR. The big lesson being that you shouldn’t let your recorded backlog build up that much. Coding is best done without distractions could also be considered a lesson if I didn’t already know that.

The first surprise was that the game was created using the Starling library. This is a molehill library that takes advantage of the 3D capabilities that later versions of the Flash player added.  When I saw the starling imports I thought that perhaps I should consider StageGL, the WebGL based renderer that is in testing now but will eventually replace the stage.js library.  The map for the game, which is procedurally generated, is 64x64 with each tile being a movie clip that goes to the appropriate frame to display the tile at that location. Once set, however, the tiles do not change. Having 4096 sprites on the screen is probably not very good for performance, but by creating a 2048x2048 pixel cache then there is only one background image that the renderer is tracking giving the game 60 fps performance on decent machines. It is easy to cache sprites, as the following code shows.

// for speed reasons, cache the tilemap
this.tileMap.cache(0,0, 64*32, 64*32);

One of the substantial changes that I am making to all the games that I am porting is to make sure that the games work with touch interfaces. Touch input meant rewriting how the player moves as the original game used cursor or WASD for movement. The obvious solution was to simply have the player click to where they wanted to move to and head in that direction. The obstacles in the map, however, made this a bit tricky. A path-finding algorithm could have been used but I didn’t feel like writing one so I opted for a simple slide along the object system. This simply checks to see if the player is stuck and if so tries moving on just one of the axis. While this method still lets the player get stuck, most of the time the player will move around the obstacle.

if (this.canEnterTile(targX, targY, mover) == false) {
if (this.canEnterTile(targX, mover.worldY, mover) == false) {
if (this.canEnterTile(mover.worldX, targY, mover) == false) {
// we are stuck!
} else {
mover.worldY = targY;
}
} else {
mover.worldX = targX;
}
} else {
mover.worldX = targX;
mover.worldY = targY;
}

This is where things got strange. The game seemed to work fine with the change until the mouse was moved at which point the game stalled for a few seconds. Out of curiosity, I removed all the tiles from the tilemap image replacing It with a 2048x2048 shape. This solved the delay problem meaning that the problem was with how create.js handles clicking. All the tiles are being checked with a pixel accurate test to see if the tile is affected by the mouse event. The solution was to not have the game screen process the mouse event but grab the mouse events at the higher stage level then manually determine which tile was clicked on. When you are dealing with thousands of objects, different techniques must be used.

var clickX = e.stageX
var clickY = e.stageY;
this.gnome.targetX = (clickX - this.tileMap.x) / 32;
this.gnome.targetY = (clickY - this.tileMap.y) / 32;

With the major issues out of the way, this was not a difficult game to port. This only leaves the final game in the series which will be covered next week and then we can get back to my 2600 emulator.

No comments:

Post a Comment