FreshRSS

Normální zobrazení

Jsou dostupné nové články, klikněte pro obnovení stránky.
PředevčíremHlavní kanál
  • ✇Grid Sage Games
  • Adventures in Map Zooming, Part 5: QoLKyzrati
    Map zooming again! Although I finished off the final bits of the core map zooming feature, that series went quiet when I turned my attention to planning and preparation for the upscaled UI, essentially due to my belief that once the latter is implemented, map zooming wouldn’t be as necessary in the first place. But it would still no doubt be used by some, and more urgently I also realized that it wouldn’t make sense to put out map zoom test builds without including the additional QoL required to
     

Adventures in Map Zooming, Part 5: QoL

Od: Kyzrati
11. Únor 2024 v 09:30

Map zooming again! Although I finished off the final bits of the core map zooming feature, that series went quiet when I turned my attention to planning and preparation for the upscaled UI, essentially due to my belief that once the latter is implemented, map zooming wouldn’t be as necessary in the first place.

But it would still no doubt be used by some, and more urgently I also realized that it wouldn’t make sense to put out map zoom test builds without including the additional QoL required to make a zoomed view actually playable in a normal sense. Although I rightly assumed few current players are very interested in zooming, some of them might at least test it out, and for proper feedback the QoL needs to be in place, otherwise any feedback will essentially amount to “needs QoL” :P

Good QoL is a make or break part of map zooming, where the real magic happens, and I love me some QoL design, so let’s see what we can do to facilitate zoomed play!

First of all, not exactly surprising or amazing, but one piece of the puzzle did suddenly fall into place here: scroll wheel zoom toggling. Back in the polishing stage I covered the reasoning for using methods other than the scroll wheel to zoom, but when putting together the QoL features I realized that zooming in and out might often be done in conjunction with map panning, which among several other methods can be accomplished by holding Shift and moving the mouse. Well if you’re panning with the Shift key held, using the mouse wheel wouldn’t do anything since that’s not a command yet (Shift-Wheel), so we can conveniently assign it to zooming!

cogmind_mouse_map_zoom_and_pan

It feels very natural to add mouse wheel zoom functionality to the existing Shift panning method, making it easy to quickly zoom in and out between multiple distant locations.

That’s low-hanging fruit, though. We’re going to need much more powerful QoL…

Relative Centering

A common theme throughout map zooming QoL development is enabling the player to get information about, and react to, things that are outside the current map view. As explained in my article on the history and theory behind Cogmind’s interface and plans for other layouts, in a roguelike it’s crucial to have easy access to knowledge that affects near-term decision-making, and by shrinking the map view to increase the size of its content we’re giving up a lot of that easy access!

We need to find ways to retain it where possible, or at least create alternatives.

One of the most direct ways to accomplish this is to offset the player’s position from the center of the map. Normally Cogmind is shown at the center of the view, allowing the player to see equally in all directions, but technically we can assume that what’s most important while exploring the world is what’s in front of the player in whatever general direction they’d like to focus on. Thus one new optional feature is the ability to manually set a new relative centerpoint.

cogmind_view_centerpoint_manual_mouse

In this zoomed map view, notice how one can choose to look further in a particular direction, and the view continues to shift along with your movement, as usual. For as long as such a point is set, it is used in most instances which otherwise want center on Cogmind, and the point is never allowed to be so far away it results in Cogmind being out of view entirely. Zooming the map in/out adjusts the relative centerpoint by the same factor, and it’s ignored or even automatically reset in some special instances, like… say… outright teleportation ;)

The above recording shows how setting such a point is accompanied by a fading cardinal crosshair animation akin to the drone centering/following animation, but here is grey instead of green. This keeps our visual theming consistent for the idea of interface-controlled “centering.” While a manual centerpoint is set, you can also see the intermittent flash of the current centerpoint, which is optional and can be adjusted or disabled. Restoring the default centering is as simple as setting your current position as the centerpoint.

How do you set that point, anyway? Oh no, it’s time to go… back to the engine! (are you counting? this is the fifth time :P)

I decided for this feature we are finally, after ten years, going to have RMB detection based on releasing the button. Cogmind has always responded to mouse down events for input, which I prefer since it’s that much more responsive, but the difference isn’t huge, and by forgoing that approach we gain access to a new realm of mouse input: holding the button for a different effect!

Now this alone doesn’t require any extra engine work, it’s just a different event we could always detect, but if you’re going to have input based on holding a key you probably need to know how long it’s been held, and for that we’re going to need more engine functionality. Paging the REX testing environment!

rex_mousedown_timers_demo

Testing LMB/RMB holding timers, a new feature for the engine.

RMB has always been one of the other methods for panning the map in Cogmind, by just right-clicking on some location outside FOV, but now if you hold down the button for a bit longer (the default is 350ms, but it’s adjustable) it will not only pan the map over there but also set it as the new relative centerpoint, as seen in the demo.

As far as implementation goes, although a little more difficult to implement, it made more sense to cause the centering effect to occur immediately after a set time had passed, rather than simply waiting for the player to depress the mouse button after a minimum amount of time, because otherwise the player has to guess whether they’ve held down the mouse long enough to count for one input over another.

