[ANN] Cruise.jl v0.3.0 : Game engine kernel for julia

Hi everyone,
Happy to announce the new version of my engine, Cruise.jl. It has now been reduced to a kernel and gained several meaningful features that were absolutely worth the wait.

Installation

Stable version

(The package is still under registration, so use the development version for now.)

julia> ]add Cruise

Development version

julia> ]add https://github.com/Gesee-y/Cruise.jl

New Features

From game engine to kernel

Cruise itself doesn’t do much on its own. It manages events, systems, the game loop, logics, and lifecycles, but you can’t make a game with just the kernel.
To get windowing, input handling, rendering, etc., you add plugins on top of Cruise.

Plugin system

Cruise.jl now relies on a DAG as its core architecture. Your game is modeled as a set of systems linked together by unidirectional dependencies.
A subgraph of this system graph is called a plugin.

A plugin is a group of functionalities (similar to a module) that you import, then merge into the main system graph to extend your game.

Note
A plugin is different from a module. A module doesn’t need to be part of a game’s lifecycle to work, while a plugin must be inserted into the plugin graph.

This design gives you optimal parallelism with just a topological sort, while keeping overhead extremely low in typical game scenarios.

The worst case is when the graph has a high dependency density. A near-complete graph leads to almost sequential execution, terrible for parallel scheduling.

Here’s a plot showing the median overhead per system depending on the number of systems and dependency density:

This architecture is extremely flexible. You can add or remove systems whenever you want. The DAG only orchestrates your systems, it doesn’t force any specific game structure.
It’s also great for contributors: plugins can be tiny 50–200 line packages that add one specific feature.

Cruise is one of the first engine to use a DAG as his core architecture (not as a feature in another architecture like ECS). This architecture has already showed his value projects like Apache Airflow or cryptocurrency where it massively updated the scalability of these infrastructure while reducing cost.

Your game code

A typical game relying on the default architecture now looks like this:

## Typical game setup

using Cruise
using PluginA, PluginB # And so on

app = CruiseApp() # The main game app

# Add plugins to the app lifecycle
merge_plugin!(app, PLUGINA_INSTANCE)
merge_plugin!(app, PLUGINB_INSTANCE)

logic_id1 = @gamelogic MyLogic1 begin
    # My code
end

logic_id2 = @gamelogic MyLogic2 begin
    # Another code
end

# MyLogic2 depends on MyLogic1, runs after it, and has access to it
add_dependency!(app.plugins, logic_id1, logic_id2)

# This loop will allow all the other systems to run.
# It becomes a system in the graph
# and always runs on the main thread.
@gameloop begin
    # Some code
end

To dive deeper into plugins, read this documentation.
For game logic internals, read this.

Roadmap

Future updates about Cruise will focus on plugins, extending the kernel until it becomes a full game engine.

Demo

You can check out this demo repo:
https://github.com/Gesee-y/Cruise-demos
Clone it and try the small demo I made.

To run it, you will need these experimental plugins:

julia> ]add AssetCrates
julia> ]add https://github.com/Gesee-y/SDLOutdoors.jl
julia> ]add https://github.com/Gesee-y/SDLHorizons.jl

Also check out the documentation for Outdoors.jl and CRHorizons.jl.
They’re integrated into the Cruise core and re-exported. Reading their docs will make it clear why the demo needs those packages.

Contribution

If you want to contribute, feel free to write plugins, they’re small packages you can build in a day.
Each plugin should have a clear purpose and do one thing well.

If you find a bug or odd behavior, open an issue.

Enjoy Cruise!

2 Likes