Segmentation Progress

I managed to make some progress with map segmentation. I've been working with the scikit-image graph module, which has a fast implementation of Dijkstra's algorithm on numpy arrays. I've had it in mind since I saw this post a couple of weeks ago:

It took me a long time to figure out how to use it properly. I even took to reading and modifying the source code to get the results I expected, which was complicated by the fact that it's written with Cython. I ended up removing the Cython declarations and using it as a Python module so I could follow the internal state, and eventually found the right inputs to use for it to work without modification.

/images/Progress1.png/images/Progress2.png/images/Progress3.png

Defining Spaces

Here's what I've managed for defining spaces so far. Just kept blindly using a number of scipy image processing functions till I managed to figure out what they did. Quickly noticed that the distance transform function had potential, but I've spent an entire day trying to learn how to segment the map using that data. Attached are a couple of plots I generated showing the kind of information I've been able to extract. It looks like taking the local maxima of the distance transform does reasonably well for identifying distinct spaces. Now I think I need something similar to the watershed transform to actually establish the boundaries of each room.

/images/Spaces1.png/images/Spaces2.png

Events, Scrolling

For events, I was thinking of using publish/subscribe to connect the game's components and systems with each other. In that case I'd try to use an existing library, and PyPubSub might be an option. Might also consider extracting the dispatch module from Django (docs) if it's independent enough. Though I don't know enough about the performance consequences of something like this, and performance is going to be a significant issue soon.

I'll need to do another rewrite soon, because the code is not at all designed to handle a scrolling viewport. Too much of it is based on assumptions about the screen being a single map. There are a lot of design issues to work out before that can happen properly, and at the same time I should think about reducing the amount of unnecessary work done on each frame. I likely won't be able to manage that before Saturday.

In the end, scrolling might be something that's better off dropped, because it substantially complicates many parts of the game. It depends on whether I'd be able to find the right abstraction to limit that.

Infinite World

It took about 16 hours, but I managed to stitch multiple maps together with only rare defects on the edges. It looks really good to me, and the errors are likely just because I cut a couple of corners in the smoothing phase of the generation algorithm. Currently the game has no viewport concept, rendering a map per screen and switching maps when you walk off the border. I'm intending to redesign it for smooth scrolling, but that's been more of a challenge. I've been struggling with designing a world model for the game, to abstract away the individual maps and unify location handling.

As for what I might work on next... I could try spawning creatures and giving them basic behaviors. That sounds a bit complicated, though. Useful behavior for NPCs requires giving meaning to spaces in the world, and that might take a while to figure out. I wanted to prototype communication/interaction systems, but combat systems will be easier to get started on, and they don't need particularly intelligent behavior.

Pathfinding could be worth looking at. I just found this blog, which has an interesting approach to roguelike game structure. It's rather different from what I've done so far, though. What I've got right now is an infinite world, so I don't know if Dijkstra maps are feasible.

There are also field-of-view and line-of-sight algorithms. I'm looking at Restrictive Precise Angle Shadowcasting for the FOV algorithm. FastLOS looks interesting; I'd have to implement it to understand what it actually does.

I haven't actually set up an event system, so inter-object communication is kind of limited at the moment. There are also a whole lot of optimization issues. Making the maps larger is very costly and I'll have to rewrite some of the drawing and update routines.

I may also look at increasing terrain complexity, creating more interesting features. Maybe wilderness or town maps as I mentioned before. That's somewhat easier to make visible progress on with the current state of the game. And there are lots of links to terrain generation material. A few such:

On noise:

Rewrite, NumPy, SciPy

I'm feeling pretty good now. Friday was a really productive day. I began rewriting the game in-place, tearing open the code and extracting it into neater compartments. Once I got into it, it became surprisingly easy to progress. I think it helped that, after cutting out each piece, being able to focus on returning the program to a working state kept me on track. In the last day and a half, I've been able to unravel the nest of patchwork hackery I'd put together and get the program looking sensible again.

After initially cleaning up the game loop, I started thinking about the possibility of live-coding. Did a little research, and found out how to spawn an IPython console in a separate thread, with access to the game's internal state. Being able to inspect and modify the game's map structure and other data makes it much easier to follow what the map generation process is doing. I've managed to put together a couple of nice debug mechanisms and visualization functions, which should help with future complications.

Unfortunately Python doesn't have enough support for full live-coding. I can reload changed modules, but it won't update existing objects. After hearing about Clojure's advantages here, I'm more motivated to finally look into it now. Maybe once I'm done with my ideas for the roguelike.

