Movement is pretty convenient in Cogmind, an important goal to aim for since this is generally the most common action players will perform in a roguelike.
Four different methods are supported out of the box, the mouse along with three different keyboard-based methods (numpad, arrow keys, and hjkl).
About the same number of players use the mouse and numpad, with the remaining minority divided between arrows and hjkl.
Moving via mouse cursor is certainly easy to use--simply click somewhere to go there automatically, although the keyboard offers finer control so it’s no surprise that in a tactical roguelike like Cogmind technically a majority of players end up relying on the keyboard for more or even all of their movement.
About one-fifth (21.3%) of players (including myself) even exclusively use the keyboard for everything, so for a while I’ve been mulling potential improvements and additional features for keyboard-based movement. According to the stats, newer players are more likely to start with mouse movement (unless already familiar with traditional roguelikes), but either way the chance of someone becoming a keyboard player goes up over time as they play more and learn how to do some actions faster that way, might as well continue improving the experience!
Keyboard Running
Although players new to the genre tend to assume “running” means a mechanics-relevant action where your character is actually “moving faster,” in terms of roguelike input schemes it actually refers to moving multiple spaces in a (usually straight) line via a single command.
Cogmind has had running ever since the original 7DRL release, because it really saves a lot of time (also more specifically back then mouse-based movement wasn’t a thing, so there needed to be some convenient way to quickly cover long distances!). At that point it was the dumbest implementation possible, though: “automatically move in one direction until something blocks the path.” (okay it could’ve been dumber--it also immediately stops on spotting an enemy, but I’m only talking about layout detection for now)
Smarter approaches need to take more of the layout into account, stopping not only at obstacles, but also where the player might want to reconsider their direction, or perhaps take another action.
That’s what I did for the alpha release, adding a new rule that the player should automatically stop running on reaching a location where the current cells immediately to the left and right are either doors or open space, and one or both of those adjacent to the previous position were not also open. This properly stops when arriving at doors/doorways, or arriving at a side-corridor while following a wall. It doesn’t stop, however, when running straight into a narrow corridor, so that’s a good thing.
At the time I left a note in my code that this could be better, but would get complicated fast and I wasn’t sure what use cases we might need to address before it was ideal, so that’s as far as I went.
Honestly if your running system gets too complicated it’ll be both annoying and unpredictable. Predictability is important, since mistakes can get you killed and no one’s going to be happy using a UI feature prone to “error” (where UI errors are defined by players as anything they did not expect/want to happen). Basically the system should stop as little as possible while still being as useful as possible.
There was definitely still room for important improvements, so that’s one of the areas I was working on recently.
For one, the original system was only applied when traveling in cardinal directions. While this is sufficient for most use cases since corridors only travel in cardinal directions anyway, sometimes diagonal running through an open area might hit a layout where it should stop. Rulewise it’s not really much different from cardinal movement, just looking at different cells.
Another improvement to address is the fact that the first diagram up there for cardinal running ends up being suboptimal! Although on reaching a corner you may want to move out beyond it in order to look around, there’s also the chance you intend to simply round the corner without looking first, in which case you can move one less space by taking the diagonal, an option which is lost if the running behavior always moves out beyond the end of the corner as it was before. Same goes for arriving at doors--open them by standing out in front, or by stepping into the doorway? The choice should be yours.
Here’s a sample of moving around using the latest iteration of the run command:
Other possible steps include automatically turning corners if moving down a narrow corridor that changes directions, although I think this is more suitable for other roguelikes (some have this feature), and not as common or useful in Cogmind. Of course QoL features always need to take a game’s unique characteristics into consideration rather than blindly implementing them.
A more reasonable possibility is to mimic mouse-driven pathfinding’s ability to optionally circumvent temporary obstacles like other robots. This is something that could theoretically be added for keyboard running as long as given the circumstances it won’t change the distance of the path, although I’m not sure I want to go there because it could in some cases have negative consequences and maintaining predictability is important here. Not to mention keyboards are all about that fine control, so running to an obstacle then quickly choosing how you want to deal with it--maybe wait, or choose a direction to go around, is probably preferable.
Keyboard Pathfinding
One of the main features I wanted to tackle with this round of movement updates was keyboard-based pathfinding. Although a lot of keyboard users don’t mind cellwise movement combined with a bit of running here and there, I always thought it would be nice if possible to choose a destination in keyboard mode and use a single command to move there via the quickest route, just like the mouse can by simply clicking on a location, regardless of how far away it is. So I’ve finally added it!
Using the mouse still has the advantage here and there were certainly some UX problems to work through, for example how to continue traveling to the destination after being interrupted--it would’ve been annoying to have to use examine mode to find the destination again!
To use this new feature, players have to be in examine mode (where you move the keyboard cursor around to inspect things) and simply press Shift-Alt-g (for “go”) on the destination. The result is just like a left-click on that location.
Technically this exits examine mode for the move, but key to the UX is that the destination is remembered, so until another destination is set, any time Shift-Alt-g is pressed Cogmind will resume approaching the destination. This is essential for when passing by a move-interrupting hostile like a Watcher.
Because it uses examine mode, keyboard pathfinding can also be useful when looking at items on the ground, e.g. while moving the cursor around to inspect salvage, if you find something you want a quick Shift-Alt-g brings you right to it.
For both this and mouse movement I’ve also finally made it so that setting an interactive machine as the destination automatically starts hacking it on arrival. After all, anyone who doesn’t want this effect can choose an adjacent cell as their target instead, and most anyone who is clicking on the machine’s terminal itself quite probably wants to hack it.
Adjustable Movement Delay
Another optional feature I’ve wanted to add for a while, one I’m quite curious if anyone will actually use, is to make the movement delay adjustable. “Movement delay” determines how long to wait before taking each move while traveling along a predetermined path, be it keyboard running or mouse/keyboard pathfinding.
Cogmind’s default has always been 100ms, a balance between “getting there quickly enough” while still being just slow enough react to unexpected changes. Quite a few potentially dangerous (or at least important to stop and observe) situations in Cogmind will stop automated movement anyway, but moving too quickly is still somewhat dangerous for the same reasons autoexplore is a bad idea in Cogmind. Among them are situations that can’t feasibly stop movement automatically, like threats on sensors changing directions, not to mention the high likelihood of wasting turns, which is generally bad in Cogmind since the passage of global time matters a fair bit.
As part of this update I also fixed the issue of the unreliability of stopping running/pathfinding in progress, even more important now that the speed is adjustable because the problem could have become more pronounced with lower movement delays. (Normally any input made while moving should immediately stop the move, but input is also generally blocked while actions are being carried out, and the way it was blocked happened to also sometimes be ignoring even input that should technically be doing the stopping xD)
Still, I don’t really recommend changing this value from the default, I mainly just added it because it was easy to do and options are good, right? :P
Move Blocking
Stopping movement in progress, or even preemptively blocking a move before it begins, is an important part of roguelike QoL. (Technically this principle also applies outside movement as well, extending to other questionable or potentially dangerous actions, but this article is about movement in particular.)
I’ve heard players of some roguelikes (though not Cogmind, to my knowledge) argue that games shouldn’t protect players from their own stupid mistakes, but I think of it as basic QoL because if anything this sort of protection allows for more efficient play without having to waste time thinking about avoiding stupid mistakes, instead focusing on in-game tactical decisions rather than fighting the UI itself.
Anyway, over the years I’ve been adding quite a few of these, and will keep adding more as necessary. Below are some of the movement-related blocks I’ve implemented (none of these are new)
Non-optional blocks:
- New combat threats entering FOV
- Ramming (this was one of the first new blocks added in early alpha, and I can remember how chaotic it was back then with players constantly ramming into non-combat bots while moving around)
- Spotting a new hostile trap
- Moving onto a known trap
- Flying while overweight
- Sudden system corruption effects like heat surge (sometimes responding with an immediate increase in dissipation might be necessary) and part rejection (don’t want to leave some random part behind!)
Optional blocks (all active by default):
- New non-combat enemies in FOV
- Exiting to another map
- Melee attacking a neutral target by moving into them
- Melee attacking while flying (since the intent may be to simply jump)
- Speed is very slow (>= 3 turns per cell)
The way temporary blocks generally work is they block the move and continue blocking movement for the next 500ms (while showing a warning message). This is important because movement is often a repeated action and players need time to respond to whatever it is they need to be noticing here, rather than just repeatedly mashing keys. Then once past initial warning period, there’s a window of about 2500ms during which that same warning won’t be shown again and the player is free to do that action (or maybe change their mind and do something else).
The one exception to the block window is spotting threats/enemies/traps, because those happen frequently and the main purpose there is to just block running/pathfinding rather than additional individual moves, so spotting a new enemy continues allowing movement freely.
What Else?
I’m sure more things will eventually pop up!
One internal movement-related feature that needs work is the pathfinding heuristic. The current pathfinding is actually pretty wasteful, and is one of the main processing bottlenecks for the game, but I’ve already done a few rounds of optimization as necessary and it’s fast enough, so that’s still been sitting by the wayside for if/when we need more performance improvements.
In its current state pathfinding (for all the AIs, mind you--just pathfinding for the player is negligible) doesn’t cause problems under normal circumstances, though the heuristic is clearly off when looking at how it searches for a path, checking more cells than should be necessary:
Anyway, I tried before and couldn’t immediately find any way to effectively improve it (the obvious solutions weren’t working for some reason xD), but there are also other ways to optimize pathfinding besides the heuristic ;)
2 Comments
This blog… so inspiring and at the same time, so **** intimidating. There are days I ask ‘what is math’ and I am happy I get a project to compile + something walks around.
Thank you for the update!
Hi Orlando, glad it’s inspiring, and I will say that I am honestly still in your boat in a lot of ways, too. Over a long period of time I did finally find a limited set of tools and processes that work for me, but in the interest of just Making Games, after all these years I stick to those rather than trying out too much new tech. I’m still using super ancient stuff when it comes to even Cogmind, a seemingly “modern” game on Steam xD
Trying to add new libraries or get things to compile gives me a headache, and I avoid it like the plague!
Also I’m terrible at math. Terrible. But not so bad at logic, so I lean on that instead :P