BLOG

1 | 2 | 3

A Sidetrack into Grid-Based First-Person Dungeon Crawling

Posted November 26, 2021

Well, I had intended to get the rest of the pathfinding logic squared away, but I got kind of bored working on that and, on a whim, decided to port my first-person dungeon crawler engine into Xist instead. Apologies to anyone who was really gung-ho about me continuing work on my strategy game project (I'll get back to it), but my productive output is better if I follow my creative whims rather than force myself to work on things when I'm not in the mood.

The reason I stopped working on the dungeon crawler project was different from the strategy game (where I eventually got mired in an endless swamp of cirtuitous debugging); in the case of the dungeon crawler, the engine was 95% complete and there were no debugging or maintenance difficulties -- I just completely lost interest in the scenario I had designed for it, and I came to really dislike the battle system I had developed.

Screenshot of dungeon crawler game
A screenshot of the current state of the dungeon crawler engine.

Because it was essentially already complete, porting the dungeon crawler engine into Xist was a pretty trivial affair. I had also already been developing a text-based prototype for alternate game mechanics for a dungeon crawler RPG which I was also able to port in. I have a lot more confidence in these game mechanics and scenario idea. Just as my strategy game project is based on my favorite RTS games (Command & Conquer and Red Alert), the new mechanics and scenario for the dungeon crawler are (very loosely) based on another retro game I have great fondness for -- an obscure gem called Warriors of the Eternal Sun, funnily enough also made by Westwood Studios (called Westwood Associates at the time). Those guys made some really amazing games in the 90s. I think the marriage of the dungeon crawler engine with roughly WotES-like mechanics is going to make for an excellent game project.

(For the record, WotES was based on the oldschool B/X (Basic/Expert) D&D ruleset, so this dungeon crawler project is going to follow something similar, but with many modernizations and improvements without breaking the B/X "feel" -- plus a variety of changes just for the sake of not violating copyright, as I might actually want to sell this game if I complete it.)

Between the functionality provided by Xist, the dungeon crawler engine, and my quasi-WotES-mechanics prototype code, a great deal of work is already completed. I just need to build the menu system (always a laborious and tedious task where RPGs are concerned, although Xist's GUI framework will make it a lot less onerous) and then build the new battle system, but most of the underlying logic for the latter is already in place; it will mostly just be a matter of programming in the user interface and the multimedia component since the prototype was text-based. Once that's done, the dungeon crawler rebuild will be ready to go and I can jump right into the fun part of game development -- content creation, writing the scenario, and creating levels.

I'll probably be working on this in the coming weeks, but if not, that probably means I jumped back into working on pathfinding for the strategy engine instead. Either way, more soon, hopefully.

Cutscene Scripting System

Posted November 16, 2021

As I alluded to last post, I switched gears to develop the cutscene scripting system for Xist so I could make custom briefings for my Red Alert mod, Red Alert Alternative.. Mission accomplished, and the briefings exist independently of the mod. I've deployed them as a Windows executable (I might add a Linux executable as well soon), so if you have a Windows computer, you can head on over to the Red Alert Alternative page to download the briefings and see the cutscene system in action.

Screenshot of VN system

The mod's briefings actually only show a fraction of the cutscene scripting engine's capabilities, though, because they're non-interactive. The cutscene engine is internally called the VN system, short for Visual Novel, because it is capable of supporting full Visual Novel style games. Its features include:

Internally, the VN system is implemented as a series of VNCommand objects and labels to act as jump targets. Conceptually, each VNCommand is basically just a function pointer (in Java, this is implemented as an interface with a callback method), and an arbitrary set of arguments, including one Object argument (the Java equivalent of a void pointer). The cutscene object maintains an index to the current VNCommand. If the VN_MODE flag is on, then on each iteration of program execution, the cutscene object executes the current VNCommand's function pointer and increments the script index -- unless it's in a wait state (waiting for player input or counting down a wait timer), in which case it does nothing until the wait state is lifted.

The way the cutscene script is populated is it reads a definition file (see my first dev blog post for more information on Xist definition files) and reads in each command and its arguments, creating a VNCommand object, assigning an anonymous function to its function pointer depending on the command, and populating its arguments appropriately. Here's an example of a series of script commands:

<fx>
Sprite: port_white_noise
X: 272
Y: 15
Width: 256
Height: 256

<alter_sprite>
ID: BriefingPhoto
Remove: -

<sprite>
ID: CenterScreen
Base: port_screen
X: 272
Y: 15
Width: 256
Height: 256

<text>
X: 165
Y: 312
Font: Roboto12
Color: 0 255 0
Line: I’m getting distress calls across the board. Our forces are under attack everywhere.
Line: It... it looks really bad. Sir, what should we do?

<alter_sprite>
ID: Sierra
TalkOn: 0

<await_click>
-: -

I suspect most devs would balk at having to create files like that by hand, so if I ever wanted to distribute Xist for public use, I would probably want to create some kind of interface for making these scripts. But personally, I don't mind working with files like that by hand, so I just created the scripts for the Red Alert Alternative briefings using a text editor.

So that's another feature done. Now, back to the pathfinding, and after that, networking capability. Then, I think the initial version of Xist will be done and I can finally use it as a springboard to start rebuilding my strategy game proper.

Pathfinding

Posted November 3, 2021

As I wrote at the end of my previous post, the next puzzle I'm tackling for Xist is hyper-performant pathfinding. The basic issue of pathfinding is simple enough: given a start position, an intended destination, and a map, find a way to get from the start to the destination, preferably the shortest route if possible. If you don't need real-time performance, this isn't a particularly difficult problem. The problem becomes much harder if you need to find a good path through complex terrain fast.

Exploring a game map to find a path through it, such as when units in a strategy game need to intelligently obey the human player's movement orders, can be quite slow if not done properly. In the worst-case scenario, you need to explore every single discrete space on the map (I'll call those spaces "cells") in order to reach your destination, which even on a modest-sized 128x128-cell map means exploring up to 16,384 cells every time a unit moves anywhere. If your game is real-time and you have units constantly moving all over the place, this is going to be unacceptably slow. And that's just for finding any path to the destination. If you want to guarantee that you'll find the shortest path, or even usually find an almost-shortest path, the problem becomes even more complex and takes even longer. I've applied several techniques to overcome this problem, from simple to fairly advanced.

One relatively simple optimization is detecting non-contiguous regions (or "islands") in your map and bailing out immediately if a unit is told to move from one island to another -- otherwise it will waste precious CPU time doing an exhaustive search trying to find the unreachable destination before it figures out it can't get there. To identify the islands, which I internally call "zones," I use the following procedure:

  1. Initialize each cell with a zone of -1.
  2. Go through each cell in the map, starting from the northwestern one. Keep a zone counter, starting from zero.
  3. Perform an iterative (because recursion is slow and therefore sucks) flood fill from that cell, marking each flood-filled cell with the current zone.
  4. Increment the zone counter.
  5. Continue scanning the map until you reach the last cell and terminate, or find a cell that has not been assigned a zone yet (has a zone value of -1).
  6. Back to step 3 and repeat.

Then, whenever a unit tries to move, just check the zone of its current cell and the zone of its destination cell. If they're different, don't even try to path-find to the destination.

That's a good first step, but pathfinding will still be slow when moving to destinations that lie within the same zone. Another good optimization is to avoid having to scan every cell on the map when we try to find a path across it. There are many techniques to accomplish this. One way is to precompute paths across the map and have units follow those paths that have already been determined, but this is rather limiting. Another common approach is to express the map at a second, coarser level of granularity for pathfinding purposes. There are different ways of accomplishing this. I went with a navigational mesh; specifically a simplified form of this technique since my maps are just two-dimensional grids.

The idea of a navigational mesh is that you lay a bunch of shapes, which I call navigational nodes or NavNodes, over your map. One important thing about these NavNodes is that they have to be convex -- this property means that you can just go in a straight line from any part of that node to any other part of that node. You lay these nodes over your map, making each one as big as possible without violating the convex restriction. Then, when units find a path across the map, they actually just find a way through the nodes, which takes far less time because there aren't nearly as many nodes as there are cells. Pathfinding within each shape is trivial since you can just move in a straight line anywhere across it.

So, I augmented my map editor UI with the ability to place rectangles for a nav mesh. It can also automatically generate them and often does a good job, but certain types of terrain make it come up with a mesh pattern that isn't the best for pathfinding, so a better approach is for the human editor to manually place NavNodes in the major parts of the map and then let the auto-generator fill in all the nooks and crannies to save time. When you save the map, it automatically determines the connections between the nodes (which ones are adjacent to each other) as well as the distance from the center of each node to the center of all the nodes it's connected to (called the edge weight), important for pathfinding purposes. Here's an example; the NavNodes are shown as translucent orange rectangles:

Screenshot of navigational nodes

Next is the pathfinding algorithm itself. Technically, now we need multiple algorithms: one for finding a path through the NavNodes; one for traversing across a NavNode (that one will be trivial, since it's just "point and go" rather than actually having to find a path); and one for finding a path through individual map cells when the preceding methods fail. First I focused on the NavNode pathing algorithm.

For this, I decided to use a modified version of the A* (A-star) algorithm. It lacks one important feature of vanilla A*; namely, once it has already added a node to a particular path, it can't go back and switch that node to use a different path. This reduces the algorithm's time complexity, making it run faster, at the expense of the algorithm not being guaranteed to always find the shortest path. This is a tradeoff I'm willing to make, since according to my testing it usually finds the shortest path anyway.

The way the algorithm works, in a nutshell, is as follows:

  1. Add the start node to the list of nodes to consider. Make the start node the current node being considered. Then do the following in a loop:
  2. If the node under consideration is the destination, stop searching and work backwards to the start to create the path.
  3. Otherwise, get every adjacent node that we haven't already considered. Add it to the list of nodes to consider and do two things:
    1. Make the current node the "parent" of the adjacent node. This is how we're able to work backwards to create the path in step 2.
    2. Compute the "F value" of the adjacent node as the distance required to reach the current node, plus the distance from the current node to the adjacent node, plus an estimate (this is the previously mentioned "heuristic") of the remaining distance, simply computed as the distance from the adjacent node to the destination "as the crow flies."
  4. Add the current node to the "closed list," meaning a list of nodes we've already looked at and won't need to look at again.
  5. Grab the node with the lowest F value and make it the node currently under consideration. This basically means "get the node that we think will probably take us closer to our destination than any of the other nodes we're considering." This is what distinguishes A* from a simple breadth-first search and (hopefully) makes it more efficient: instead of spreading out evenly in all directions, our search space grows toward the destination.
  6. Go back to step 2 and repeat.

The implementation details of A* are important to make it live up to its promises of efficiency. In particular, you don't want your open and closed lists to be simple arrays, otherwise it's a linear [O(n)]-time operation every single time you want to check if you've already visited a particular node. Instead, I use binary search trees. Now, absurdly, Java doesn't have built-in tree structures (I tried a TreeSet implementation of Sets but just couldn't get it to work as desired) so I actually had to implement this myself; it felt like being back in a Data Structures class. I didn't get super-fancy and make it a self-balancing AVL or Red-Black tree, so technically it still has a worst-case linear time complexity, but in practice all relevant operations (search, insert, and remove) will be closer to logarithmic [O(log n)] time, which is extremely good. (If the pathfinding still proved to be too slow, I could go back and turn the BST into a self-balancing tree to guarantee logarithmic time complexity, but I'm not going to go to that effort unless the data structure proves itself to be a bottleneck).

Since I removed the "re-check already-visited nodes to see if we've found a shorter path through them" property of A*, the time complexity of my modified algorithm becomes:

the time complexity is linear times logarithmic, or [n log n], which is quite good, especially when we already drastically reduced the size of the search space using NavNodes as explained above.

I created a medium-sized map with realistically complex terrain and wrote a test to have a unit pathfind its way to all four corners of the map using the NavNodes and this algorithm. It completes its pathfinding in under 3 milliseconds -- quite sufficient for real-time use; a player wouldn't even notice that in a game running at 60 fps.

Now, there's plenty more work yet to be done. I need to implement the other pathfinding algorithms, and then take into consideration the issues that arise when you're not just dealing with one unit moving across a static map, but a whole host of units moving at once and potentially getting in each other's way. I have two tricks in mind to keep the efficiency at an acceptable level:

That still leaves the issue of units getting in each other's way, but I've dealt with that issue in the past and I find that some relatively simple rules result in perfectly acceptable behavior with respect to this problem. It's really not an especially thorny issue; I get the idea that a lot of game designers overthink it. But I'll save that discussion for another post.

Before I finish the pathfinding, though, I'm actually going to switch gears and work on the system for rendering in-game cutscenes. Why the sudden shift? Because I'm likely going to be adding more detailed briefings to my Red Alert Alternative campaign in the near future and a fully functional cutscene system will help expedite that effort.

More soon, hopefully!

Environmental effects, fleshing out the map editor, Players and Entities

Posted October 27, 2021

Progress on Xist continues to be satisfactory. I've enabled environmental effects, including rain, lightning, snow, distortion waves, a "virtual reality wireframe" effect, and ambient lighting. That didn't take long because it was mostly a copy/paste job to port the functionality from previous projects, then it was just a matter of adding the UI to the map editor to edit the environment parameters. I was too pressed for time to record video, but I did take some screenshots.

Screenshots of environmental effects

Rain is simple -- just seed some random points across the screen, update their X and Y positions every frame, and draw a slanted gray line at each rain position. When a raindrop falls off the bottom of the screen, reposition it at the top. Snow is similar, except each snowflake is assigned a random speed and coefficient for following a sine wave as it falls down the screen, so the flakes fall at different speeds and amplitudes as they waft down the screen. This creates a very natural-looking effect for "lazy" falling snow, but wouldn't be appropriate for a raging blizzard.

The wave distortion is maybe my favorite effect -- it runs the pixels of the entire screen buffer (prior to rendering UI elements) through a sine wave function. It makes a nice "heat ripple" effect and would also be appropriate for rendering underwater scenes. The "VR wireframe" just moves two points across the map and draws colored grids with increasing translucence in a gradient effect from those points on the vertical and horizontal axes to create a neat "strobing wireframe" look, suitable for if you're rendering a level that's supposed to take place in a VR environment. Finally, the ambient lighting is the simplest of all -- that just overlays a translucent rectangle in the chosen color over the scene, tinging everything with whatever color light you want.

From there it was just a matter of fleshing out remaining functionality in the map editor by implementing the New, Save, and Load buttons, which included the implementation of reusable confirmation and file dialogs. There are still a couple of (major) buttons that remain unimplemented -- the placement of game Actors, and editing navigational meshes -- pending implementation of those features. Actually, Actors came next (along with Players and Entities), but I'm saving implementing that button for after navigation.

The Player class, at present, is mostly just a collection of instance variables. The few noteworthy points about it are:

Next are the Entity and Actor classes, which are generic (and extensible) ways of representing dynamic things in the game world. Actors are subclasses of Entities; what distinguishes them is that they "exist" in space in the game world so they have positional, size, and movement data -- including movement costs for different terrain types -- while Entities, which are more abstract, do not. What Entities (and by extension, Actors) possess is:

A PropertySet is basically a way of assigning additional variables to Entities and Actors without having to do so in code. PropertySets have maps of strings (variable names) to integers, floats, and strings. In this way, the game designer can extend Entities and Actors with additional variables through definition files. Of course, adding behavior to these classes will have to be done in code, but PropertySets nonetheless supply a convenient way of allowing the user to define additional data through external files and automatically be able to save, load, and (later) transmit that data without needing to write any additional code.

Next up will be one of the most algorithmically complex parts of the Xist project -- built-in nearly-optimal pathfinding that's performant enough to be used by large numbers of Actors simultaneously in real time. Optimal pathfinding is easy to implement in a turn-based game (just use a basic A* algorithm) because performance isn't really an issue, but it becomes a much tricker issue when real-time performance is important. I believe I have a plan to make this possible, but I'll save the detailed discussion of that for next post.

On creating a game framework

Posted October 23, 2021

After a bit of a hiatus, I've resumed my hobby game dev activities, and with that, I've decided to revive my defunct development blog. At any rate, I'll probably dedicate it primarily to development, unless another, really interesting topic presents itself.

Anyway, like many software developers, I like to create video games as a hobby. However, unlike some of my other creative endeavors -- such as finishing and publishing several novels -- my track record with finishing video game projects is not great. I've had some projects that I made pretty significant progress on and which held a lot of promise, but I've never been able to take any of my really good video game projects to completion, only a couple of minor, frankly rather lackluster ones.

I'd like to change that. I have at least two game projects -- a strategy game and a first-person grid-based dungeon crawler -- that I'd like to actually finish. And, I'm sure I could come up with many other ideas as well.

Naturally, there are a lot of elements that recur between my game projects, like a sprite system, pathfinding, menus, cutscene system, and so on. I don't reinvent the wheel every time; I copy and adapt relevant code from old projects to new ones whenever I can. Even so, I've never been particularly organized about it; the effort has always been rather haphazard and slipshod. Also, one of the banes of my game projects has been excessive reliance on rapid prototyping, and not enough focus on solid, maintainable design in my code.

I believe I have a solution to address all of these problems at once. Now that I'm resuming my hobby programming activities (again), I've decided that the first thing I'm going to do is consolidate all of the functionality that gets used across multiple games into a clean, elegant design that's easy to maintain, debug, and expand with additional functionality. Then, instead of haphazardly copy-pasting and modifying code from previous projects, creating Frankencode, anytime I want to start a new project I can clone this codebase, get tons of preexisting functionality right out of the gate, and hit the ground running with code that's already well-designed and easy to use.

In far fewer words, what I want to do is create my own game framework/game engine. The effort is already off to a good start. And any good framework needs a cool logo, so I slapped one together. I went for a "simple but elegant" look:

Exist Logo

The framework's name is Xist, pronounced "Exist." There's no meaning behind the name other than that it sounds and looks cool.

So, what functionality does Xist have? Well, my needs are based on the fact that I use the Processing framework to create my games. Processing is essentially a library of Java functions for conveniently doing various graphical manipulations and painlessly utilizing OpenGL, which is crucial for making performant real-time games, even primitive retro-style ones as is my style. Processing also has push-button deployment where it bundles up your executable with a self-contained JVM so it makes cross-platform distribution a snap. Basically, although I don't think many people use it for this purpose, Processing actually has a lot of features that make it really useful for hobby game development -- particularly retro-style games (it would not be appropriate if you're going for a hyper-advanced AAA title look).

There are, however, many things that Processing lacks, and these are the gaps I'm filling in with Xist. Foremost among these is a sprite system; in other words, built-in functionality for animated images, crucial for 2D games. It's not too difficult to create a reasonable sprite system if you already have a framework with convenient image manipulation functions (as Processing does). Basically, you need an interface for reading sprite sheets (like the one below), splitting them off into separate frames, setting the timing on those frames, and finally, a simple next_frame function to fetch the next frame in the animation. Once I implemented a good sprite system, I copied it ad nauseum across numerous game projects, so for Xist it was a pretty simple matter to import it with only some minor enhancements.

Sample Spritesheet
An example of a sprite sheet (an animated billboard) from my strategy game.

With one exception; namely, in previous projects I had always hard-coded loading and processing the sprite sheets in some kind of initialize_sprite function. However, I've come to dislike cluttering my source with loading and initialization, and for some reason, I find it more enjoyable to define properties of game entities using external configuration files rather than hard-coding them. So, I created a generic "definition file" (as it's called in Xist lingo) format, which is simple yet versatile enough for describing just about any kind of game entity you can imagine (but like XML or JSON, which accomplish the same purpose, it would not be appropriate for defining behavior):

<SectionName>
AnIndex: some value
AnotherIndex: another value
etc.

As a concrete example...

<spritesheet>
name: test_tile_tree
graphic: TestTileSheet
width: 32
height: 32
rows: 5
columns: 4
frames: 1
skip: 2

The Definition class parses files in this format and hands them off, neatly divided into sections and index/value pairs, to other classes to parse as they see fit. With this format defined, writing parsers to translate configuration files into in-memory game data is a snap. I adapted sprites to be defined using Xist definition files rather than hard-coded as they have been in the past. I'm already finding that separating the game logic from files that purely contain data (which changes from one game to the next in any event) to be extremely useful for cleaning and decluttering the code.

Another important technique with sprite-based games (and even some 3D ones) is palette swapping -- using the same image file and programmatically changing the colors. Although this is most infamously used for the "lazy" purpose of expressing different enemies, terrain, items, etc., using the same image and just changing the colors, to some gamers this is actually a fond aspect of retro games, and it also serves more important purposes -- like distinguishing different players' factions in strategy games. So I also implemented built-in support for palette swapping. The game designer can specify palette swap definition files which provide a list of colors that act as "placeholder" colors, and then any number of other lists of colors that the placeholder colors can be swapped with. Within the code, it performs a palette swap by loading all the pixels in an image, checking each one's color to see if it's "swappable," and then replacing it with the corresponding pixel from the specified color set.

Related to sprites, another visual entity I've used in some past game projects is voxels. Nowadays, when people hear "voxel," they think of Minecraft. But I've never played Minecraft, am not interested in it, and frankly hate the way it looks. 😅 My experience with voxels long predates Minecraft and actually comes from an old strategy game called Tiberian Sun. Although Tiberian Sun was rendered from a two-dimensional isometric perspective, the developers used voxels at a far smaller scale than Minecraft to render the in-game vehicles three-dimensionally, with a technique that's very different from the more traditional polygons.

Screenshot of Tiberian Sun
A screenshot from Command & Conquer: Tiberian Sun.

Voxel stands for "volume pixel" and a voxel model is basically just a three-dimensional image file. The vehicles in Tiberian Sun were rendered by layering multiple images on top of each other, and I've replicated this technique to create voxels of my own for similar purposes. I added built-in support to Xist for this as well. If you've never seen voxels used in this manner before, you might be surprised by how three-dimensional they can look and how smoothly they rotate. Here's a very simplistic example using a very basic two-color voxel definition with no shading or lighting effects applied, and it still looks (in my opinion) impressively 3D, so you can imagine how nice this looks with higher-fidelity models:

A sample voxel model rotating

With sprites and definition files done, the next task I turned to is creating a good GUI framework. Processing has no built-in facility for handling menus and other UI elements; there are libraries you can download, but I've found that they don't suit my needs. Frankly, aside from building layouts with HTML and CSS which I actually kind of enjoy because I'm weird, I've never found a GUI library that I actually like. The most prominent examples I've used are Qt for C++, Swing for Java, and JavaFX for Java, and I've hated them all. 😅

So, this was my opportunity to make my own GUI framework. I'd made an attempt while iterating on my strategy game, but that ended up being kind of a clunky mess. (It's not an easy problem to solve.) I used the lessons learned from that experience to build a much better framework this time, and so far (as I use it to create a built-in map editor), I'm very happy with the results. The Xist GUI framework is very simple and basic, yet this is its strength. Instead of a bazillion different component types -- windows, panels, checkboxes, dropdowns, comboxes, and whatever else -- there's just one, GuiItems. GuiItems have many different properties, and like many things in Xist, are defined through definition files. Their properties are versatile enough that by setting them properly, you can create GuiItems that act as any kind of component you could want. Each GuiItem can also contain subitems (for example, a window would contain all of its associated buttons and labels as subitems) and can also turn on a scroll flag to make it act as a scroll pane, dropdown box, or any similar component that contains a scrollable list of other components.

GuiItems are stored in a map (AKA dictionary, AKA associative array, AKA hash, depending on the flavor of language -- they're maps in Java) and you can place one on the screen simply by referencing its name and calling its open method. Xist maintains a list of open GuiItems for displaying them and responding to user input. The definition for a GuiItem can give it a callback (function that's invoked when a user clicks on it), but the actual callback implementation is done in code rather than the definition file. The number of different actions that you might want performed when a GuiItem is clicked is so vast that it was easier to defer that to the source code rather than try to create some kind of custom scripting language for it.

In addition to the names which serve as their references in the GuiItem map, you can give GuiItems IDs, and multiple GuiItems can have the same ID, which is useful when you want to perform the same action on multiple open GuiItems (such as closing them); a convenience function is provided for getting all open GuiItems that share the same ID. I think it's about as simple a design as you can get while covering all the important bases for a GUI framework, and so far, as I'm using it to build the UI for the built-in map editor, it's working very well. It's really taken the pain out of building the UI, which used to be one of the most tedious parts of my game projects.

With the GUI framework in good shape, I turned to the next major item, which is also serving as a good trial run for the GUI framework: a built-in map editor. Many 2D games, including most of my game projects, are tile-based, meaning the game areas basically consist of two-dimensional grids of sprites. To support this, Xist includes Tile and TileMap classes, as well as CompositeTiles which are just groupings of individual tiles for convenience when building maps. Tiles are fundamentally pretty simple, consisting of a graphic and a terrain type. The terrain types are user-defined so that the game creator can define terrain types and how game Actors (yet to be implemented) interact with them in whatever way is most appropriate to the game. Tiles can consist of multiple layers so that, for example, you can place trees on top of ground, be able to draw actors behind tall terrain features but on top of the ground, etc. Like most other things, these are defined through definition files.

One thing I wanted to improve from previous projects was how I save maps to disk. The game designer can define the maximum dimensions of maps; it defaults to 128 x 128 tiles. Assuming a two-layered map and that each layer includes a reference to its associated sprite and its terrain type (both defined as a short, or two bytes), naively writing all of the map data verbatim would take up 131,072 bytes (128 KB) in binary format; several times as much if converted to printable ASCII or Unicode. That might not seem like a big deal, but I also want other parts of these map files to be human-editable, and having a giant pile of numbers in the middle of the file (potentially also slowing whatever text editor you're using) is an inconvenience. So, I implemented an algorithm to convert all the tile map data to its consituent bytes, compress them, and then base64-encode them so they can be written to a text file without a bunch of unprintable garbage characters. Granted, the following example is for a mostly-empty map -- so, the best possible case for compression algorithms; a fleshed-out map would take a lot more text, even compressed -- but nonetheless, it's quite satisfying watching a giant wall of 65,536 (or thereabouts) numbers compress down to the following, and then be able to read it back in and have everything work correctly:

eJztxEENAAAIBKCzuc3VzRrwIF1J5ti2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu 2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu 2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu2bdu 2bdu2AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4CzCwpdU=

Developing the map editor has been my most recent stage in implementing Xist, and it's coming along quite well. It also has a fully functional minimap, which is not particularly difficult to implement, but is a very important convenience both for creating maps and for gameplay. Soon, I'll be ready to move on to the next step.

Screenshot of the Xist tile editor
A screenshot of the Xist map editor

Screenshot of the Xist tile editor
Another. These half-hearted terrain graphics are only for testing purposes, so don't judge them too harshly. 😛

What's Next?

Progress is excellent so far, but there is still much to go: environmental effects like rain, snow, and heat ripples; a flexible way of handling game actors (enemies, player-controlled actors, items, and other such interactive entities); smart and efficient real-time pathfinding; some primitive 3D support for when I don't want exclusively sprite-based graphics; and -- if I'm feeling ambitious -- built-in convenience functions for networking, in order to support remote multiplayer. But this inaugural post has grown far too long already, so I'll save details on those for once I actually implement them. It's a lot of work, but it will have been more than worth it when I'm done, since Xist will allow me to kickstart new game projects with enormous amounts of core functionality already done in a convenient form that can be easily extended to support various game ideas.

A Sneak Peek of the Games I'm Eventually Rebuilding

To show I'm not just blowing smoke about having made good progress on previous game projects, here's one screenshot each from my strategy game and first-person grid-based dungeon crawler RPG, which I'll be recreating using Xist as their basis:

Screenshot of strategy game

Screenshot of first-person dungeon crawler

Is This Framework Publicly Available?

While it's a work in progress, no; there would be no point sharing it in an incomplete state. For whatever reason, Processing doesn't seem especially popular for game development (I guess people find Unity sexier?), so I'm not sure how much interest there would be in Xist even once it is complete. That said, I'm not opposed in principle to sharing the framework, so if people expressed any interest in it, I'd be happy to share the code once it's ready.

1 | 2 | 3