I've reworked map handling to use numpy, which substantially increased the speed of the dungeon generation algorithm. It can run several iterations on the current map size in tens of milliseconds, much better than the couple of seconds it took before. I improved the way terrain variation was implemented, and based it on a hash function as mentioned before. I also started putting together the entity-component system, but since I have no idea what it really ought to look like, I don't know whether I've created some kind of abomination. It's working for now and I've got characters moving again, but I'll call it placeholder.

UI is nonexistent and input handling is simplistic for now. The thing that caused me the most trouble yesterday was coming up with a scheduler for entity actions/updates. Struggled with it for a while and ended up just reimplementing the basic scheme I used before, but with slightly better separation of concerns.

The following is a screenshot showing scipy and matplotlib used to display isolated map regions. I've only figured out very basic usage so far, but maybe I can do something interesting in time.

/images/ipython,%20scipy,%20matplotlib.png

The game is currently running on 32-bit Python 2.7, with libtcod 1.5.1, numpy 1.9.2, scipy 0.16.0, and IPython 4.0.0.

Libtcod is the main limitation here--I'm getting errors attempting to build a 64-bit version from the repo, and the Python bindings don't work properly on Python 3. I kind of want to switch to pyglet since there isn't really all that much benefit to being on libtcod aside from the simple console-like output. I don't want to try to implement my own tile engine at the moment though.

Never mind what I said about wilderness generation being next. I really want to get multiple maps and map transitions working. Then see if I can force the edges of the cell-automaton generated maps to link up. Roaming through endless random caves has potential, and I can use that as a starting point for basic gameplay.

Spatial Indexing

I just spent nearly two days researching spatial indexing/partitioning. I'm trying to figure out what kind of structure I need to represent my game world.

Initially, I was trying to find a way to identify contiguous regions in my generated map. I wanted to select isolated rooms (some can be seen in the previous screenshot) so I could try to do something with them. Maybe run a tunneling algorithm to connect them up to the rest of the map, or just convert them into something decorative like pools of water. Started looking at running flood fills and counting cells but quickly abandoned that. I don't want to try to manually implement flood fill in Python, given that I'm already seeing a small slowdown in generating this tiny map. I wanted a more efficient option, and eventually got to numpy and scipy. These two libraries allow fast processing of multi-dimensional arrays, and these scipy functions (particularly label) look like exactly the kind of thing I need. It took me some time to understand how it works, and now I've got a pending task to refit my map representation to use numpy arrays.

With this, I started considering the possibility of treating the tilemap as essentially a 2D image. Each tile is pretty much just a pixel, so that should allow you to use all sorts of 2D graphics techniques to process a map. You could split a map into multiple layers, create masks, and treat them like sprites, blitting subregions onto a background. Something like that might be a way to support construction and terrain deformation in the game. What could be done with filters, shaders, and other such methods? I don't know much about those, so they're another subject to research later.

From there I went to 2D collision techniques, looking at ways to quickly find intersections among intervals and points. I found references to R-trees, kd-trees, quadtrees, segment trees, and interval and range trees. After many hours I've understood pretty much nothing of the technical aspects of how they work, but the latter three look like useful constructs. I found this series of articles which led to this Javascript library that implements streaming segment trees. At least 10 hours yesterday were spent attempting to port this library to Python, both because I wanted to experiment and because I was hoping to learn about the algorithm and the techniques used to make it efficient. I only got partway through before hitting a major roadblock, in that the library seems to make heavy use of some kind of run-time code generation which I have no idea how to translate.

Nobody seems to have written Python code that provides mutable 2D spatial trees. The best I can find seem to be the 1D intervaltree package and the insert-only pyqtree quad tree. Maybe that'll be enough. In the end, though, all of that is completely irrelevant to the roguelike. Consensus is that uniform grids and spatial hashing are generally sufficient for box intersection in a game. Constructing and maintaining a tree is only worthwhile in cases where you have objects of widely varying dimensions or if they're sparsely distributed. Still, this may be useful for a later project.