Dynamic Centering

Pure keyboard users need access to this recentering concept as well, though unlike with a mouse where it’s fairly quick to select a new forward point to center around, this isn’t so convenient to do via keyboard… We need an automated alternative!

By default whenever zoomed in keyboard mode, simple regular movement will automatically attempt to adjust the map view so that a more useful or pertinent area is visible at all times. Exactly how to achieve this is a big question, however :)

I’m sure no single algorithm will be perfect for everyone, but I experimented with five different possibilities before settling on a default. Most of these are included with the game as optional alternatives, and can also be completely disabled or further adjusted by specifying a maximum distance out to which they’re allowed to offset the view. Many of them feel quite strange at first, but with some actual play experience I got more and more used to the default as a helpful feature.

cogmind_keyboard_automated_view_centerpoint_style_WIP_3_instant

INSTANT: “Smart leading” behavior #1, simply instantly “face” the direction of the most recent move. Just try not get whiplash :P (seriously though, controlling these, and also gaining some experience with them, is a lot different from watching them; also adjusting this one to have a shorter offset range would make it less jarring :P)

 

cogmind_keyboard_automated_view_centerpoint_style_WIP_2_midpoint

MIDPOINT: Behavior #2 is the same as INSTANT, but makes diagonal turning less violent by checking whether a new movement direction is only 45 degrees off the previous one, in which case the new centerpoint instead uses the midpoint between the old and what would otherwise be the new instant direction’s centerpoint.

 

cogmind_keyboard_automated_view_centerpoint_style_WIP_1_gradual

GRADUAL: This more tame approach slowly shifts the view to reflect ongoing movements, both in terms of direction and distance, so that moving forward gradually extends the view outward.

 

cogmind_keyboard_automated_view_centerpoint_style_WIP_4_pure_fov_weight

WEIGHTED: GRADUAL doesn’t perform as well with sudden changes in direction like going around corners, so I wanted to experiment with using a more complex algorithm that instead tries to orient the view based on the weighted center of all FOV cells. The theory seems nice, but in practice is kinda chaotic and not very effective. primarily because it entirely forgoes predictability in the face of a pure focus on information, when we probably want a balance between the two. (This particular gif happens to have a persistent red dot where it’s centering the view, so I could better keep track of it during the experiments, since the weighted behavior was harder to get right.)

The behavior I actually chose for the default was a combination of the last two, gradually shifting the centerpoint with each move, and using a second pass to try to ensure that FOV edges are visible where it’s possible to shift the view without obscuring already-visible FOV cells. This is a pretty effective way to solve the corner problem, or whenever a large batch of new cells becomes visible, for example on passing through a door, or terrain destruction. It can also even keep the FOV shifted backwards if the current direction of movement doesn’t yet really contain much to see.

cogmind_keyboard_automated_view_centerpoint_style_WIP_5_gradual_with_FOV_shifting

The default behavior, a gradual two-pass approach striking a balance between seeing further in the direction of exploration and maintaining visual confirmation of existing FOV areas.

As with the mouse, keyboard users can also manually designate a relative centerpoint. This is done with the ‘s’ key in examine mode with the cursor over your desired target cell. Assigning a manual centerpoint deactivates the automation feature until designating Cogmind’s own position to reset it, at which point the automated system will again take over. This feature is also useful for quickly recentering the map to reset the automated system, by simply pressing ‘x’ to enter examine mode followed by an immediate ‘s’.

cogmind_view_centerpoint_manual_keyboard

Manually setting centerpoints while playing in keyboard mode. It’s actually fairly fast if you’re familiar with jumping the examine cursor!

While playtesting keyboard mode, zoomed in for almost the entirety of play, I started to rather like the combination of default autocentering sprinkled with occasional setting of a manual offset for certain situations!

Notice that while in keyboard mode, the centerpoint highlight is not shown--that’s a mouse-only thing because it is automatic, and also at times quite near Cogmind’s own position.

Internally, the automated centering feature is implemented by simply adjusting the same offset variable used for manual centering, just doing it on the fly. So they’re the same mechanism. Automating this behavior during mouse-based play doesn’t really work because you have to be able to click on locations, including most importantly your next move destination, but that’s hard to pull off when everything is shifting around in a semi-unpredictable manner.

And even for keyboard mode, the automation behavior is only applied while the map is zoomed in, but it’s always being calculated and updated while not zoomed, so that zooming in again can continue to take the latest navigation information into account.

Of course I added new contextual tutorial content for these features, including Cogmind’s first tutorial messages that will eventually repeat themselves if you haven’t actually tried a given feature yet, because these are quite important :)

Offscreen Object Info

So far we have ways to try to keep important objects in view, but once you’re zoomed in on only a quarter of the normal map area it’s literally impossible to always see everything you might need to see in every situation. We need new indicators for important objects outside the current map view, especially those which are still within FOV (and probably even attack range!).

