Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines
(16 edits)

Don't know if this would be applicable for your system, or maybe you've already tried something like this, but I've been implementing my events using Callables (basically function references in Godot). I was annoyed by my original approach, which was to have the main event loop be responsible for event dispatch logic, and an Event object being sort of "instructions" to be read and executed. Having the Event object execute its own logic is surely an improvement but faces similar long-term complexity if it has to know everything or maintain derived types.

Callables kind of solve this complexity. The main event loop knows nothing, and is only responsible for running a Callable and awaiting a signal to proceed to the next one (sometimes have to wait for user actions like dialogue box dismissal, or signals like timer timeout and animation/tween finished), and the Callables themselves only dispatch event logic, and are not responsible for implementation.

For the most part, these Callables are just signal emitters that get appended to the event queue. Most are just like

EventBus.signal_name.emit.bind(args)

but you can use normal functions, lambdas, and I think closures should work if you need them. A complex event could be loosely composed of several general purpose Callables. The response to a signal is handled locally by individual systems that subscribe to it, stuff like UI or spawn managers, helping keep things decoupled.

I'm finding this approach very freeing and expressive, and also tidier than I expected. I sort of stumbled into it in my last jam game, staring down the path of cutscene god objects in horror, and then remembered a chat with another GBJammer about callbacks. My next game's cutscene system will build on this from the ground up, and hopefully result in lean, flexible code.

(+1)

Thanks for the suggestion! I need to look more at the codebase to actually see where this pattern would benefit this project. Because after an hour-ish of pondering I don't have a conclusion that's very useful.

In general, I tend to avoid Callables unless they're very simple (I use a Queue of Callables for the floating synergy text in my game). I've worked with too much clever code (including my own) that was too hard to debug or add to.

It sounds like your use case is solid. You can store Signals as variables and emit them (queue.pop_front().emit()) but it sounds like you probably want dynamic arguments so Callables sound like a great tool for your use case.

(2 edits)

Ohh I hadn't thought of storing signals like that, that's a good tip. 

You're right that too clever can smell. Too terse also, like big regexes and clever one-liners. Don't ask why I know that :)

Tough question, how to make something easy to debug and remain extensible. The Godot State Charts addon is a good example. It comes with a GUI debug control, so internally its organization is concrete enough to build tooling for. But it's also very flexible to use, I think because it's not highly abstracted from vanilla Godot.

I'd love to spend more time on tooling, speaking of writing code for myself. 

(+1)

I have been writing my own tooling because it's a good way to learn, but as I look toward actually creating finished games I'd like to look more into libraries like that. That State Chart library seems pretty cool, it's doing stuff I haven't thought of like adding editor plugins (and on a more minor note, I didn't know you could provide icons for Resources!)