There's another significant challenge pending, namely making the map generation deterministic so that I can save its state. Even if I save the terrain layout of the map, I'm going to be using random minor variations in color and characters to texture the terrain. Modifying the terrain during gameplay will throw this off completely and result in blatant changes in appearance. I want to keep the terrain layout and appearance separate. That is, I just want to record that a cell contains grass; I don't want to store which of the 8 possible variations of grass tile the game displayed for that particular cell. And I just realized that I should be using a hash function here instead of an RNG. That'll fix the problem, assuming the function provides good distribution of values. Maybe save a random seed/salt value for each map, and then use a hash to combine that with each tile's position and terrain type to choose a variant.

...and now I've spent some hours reading about Bloom filters, cuckoo hashing, key derivation functions, etc., while looking for a suitable Python hash function. Interesting post here (links to a Youtube playlist with videos).

The step after this is going to be wilderness generation. I'll pause work on dungeon generation because I need to figure out map representation for towns and overworld terrain. I'm thinking that I'd like to have some z-level variation in surface maps, and I have an idea of how to visualize it, but that's something that needs to be prototyped. Giving it the right visual presentation will mean more trial-and-error color work, and I'll probably have to try out stuff like alpha blending and color interpolation.

Scheduling and Terrain

I've done more work on the roguelike prototype. Ran into a couple more challenges than I intended to deal with. I want to make the game turn-based, but I had to use a real-time game loop to avoid having very clunky and unresponsive input. So the UI updates at 60 fps, but I need the game entities to update in step with the player. I had to set up a very crude scheduler for entities along with an action queue system. At least now I can have my NPCs carry out move, wait, and loop instructions.

Also had to start defining terrain characteristics so that I could start map generation. I'm currently using JSON to define symbol sets and colors for different terrain types, but it'll get much more complicated before it's capable of everything I'll need. I spent way too long trying to coordinate terrain patterns and colors. Finally, though, I've got the first dungeon generation algorithm working. Uses some simple cellular automaton rules, based on this article. It looks pretty much like I wanted it to, but this method creates space as pretty much an unstructured blob. I'll have to eventually figure out how to establish/guarantee connectivity, find useful spaces for distributing dungeon features and monsters, and so on.

/images/cellular%20automaton%20cave%20generation.png

The code at this point is a horrible mess. I'll need to rewrite it to use an entity-component system before I can get any actual gameplay going. For now, I'll just try to work out other methods of dungeon and overworld generation, and try to produce a decent map representation that can handle the features I require.

Here's a good post that lays out several of the basic systems needed for a roguelike game. I'm glad I stumbled across it since it kept me from having to discover them through trial and error.

Getting Started

Lately I've been busy reading game development resources. I discovered the Phaser HTML5 game framework, and after spending a couple of days exploring the possibilities, found and followed a shmup tutorial. Around the same time, I found guides to 2D sprite art and started learning about the basic skills involved. This collection of vector art walkthroughs turned out to be useful, along with more detailed guides like this and this. Those and their many links helped me finally make some sense of colors and shading.

I made a few attempts to integrate that information and practice constructing basic combinations of shapes. I've found I presently don't have the slightest intuition for artistic composition, so it takes me many, many hours of trial and error to construct even simple things. For example, I managed to put together the following "TrivialSprite" after 6-8 hours. It's intended for a simplistic top-down shooter idea where I wanted to mimic a tiny portion of the design of the game Heat Signature (which looks interesting, incidentally).

/images/TrivialSprite.png

I've started to think that composing a piece of artwork involves much the same level of design work as writing a program of similar scope. A trivial object may be as straightforward as a script. A person or other complex figure requires composing multiple trivial objects and carefully aligning things like color and shading. A scene requires balancing/connecting lighting, colors, emphasis and such across many figures. Improving my ability in this would take a lot of work, and since I'm not feeling much interest/pleasure/affinity for the process of composition, I'm thinking I probably don't want to go much further with it.

I've also started learning about roguelike development again. Went back to old resources and found many new ones. Between things like RogueBasin and /r/roguelikedev's FAQ Fridays, there's a lot of information to work with. I've been learning about terrain generation and trying to prepare a prototype to experiment with. I'm currently following the Python + libtcod tutorial to refresh my memory. I've found many potential platforms to work with as well:

  • libtcod for console output
  • SquidLib for Java
  • pyglet for OpenGL in Python
  • or even Godot, a full, open-source game engine with scene editor, IDE, and Python-like scripting language.

I've been seeing many examples of game designs and interfaces that seem simple enough to be accessible to me now. It's making many of my previous ideas more viable, so they keep cycling through my mind. I've got at least half a dozen clusters of fragments of ideas being formed. I have to figure out which one to isolate and focus on.