While manually panning the map or designating a centerpoint to keep an eye on a particular direction is useful, and temporarily zooming out to get a general idea of the surroundings is another option, to save time there are a variety of new markers that can appear at the edges of the map view to denote objects in that direction. You’ll see markers for offscreen hostiles, non-hostiles (both neutral and friendly), new items, and sensor data. Each marker category uses its own unique background color, and in the case of sensor data is also darker and blinks in and out to reflect the fact that it is not a directly visible object like the others. Items are only marked until automatically labeled for the first time after entering view.

cogmind_map_zoom_qol_edge_labels_robots

A demo of flashing offscreen zoom markers for visible robots (I have some drones out here to help demonstrate). Threats appear on a dark red background, while non-hostile robots use dark-green. As usual, the colors used are different if colorblind mode is active. (Also curse multitile robots and their special requirements, but yeah I got them working with this system too…)

 

cogmind_map_zoom_qol_edge_labels_items

Flashing offscreen zoom markers for new items, which use a dark gray background.

 

cogmind_map_zoom_qol_edge_labels_sensors

Dark offscreen sensor data markers with a low-frequency blink out effect. The range for this and other FOV data (which actually includes drone FOV that may be further away!) actually uses the non-zoom window dimensions to determine the extent within which to draw objects from, meaning this feature essentially serves the specific purpose of giving you more info about many things you’d normally be able to see if not zoomed in.

We’ve seen such map edge markers before, for map intel (for example known interactive machine locations) and also Cogmind or drones currently out of view. The latter appear a couple rows away from the map edge, so there aren’t any issues with overlap, though intel would technically be able to overlap these markers, also being up against the view edge. I’ve updated those to not only reposition to avoid any offscreen object markers, but they also avoid covering visible robots currently at the edge.

cogmind_intel_markers_avoiding_visible_edge_robots

Intel markers avoiding visible robots at the map view edge.

Similarly, the new offscreen object markers will also avoid covering visible robots.

cogmind_offscreen_object_markers_avoiding_visible_edge_robots

Offscreen robots markers shifting aside when necessary to reveal visible robots at a position they would otherwise occupy.

Offscreen Object Responses

Indicators are great, but not quite enough. After all, what do you generally want to do when a new threat comes into view? A quick visual check! What exactly are they, what’s their status, do they have company, what’s the surrounding environment like… These can be important questions to answer before making your next decision, and by default Cogmind already pauses for a moment in these situations in order to let the player have a moment to take it in (and avoid accidentally wasting valuable turns), so why not also use that opportunity to automatically shift the view over to spot the threat?

cogmind_map_zoom_qol_view_shift_for_new_threat

Automatically shifting the view a bit more to the left as soon as a Sentry is spotted down at the end of a corridor.

This feature is optional, but active by default.

cogmind_map_zoom_qol_view_shift_for_new_threat_multiple

Another autoshifting example, in this case simultaneously spotting enemies down two different corridors and shifting to put them all in view.

Notice that the shift leaves one space of padding to the edge rather than putting the hostile right at the edge, which is harder to see and there may also be other markers present, plus it’s nice to know a little of what’s around the target.

There are also a couple other important threats that don’t involve direct sighting of enemies, but that most players would probably find worth automatically shifting to see for better situational awareness.

cogmind_map_zoom_qol_view_shift_for_watcher_alert

The view shifts twice here, once on first spotting the Watcher, and again when it sends out an alert to some nearby ally.

 

cogmind_map_zoom_qol_view_shift_for_heavy_sensors

Heavy active sensor proximity alert!

We can use this shifting behavior for more than just enemies, too!

cogmind_map_zoom_qol_view_shift_for_machine_ping

There are a few special types of environmental pings you really want to know about, like machine pings. Show me that RIF Installer so I know where I can get my next fix!

Other Features

As part of this update I even added a completely new type of indicator, one that can come in handy even when not zoomed in. Sometimes those pesky Operators spot you and immediately zip out of FOV, much less out of view, on their way to their Terminal. At least there’s a log message reflecting that fact, though it may not be obvious where they were at the time. Now it will be.

cogmind_operator_reporting_response_animation

Operator reporting indicator, which remains for a short duration whether the position is visible or not.

Although available even while not zoomed, a new <HOSTILES> button that appears above the map while there are hostiles within Cogmind’s FOV was added primarily to facilitate play while zoomed in, offering another way to know and confirm that there are hostiles in line of sight, even if not currently in view. The button reports the total enemy count, and can be pressed to focus on and highlight the largest concentration of enemies. Pressing it again restores the centerpoint to its original area, or in some cases if there are other enemies not visible in the first highlight area it may be able to determine that and focus there instead.

cogmind_map_zoom_qol_fov_hostiles_button

Demonstrating basic functionality of the <HOSTILES> button, although in this situation there would be no strong need to actually use it.

 

cogmind_map_zoom_qol_fov_hostiles_button_return

Using the <HOSTILES> button to refocus the view on a new squad still out of view to the north.

 

cogmind_map_zoom_qol_fov_hostiles_button_multiple_out_of_view

