Skip to content
MatVeiQaaa edited this page Dec 17, 2024 · 8 revisions

Genode

Genode (Game EngiNe On DEmand) is a game framework that is written in C++17 and built on top of SFML V3.

As the name suggests, this project is on the contrary side of other common engines or frameworks; initially, it is not built for the general use case. It began with the idea that it would only evolve or change to satisfy the demands of my own game development needs, which favor certain conventions, patterns, and even my own personal preferences.

Getting Started

Integration

The easiest way to use Genode in the current form is to drop entire src and include directly into your SFML game source tree. No particular macros or configuration are required.

Alternatively, you can include the CMake project into your project or build the library statically via CMake command, linking it into your project:

cmake -B ./build -DCMAKE_BUILD_TYPE=Release
cmake --build ./build --config Release

Genode requires sfml-system, sfml-audio, sfml-graphics and sfml-window. Unlike SFML, each module in Genode is not designed to be compiled or distributed separately. As such, omitting one of those dependencies may result in a compilation error (it is untested)

Tutorials

The following articles introduce the modules and teach you to build your game with Genode. It is strongly recommended to read those articles in the following order, from low- to high-levels of abstraction, so you can decide the right amount of abstraction and become familiar with the layers of implementations that you wish to optimize later:

  1. Entities
  2. Tasks
  3. Graphics
  4. System
  5. IO
  6. Scene Graph

Quick Start

Genode primarily uses SceneGraph as its building block. However, you can always omit some of these components and roll out your implementation. This could be useful if you're particular about performance and/or implementation in specific areas. See Only pay for what you use for more details.

Typically, you will need to implement these 2 classes:

  • Gx::Application
  • Gx::Scene

Gx::Application

This class represents your application class; it provides some simple lifecycle events, such as Boot and Shutdown, which will be called when the application is about to start and exit, respectively. Here's how application class would typically look like:

Important

Gx::Application is designed to work with a single thread for polling inputs and rendering; it also only supports a single render window at a time. If this does not fit your use case, use Gx::SceneDirector directly or manage Gx::Scene objects manually

#include <Genode/System/Application.hpp>
#include "MyAwesomeScene.hpp"

class MyAwesomeGame : public Gx::Application
{
public:
    // Application constructor
    MyAwesomeGame(std::string title, const sf::VideoMode& mode, const sf::View& view, const bool fullScreen, const sf::ContextSettings& settings) :
        Gx::Application(std::move(title), mode, view, fullScreen, settings)
    {
    }

protected:
    void Boot() override 
    {
        // Initialize your game here.
        // For example, you can load global resources, load game config, register scene loaders, etc.
        // You should also present your initial scene here

        GetSceneDirector().Present<MyAwesomeScene>();
    }

    int Shutdown() override
    {
        // Called when the game is about to close. Return application exit code here
        return 0;
    }
}

Gx::Scene

Scene (also known as State or Page) represents a virtual environment comprising a collection of node objects. A game typically has multiple scenes, such as the Main Menu, Inventory, and Battle scenes.

In Genode, every object in the SceneGraph is made of a Gx::Node object, which is a class that represents an object inside the scene. In fact, the Gx::Scene class itself is made of Gx::Node. Each of node objects can have other nodes as children. This allows you to build a complex object hierarchy inside the scene.

For this purpose, many SFML drawable entities such as sf::Sprite, sf::Text and sf::Shape are re-implemented to work with Gx::Node; see Drawable re-implementation for more details.

Here's how a Gx::Scene implementation is typically written:

#include <Genode/SceneGraph/Scene.hpp>
#include <Genode/Graphics/Sprite.hpp>

class MyAwesomeScene : public Gx::Scene
{
public:
    // Avoid performing complex initialization in the constructor.
    // This is because many scenes' contexts are not initialized when the object is newly constructed.
    MyAwesomeScene() = default;

    // Similar advice also applies to the destructor.
    ~MyAwesomeScene() = default;

protected:
    // Instead, you should do initialization and clean-up in `Initialize` and `Finalize` respectively

    void Initialize() override
    {
        // Initialize texture and sprite
        m_texture = sf::Texture("./some/path/to/texture.png");
        m_sprite  = Gx::Sprite(m_texture);

        // Add sprite into the scene
        // You need to ensure that textures and sprites are alive when they are still a part of the active scene
        AddChild(m_sprite);
    }

    void Finalize() override
    {
        // Do clean-up here if necessary
    }

private:
    sf::Texture m_texture;
    Gx::Sprite m_sprite;
}

Running your application

Running your game is straightforward: simply instantiate your application with the required parameters and call Start() function to start the game.

#include "MyAwesomeGame.hpp"

int main(int argc , char** argv)
{
    auto myGame = MyAwesomeGame(
        "My Awesome Game",            // Title bar string
        sf::VideoMode({1920, 1080}), // sf::VideoMode to initialize the window
        sf::View({0, 0, 1920, 1080}), // Default view of the application
        false                         // Fullscreen mode
    );

    // Start is a thread blocking function which returns the exit code of the application, propagated from `Shutdown()`
    return myGame.Start();
}
Clone this wiki locally