Signs of Danger has both online and local co-op.
Remote players are controlled remotely (duh), but I gotta support multiple gamepads for local players, with an easy drop-in/drop-out flow.
Still, when playing singleplayer, you should be able to seamlessly swap between keyboard & mouse to any gamepad controller and back again.
The Problem
If you only support one local player you have it easy: when John presses a button on an input device (keyboard or gamepad), that becomes the active device - and then you can use the active device to show in-game hints like Press (X) to interact.
But in a local-multiplayer game, it's suddenly more complicated: how do you know if it's John pressing a button, or his mate Tim who just rocked up and wants to play?
Attempt 1: Start to Join
Okay, no problem: Tim presses the Start button on his gamepad, and can press Start to leave (for necessary pizza runs).
But I found that players kept pressing Start when trying to open their Signcrafting, which would do horrible things:
- If new-player-Tim presses
Start, his character commits suicide and - because there's only a "single local player" in-game - his device gets reassigned to John. - Now Tim and John are both controlling John's character - awkward.
- And worse, if John then presses
Start, John's device would get reassigned to Tim's old character!
Attempt 2: Manage Players Menu
For a while I got by with having players physically swap gamepad as needed, but I needed a proper fix: players manage which device is assigned to each character via a dedicated menu.
Should be straightforward, right? I've seen these before - something like this:
Makin Menus
Except, err.. I've somehow lasted 2 years without adding any real menus. 1
And worse than that: since Signs of Danger is written in a wholly custom engine, I didn't even have a way to build a menu.
Every Rust UI (user interface) library I could find was mouse & keyboard oriented - no support for gamepads and no clear paths to adding that either.
So I shaved what is possibly my biggest yak yet and wrote my own gamepad-compatible UI toolkit: 2
It worked - barely.
I cleaned up the visuals, added animations,3 and built a settings menu in it:
Actually getting all that working was a right pain.
So I also added some visualizations of what was happening with the layout:
Along the way I redid how I draw text4 to support wrapping and measuring text accurately, added support for translating interfaces to different languages, and ported the splash screen and player HUD (healthbars, ability display, etc) over to the same UI system. 5
Aside: having fun reading? Don't forget to wishlist Signs of Danger on Steam!
Now why did I start down this path again?
Oh yeah, I wanted a menu for swapping devices between players:
Of course in online multiplayer, only your local player characters will show up in the list there.
Attempt 3: Return of the Drop-in
This worked great - buuut, when I'm demoing the game at conventions I don't want to interrupt players' by pausing the game.
So I added special-case "hold Start to drop in or out" functionality to cater for that:
Hmm.. that also addresses the problem of accidentally joining or leaving. Guess I could have done that from the start and saved myself about 2 weeks of work.
Oh well, I needed to figure out menus at some point anyway.
Playable web build
You can play with these fancy menus here. I am sure there are still bugs - please report them! .
Known issues:
- I have no idea if touch controls are still working, sorry readers-on-mobile. 6
- The orange focus brackets in the settings menu aren't as visible as they should be, and clip with the scrollbar.
- At certain screen-sizes, there's terrible lighting bleed at edges. I broke some stuff when I added zooming in and out when there are multiple local players - might talk about that another time!
- Single atoms disappear and re-appear sometimes, most noticeable with flammable gas. It's a rendering glitch caused by a big optimization I haven't quite finished - also a topic for another time!
Except for egui, but that's only for debug menus.
I was using Macroquad's built-in text rendering before, which had an annoying texture corruption bug. Now I'm using Cosmic Text - I took what Glyphon does for WGPU and adapted it to work with Macroquad's OpenGL-based rendering.
I'm still debating whether it's wise to port the Signcrafting tree interface over to my new UI framework or not - it inherently has its own layout algorithm, special behaviour for how to navigate between nodes in the tree, etc.
My custom UI library is modeled on the immutable-with-message-passing architecture of Iced (for the web devs: a bit like Elm or Redux), with an immediate-mode interface backed by retained state similar React.
I'm using taffy to get support for full CSS box-model semantics which, to be perfectly honest, is total overkill. And as a CSS noob guru I struggle with it sometimes, but I take some comfort in knowing that it's flexible enough to handle basically any layout I could dream up.
Animations are powered by an approach similar to that of lilt, except easing functions are taken from bevy_math - I was already using the latter's easing functions so seemed neater to do that. I do recommend the lilt crate though - the core idea behind its API is very nice.
It's late and I got 5 hours sleep last night so I can't be bothered checking it right now! Also am working towards getting the playable desktop build up on itch.io to download so then the web build with its touch controls will be a lot less relevant anyway.