Cycling between two different enemies that aren’t present in the same view. Remember that in targeting mode Cogmind can also cycle between visible robots, this is just another more general way to achieve a similar effect while not in that mode.

I also have notes on even more QoL ideas for map zooming, as well as ways to further extend these new features, but this seems quite good enough for now and we’ll have to see how more playtesting pans out.

Shortly before the first testing build went out I did my own playtest run, trying out both mouse and keyboard play while zoomed… it went well!

We’ve arrived at the end of our five-part adventure through the process of putting all this together:

  • ✇Grid Sage Games
  • Adventures in Map Zooming, Part 4: PolishingKyzrati
    The core functionality of our map zooming feature is operating smoothly--common windows are popping up where they’re supposed to go, map interaction itself appears normal… however there are plenty of less vital systems that still need to consider the effect of zooming. And after those there’s the public-facing side of this feature, like how do you access it, and do we need to animate it? Odds and Ends Gotta check every little thing, like the tiles-ASCII toggling animation, does that work? Nope.
     

Adventures in Map Zooming, Part 4: Polishing

Od: Kyzrati
12. Prosinec 2023 v 11:05

The core functionality of our map zooming feature is operating smoothly--common windows are popping up where they’re supposed to go, map interaction itself appears normal… however there are plenty of less vital systems that still need to consider the effect of zooming.

And after those there’s the public-facing side of this feature, like how do you access it, and do we need to animate it?

Odds and Ends

Gotta check every little thing, like the tiles-ASCII toggling animation, does that work?

cogmind_map_zoomed_tiles_ASCII_swap_bug

Nope.

How about the map export function?

cogmind_map_zoomed_map_export_bug

Nope.

Anyway yeah just a case of going in and seeking out what prior assumptions they made about the interface that no longer held true when zooming is possible.

For the tileset animation I think it was as simple as having needed to set it to match whatever tile size the map is currently using, rather than always using the standard size. Funny result though :)

The map export issue was similar, resulting in only the top-left corner of each oct tile being rendered, but to a huge mostly empty image. Resolving that was a little more complicated than simply switching to a dynamic tile size because you don’t want the output to actually use larger tiles (doing so takes forever and results in a massive image file that doesn’t even add any extra data since it’s purely a pixelwise upscale). Instead what happens now, assuming the player is zoomed in, is an automatic zoom out, prepare the image, then zoom back in, all behind the scenes. (Map export images are created by repeatedly moving the map view, rendering the view area, and copying that view to an image surface, eventually stitching together all the views into a final image.)

Many of Cogmind’s optional special modes also have their own UI elements, usually an interactive window in the bottom-left corner of the map, and although I don’t generally update those, failing to have them take into account a zoomed map would almost be equivalent to leaving them behind. That would be bad, especially the fan-favorite Player 2, and the essential-for-some RPGLIKE.

This ended up requiring that some of them be moved to the new window-container-map-view-thing I described last time, or in other cases slight architectural changes.

cogmind_map_zooming_special_mode_UI_compatibility

Sample special mode consoles remaining functional regardless of zoom state.

Okay we’re just about finished up with the zoom function here, let’s not forget about the last but not least important test of all… stress testing!

cogmind_map_zoom_stress_test

Repeatedly zooming in and out doesn’t seem to break anything, except maybe a few eyes if you keep this up.

Access!

From the beginning and throughout this entire process so far, I had simply dropped the zoom toggling code into the input section for responding to the map intel key, ‘z’. Now it’s time to consider how the player will access this feature…

Actually, as far as keyboard input goes ‘z’ seems appropriate, yeah? Obviously.

Then where does intel go? Under past circumstances I’d be tempted to leave map intel to F8, its matching window key which also works, and despite the awkwardness of F8 being a function key, I don’t believe toggling intel has been a common need in the first place.

That said, while working on map zooming I’ve also been somewhat thinking about interface developments down the line, and realized we’ll later on need to free up yet another key anyway, so where can we get two keys? The answer is inventory sorting.

Cogmind’s inventory can be sorted by type, mass, and integrity, each with their own key (t/m/i). We don’t really need the latter two. It’s not that they absolutely never come in handy, but after the Beta 11 storage rework the largest build inventories are no longer as extreme as they used to be, so there are fewer items to parse through, and you can also relatively easily see the mass/integrity info fairly easily in different data visualization modes--colored bars and numbers for integrity (which are also automatically subsorted for matching parts), and the ‘q’ info mode shows mass as its first number.

Two whole keys! And lucky for us they match our needs perfectly: ‘z’ for zoom, ‘m’ for map intel, and ‘i’ for… well you’ll found out what that’s for later ;)

cogmind_inventory_type_sort_final

The inventory’s {t/m/i} buttons have been replaced by a single large {sort (t)} button.

So anyone wanting to toggle the zoom state of the map can tap ‘z’ and boom, but what about mouse users? Can’t forget mouse users.

I had some different creative ideas* for this one, but settled on just making it a typical button. The <ZOOM> button appears directly over the center of the map, in the bottom left corner of the central multiconsole. It uses the same style as the <MAP> and <ESC/?> buttons, and is similarly capable of glowing.

cogmind_zoom_button_demo_tutorial

There is also a new tutorial message shortly after starting the game that points out the zooming feature, after which the button will glow until it’s used for the first time.

The button disappears completely while keyboard mode is active (like the CYCLE buttons in the parts list), since it’s not needed in that case.

*Before getting creative I originally wanted to use the mouse wheel for zooming, but it’s a mere toggle rather than a smooth zoom, so that’d be a bit of a waste for the wheel, and making such a change would remove the simple method mouse users can use to pass turn(s).

Fluff

Towards the end of the map zooming work I couldn’t help but take advantage of the opportunity for a new animation to test out a lot of possible concepts. Like dozens and dozens of them.

I shared a bunch of samples from that process on Patreon, like this one I thought was pretty neat:

cogmind_map_zoom_animation_ascii_merge_unused

In this animation test, zooming the map in ASCII mode merges multiple copies of each character into a larger version to fill the final cell size.

The problem with such animations is that they can be too distracting when the purpose of adjusting your zoom is clearly to get a better look at something or some things, be it closer up or further away. So you need to be able to quickly focus, a need which most animations are likely to detract from.

And while sure it’s fun to get a cool new animation, if it gets in the way it would more easily “get old.”* Yeah we could make it optional, but if it’s detrimental and most people would presumably want it off, then why add it in the first place?

*on that note, I do plan to eventually swap out the world map animation for something snappier! the world outgrew that thing a long time ago…

In light of that analysis, and having not found anything extremely compelling while exploring animation styles, from early on I was already leaning towards having no animation at all--short and sweet, right? Instantaneous results, either big like you want it or small like you want it.

But maybe there’s some other type of animation that could add a little style and maybe even be somewhat helpful for quickly digesting the new view area…

I got to thinking that one of the main elements that’s universally important and the first aspect you might visually analyze is the general layout of the map. This is usually defined by walls and doors, so what if we just highlighted all of those after a zoom?

cogmind_map_zoom_animation_highlight

Wall highlighting shortly after a zoom state change. Zooming out lets the highlight last longer since it’s more relevant in that case, having added new content to your viewport.

I also considered highlighting other objects like machines and hostiles and/or something more, but figure it’s easy to go overboard and get back into distraction territory, so decided to stop there for now.

And that’s it, the map is now zoomable, and zoomable in style, and can be played that way. But it’s not yet ideal! Playing with a zoomed map introduces yet more challenges that we’re going to need some new QoL to help resolve next time…

This is the fourth in a five-part adventure through the process of putting all this together:

  • ✇Grid Sage Games
  • Adventures in Map Zooming, Part 3: ImplementationKyzrati
    Time to get serious! Last time I told you about my engine upgrade and the new “quads,” now it’s to put them to use. If you recall, for my initial Cogmind map zoom demo upon adding Quad support to REX, all I did was change one thing in the game: the map font size. The game doesn’t care about the engine side of things so it simply worked, or at least didn’t crash and we could easily see how it’d appear, despite of course numerous input and secondary display issues in some other windows. By just tw
     

Adventures in Map Zooming, Part 3: Implementation

Od: Kyzrati
7. Prosinec 2023 v 04:54

Time to get serious! Last time I told you about my engine upgrade and the new “quads,” now it’s to put them to use.

If you recall, for my initial Cogmind map zoom demo upon adding Quad support to REX, all I did was change one thing in the game: the map font size.

The game doesn’t care about the engine side of things so it simply worked, or at least didn’t crash and we could easily see how it’d appear, despite of course numerous input and secondary display issues in some other windows. By just tweaking a few more variables it would be easy to solve all those problems in order to purely have a consistently larger map view. Things get a lot more complex if we want to support both the regular map font and quads, not to mention the ability to swap them dynamically while the game is running.

But with the engine fundamentals solid and behind us, we’re ready to tackle those challenges.

Normally with UI feature implementation I’ll start by writing out a comprehensive list of everything that needs to be done, and any other elements I can think of which might be affected and therefore need testing and confirmation. While I drew up at least part of such a list like a good dev, this is one of those rarer cases where attempting to write a complete list ahead of time is probably not all that feasible or helpful, as it’s basically… the entire interface :P

With a change like this I would need to test pretty much everything, so instead of trying to be complete about it, I just noted areas of the code to be adjusted as I thought about them while working on fixing high-priority features, trying my best to finish off entire groups of related interface elements to speed up the process.

I started in the most important place, restoring the basic functionality required to speed up the rest of the implementation, like fixing map panning and cursor-map interactions. And realtime zoom toggling in order to easily compare and confirm that everything functions properly in both states.

And it was shortly after getting those bits operational that I discovered I wasn’t quite done with the engine xD

When examining the details of what still needed to be done in the map area itself, I realized that while zoomed in we’d probably also want to increase the font size of many types of text that appear over the map, especially object labels which are already integrated pretty tightly into the map coordinate and orientation systems.

cogmind_map_zoom_wip_map labels_small

Yeah these labels are not great like this, using the regular text size (ignore the fact that they’re not even pointing at the right objects here :P).

To maintain the proportionality of map-related text when zoomed in, we’d need… zoomed text. Oh no.

Back to REX

Last time I introduced the engine’s base cell size that fits individual text characters, wide glyphs for square map tiles, and the new “quad,” or four map tiles in order to enable a zoomed effect. To zoom text we’d need yet another type of glyph size, one that like the doubling of map tiles for quads (2×1 to 4×2) instead doubles text/base cell size (1×1 to 2×2!).

For me one of the first annoyances was what to call this new type, and I decided they’re probably best named after the number of base cells they occupy, meaning I had to go in and retroactively rename all the quad stuff to oct. Now our zoomed text glyphs can assume the name “quad.”

rex_terminal_grid_demo_quad_and_oct

A new member joins the REX glyph type family!

Because I had built a generalized system to simplify handling of both wide glyphs and octs (previously quads), inserting this new type was actually fairly easy (whew!).

rex_testing_console_quads_and_octs

REX again displaying operation of the newly renamed octs, and the new quads (the main new area of interest being the large olive-colored box).

Well, the initial implementation was fast, but on returning to Cogmind to apply it to map labels I found an issue…

cogmind_map_zoom_wip_label_text_shearing_bug

The text quads worked nicely in most places, but sometimes this happened. Perhaps we’ll just say this Recalibrator is corrupted and leave it at that? :P

It took a while to figure this one out, since I couldn’t quite tell if it was a Cogmind problem or a REX problem. This was particularly tricky to track down because it looked like an engine bug but also had a property that suggested it couldn’t be an engine bug, yet its other behavior pointed to it to being impossible to be a bug caused by the game itself… Anyway, a really weird confluence of situations managed to hide the real reason for a good hour. It had to do with a specific type of partial transparency of the new quads/octs, and of course it was caused by just one line of code in the engine.

Zoom Text Applications

Yay now we can have some large text on the map, too!

cogmind_map_zoom_wip_map labels_large

Revisiting the scene from earlier, this time with larger labels.

Beyond labels, I also enabled the on-map mode indicators to make use of quad text. To facilitate this (and by necessity for architectural reasons), I also refactored that part of the UI--they used to be drawn directly to the map at the end of its rendering process, but now they are a real window.

cogmind_map_zoom_item_large_text_label_category_mode_indicator

Cycling through item label categories, with the mode indicator visible at the top of the map view.

On-map popup alerts like low matter/core/etc. also got the zoomed text treatment, for one because they otherwise looks fairly small compared to everything else and would be even more likely to go unnoticed.

“ALERT” announcements are also larger now, almost too large when they include longer strings, but again having them remain at normal text size doesn’t seem ideal for getting noticed among the larger map cells. I might tweak those later when the UI undergoes more changes down the line, but for now they’re large.

I also decided to convert the program shutdown animation to the zoomed text, and unlike its other uses described above, this is the only instance in which it is used regardless of map zoom state.

cogmind_close_animation_new_strip_size_2

Cogmind’s program shutdown animation with larger central bar.

The MegaTODO

The UI is way more than just a handful of temporary popups though! Back to that growing list of challenges… well, technically most are not especially challenging, it was just a case of putting in all the necessary hours to scour the source for anything affected by the advent of new glyph types.

There were lots and lots (and lots) of alignment issues due to years of relative coordinate assumptions behind the fact that map spaces were always twice as wide as text, and both text and map spaces had the same height. Now map cells could be four times as wide as text, and twice as tall!

Most popup windows relative to something on the map needed to have their dynamic coordinates take into account additional calculations.

cogmind_cursor_hover_detection_debug_visualization

The old REX debugging visualization for examining UI z-depth and cursor hover focus came in quite handy for solving some of the more mysterious issues.

cogmind_debugging_console_index_structure_output

I also finally built an exporter for Cogmind’s window index structure to help track down some issues related to cursor input. In fact it also helped me find and resolve an unreported and difficult-to-notice bug in Cogmind’s UI that’s been in there since the very first version!

A chunk of the adaptation work actually required larger architectural rewrites, like the project of splitting the map interface into a trio of classes.

The first new class was purely to hold interface data that must be preserved during zoom events. Whenever a zoom occurs, the entire map interface is actually destroyed and recreated from scratch (far simpler than trying to convert everything over), but doing so would also lose some important info needed to facilitate various QoL features such as targeting history and resource alarm records. So data of that nature was moved to an external class to preserve it regardless of any zooming.

The second class is more interesting, a kind of container for other windows, those that are positioned over the map itself.

A number of windows such as on-map dialogue lines, combat logs, and achievement popups may need to be placed on any UI row within the map area, and these being organized under that window itself was never an issue before. But what happens when the map is zoomed such that a single “oct” occupies two rows? The map window’s grid coordinate system now no longer has any values corresponding to every odd row of the main interface, meaning its child windows cannot be placed on those rows.

So all of those map-related windows in which vertical alignment is important down the sub-row level needed a new parent window, kind of a fake alternate map window that always has a finer coordinate system regardless of the viewable map’s zoom state.

None of these informational windows are interactive, either, so this “finer map” window doesn’t need to capture mouse input and only has to occupy a 1×1 spot in the top-left corner of the map. It is a good example of an “unhidden yet transparent and therefore invisible” control window, allowing it to update normally and its children can both appear visible and use their parent as a coordinate reference (placing subwindows outside of a parent is fine).

The reason it must have an unhidden state is because that’s a prerequisite for actually updating itself and updating children, but is at the same time transparent because the window doesn’t actually want to display anything of its own.

cogmind_debugging_window_zlayer_data

Another useful debugging feature, the ability to show all windows that exist under a given cursor location and their z-depth. With the cursor in the top-left corner of the map there, it shows that there are two map classes overlapping at that location, the single-cell window container CMapFine, and the regular CMap class. The other values can show things like coordinates, indices, current colors, tile values, and any active animations at that point.

So yeah, long story short, this process wasn’t just about changing font settings and recalculating coordinates.

At this point all the heaviest lifting was done, but there was still an awful lot of residual work before map zooming could be called feature complete. I’ll share more on that next time.

This is the third in a five-part adventure through the process of putting all this together:

  • ✇Grid Sage Games
  • Adventures in Map Zooming, Part 2: Engine-level ArchitectureKyzrati
    Taking a different tack from last time, I decided that it would be worth getting really dirty with low-level engine work for the next attempt at map zooming. One of the main reasons we’d need to go this route if there’s ever to be hope of reasonable performance in software mode: Dirty rects. If we play by the engine rules we get to keep that functionality in its existing simple package, which generally means massive savings on CPU cycles. REX It had been a while since I’d done any serious tinker
     

Adventures in Map Zooming, Part 2: Engine-level Architecture

Od: Kyzrati
2. Prosinec 2023 v 04:42

Taking a different tack from last time, I decided that it would be worth getting really dirty with low-level engine work for the next attempt at map zooming. One of the main reasons we’d need to go this route if there’s ever to be hope of reasonable performance in software mode: Dirty rects. If we play by the engine rules we get to keep that functionality in its existing simple package, which generally means massive savings on CPU cycles.

REX

It had been a while since I’d done any serious tinkering in “Rogue Engine X” (REX), Cogmind’s underlying game engine. The acronym you might recognize from REXPaint, the engine’s ASCII painting software I built with it for my own use and later released (dang that’s been out for over 10 years now, too, with many of its own users).

I do very occasionally add a little REX functionality here and there to cater to Cogmind needs (or REXPaint for that matter), but it’s been mature for like 12 years so there’s never been any huge developments in that time.

My plans this time were for a pretty big one: Add a third type of glyph size.

To summarize, in traditional terminal style the display is just a uniform grid of monospace glyphs, each with a foreground and background color. Less traditional, and needed to produce Cogmind’s map with square spaces as opposed to rectangular ones more appropriate for text elements, two adjacent text cells can be occupied by a single “wide” glyph.

rex_terminal_grid_demo_narrow_vs_wide

The concept is simple, though does require that text characters take up about half the width that tiles do, which can be a little restrictive at certain sizes.

So the terminal has a base cell size, though doubling the width of that base size gives another wider type of glyph that can be used as well. (I also shared a larger diagram and some related ideas under the section “mixed fonts” in my Fonts in Roguelikes article.)

cogmind_terminal_grid_demo_narrow_vs_wide

Notice how the tiles in this Cogmind screenshot each occupy two cells, delineated by the partial grid overlay.

In practice it gets a little more complicated than one might imagine from the above description, because glyphs are not drawn directly and immediately to the visible console as shown, but instead first drawn to their own subconsole, and numerous subconsoles can overlap one another at different positions. This is great for organizing an interface, though when it comes time to merge everything to create the final view, partial overlapping means you can have pieces of larger glyphs showing through, etc.

The idea is to now add something even bigger than wide glyphs, but a key point is that whatever the new dimensions are they must still be a multiple of the base cell size. We have the regular base cell size used for text characters, a wide glyph size used for map tiles/characters, and what can we extrapolate comes next for a zoomed map if we want it to retain a square aspect ratio? Enter: the quad.

rex_terminal_grid_demo_quad

Big chonker tile has arrived.

Doubling the map tile size turns 1 wide tile into 4 (2×2), so while a wide cell occupies two base cells, a “quad” glyph would occupy 8 base cells, 4 in the first row and 4 in a second row. This behavior is similar to the wide glyph, just wider, while also expanding in a second dimension as well, so introducing it to the engine logic is, uh, fun :P

I had to rewrite most of the wide glyph support in order to add quads, but having wide support already there to reference was helpful, and merging everything under the same umbrella kept the overall complexity from expanding much.

To design and test quads I loaded up my old REX testing environment, which contains a random assortment of little test consoles and behavior samples to ensure everything is working properly. One of the important things to test beyond basic functionality (which itself took a little while to get down) is quad overlap with other consoles of different types, and screen edge overlaps.

rex_testing_console_quads

Been many years since I used this thing! It was put together as the engine features were coming together back in 2011 (my first post about it).

Some of the environment is animated/dynamic, though with quads it’s more about rendering and alignment issues, and confirming that underlying data values are correct.

I got pretty excited seeing the quads appearing normally each time a new test was devised and (finally) passed.

It’s official: REX has quad support!

Fonts

REX/Cogmind/REXPaint/etc use bitmap fonts, so if we’re adding a new glyph size that means we also need to accommodate that size in the font files.

While I allow quad fonts to be loaded from file, and that’s what I worked with for the initial implementation, it seemed unnecessary for our needs as far as providing this zooming feature in Cogmind, since our main goal is to simply allow the upscaling of map tiles. Therefore another part of this engine rework was to allow quad bitmaps to be generated as needed. Basically quads don’t have to exist until a given font set is actually set to be used, at which time the bitmap will be generated in memory by upscaling a specified source bitmap which has already been loaded.

Cogmind

Then there’s Cogmind over here not having any idea what’s about to hit it. Hm, what will the impact be? My first quick test was to simply switch the map font to a quad and just… see what happens!

Well for the most part it Just Works. Wow. No crashes, just big tiles.

There’s some obvious kinks like the fact that I didn’t even change the map view dimensions, causing the map view to also quadruple in pixel size and extend off behind the HUD and off screen, therefore “centering” Cogmind in the bottom right corner. That’s to be expected, along with other issues like console alignment and any other source code references assuming the map view is using wide-type glyphs.

But the important thing is that IT WORKS.

cogmind_zoom_map_first_sample

Cogmind’s very first use of the new “quad” glyph support added to REX.

That ain’t no mockup. Also because it’s playing by the engine rules there is zero performance hit from this feature. Zero.

You can see the UI jank--to record that I had to turn off autocentering and use the mouse for directional input, plus the misalignments and weird stuff in various locations (check out the items in the inventory xD). BUT IT WORKS.

There is clearly still a lot to do. Manually test swapping the font is literally all I’ve done so far on the Cogmind side of things--the size can’t yet be toggled dynamically, but before starting this whole adventure I did prove it could work in theory by testing whether the game would explode if I tried to destroy the entire main map interface and recreate it on the fly.

The disparity between the surrounding UI text size and map tile size when zoomed is kind of annoying--it’s not quite the same aesthetic, but if it means some people who otherwise might not be able to play could now do so, I guess that’s a good thing! Also again I find myself wondering what portion of potential players will find this sufficient since it doesn’t address text, but maybe in combination with the Terminus font it will work for most people. We’ll just have to find out.

While doing the latest map zoom experiments I also came up with an initial list of complementary feature ideas, those that could help blunt the negative impacts of having a much shorter view range than usual.

  • Cogmind may not necessarily be centered when zoomed, instead having the view gradually shift so that you can see further and further in your general direction of travel, out to your actual sight range. Cogmind’s unmodified sight range (16) while truly centered in a zoomed view would extend at most about 4 spaces out of view in the worst case scenario--a north/south direction, so Cogmind would generally be within that distance of the center unless sight range is further boosted. (East-West direction is less of an issue since the view is a horizontal rectangle for most people’s screens.) I can see this dynamic view positioning being fairly complicated to implement well, but a good formula and related behaviors there could save the player a lot of time that would otherwise be spent scrolling around.
  • The above feature is likely more appropriate for keyboard users, not mouse users who wouldn’t generally be happy with a map sometimes shifting to a different position under their cursor during successive movements. For that type of input it would be nice to have a way to quickly set your own relative centering position, depending on the direction from Cogmind you wish to see more of while moving or performing other actions.
  • Labels for important things, especially hostiles, that enter FOV but are not currently in view can be shown at the edge of the view in their direction. Or perhaps not the whole label, but more like the floating indicators that appear to denote an offscreen drone or Cogmind location. Cogmind already stops and labels new hostiles, so this would just be an extension of that feature to accommodate zoomed folks who want to have a little more info about the cause. Heck, maybe in temporarily pausing the action it could even shift the view over a bit to directly see the cause?
  • For new players, zooming the map could perhaps assume they would like everything to be larger or more readable, in which case maybe it’d be a good idea to also automatically switch the font to Terminus at the same time? Just a thought though, not a fan of this approach, and I think it won’t be nearly as relevant given the nature of future planned UI updates…
  • This one’s just fluff, but I can see feedback SFX and an optional very fast animation for the transition between zoom and standard view, for people who want to use both and do it in style :)

Lots of optional features out there, it appears, though exactly how many of them are actually useful, and more importantly can actually be implemented in a way that brings out that usefulness, remains to be seen.

Anyway, those are just some general notes for now, and I haven’t done any real playing with this feature active, but later once it’s actually built and not hacked together I’ll definitely be trying out some runs to see what about this setup irks me and if there’s anything I can do about it.

Although a zoomed map this isn’t the kind of feature I want to use, I imagine it could be useful to others, and look forward to seeing where development takes it. I’ve always loved working on UI to begin with :)

This is the second in a five-part adventure through the process of putting all this together:

❌
❌