Giter Club home page Giter Club logo

sdk-core's Introduction

Trollworks SDK Core

tests license version

Trollworks is an (unfinished) game engine in C++ I've been working on for a while.

This repository contains the basis of the SDK, as a header-only C++23 library. It is built around EnTT, an ECS library.

This library provides:

  • a game loop abstraction (with fixed updates, updates and late updates)
  • some EnTT utilities as singletons:
    • asset manager
    • event dispatcher
    • scene manager
    • job manager
  • a UI component framework inspired by React to help organize immediate-mode UI code
  • coroutines inspired by Unity coroutines

List of backends:

Name 2D/3D URL
SDL2 2D https://github.com/trollworks/sdk-backend-sdl
raylib 2D https://github.com/trollworks/sdk-backend-raylib (TODO)
glfw 3D https://github.com/trollworks/sdk-backend-glfw (TODO)

Installation

Clone the repository in your project (don't forget to pull the submodules) and add the include/ folder to your include paths.

Or, if you are using Shipp, add to your dependencies:

{
  "dependencies": [
    {
      "name": "trollworks-sdk-core",
      "url": "https://github.com/trollworks/sdk-core.git",
      "version": "v0.2.0"
    }
  ]
}

Usage

Game loop

#include <trollworks.hpp>

struct game_state {
  // ...
};

struct listener {
  game_state& gs;

  void on_setup(tw::controlflow& cf) {
    // create window and opengl context, load resources
  }

  void on_teardown() {
    // free resources, opengl context and window
  }

  void on_frame_begin(tw::controlflow& cf) {
    // process window events and inputs
  }

  void on_fixed_update(float delta_time, tw::controlflow& cf) {
    // physics updates
  }

  void on_update(float delta_time, tw::controlflow& cf) {
    // game logic
  }

  void on_late_update(float delta_time, tw::controlflow& cf) {
    // more game logic
  }

  void on_render() {
    // render graphics
  }

  void on_frame_end(tw::controlflow& cf) {
    // ...
  }
};

int main() {
  auto gs = game_state{};
  auto l = listener{.gs = gs};
  auto loop = tw::game_loop{};

  loop
    .with_fps(60)
    .with_ups(50)
    .on_setup<&listener::on_setup>(l)
    .on_teardown<&listener::on_teardown>(l)
    .on_frame_begin<&listener::on_frame_begin>(l)
    .on_frame_end<&listener::on_frame_end>(l)
    .on_update<&listener::on_update>(l)
    .on_fixed_update<&listener::on_fixed_update>(l)
    .on_late_update<&listener::on_late_update>(l)
    .on_render<&listener::on_render>(l)
    .run();

  return 0;
}

NB: A concept backend_trait is also provided to facilitate pluging in a specific window/event/render system (SDL, raylib, glfw, ...):

struct sdl_backend {
  SDL_Window *window;
  SDL_Renderer *renderer;

  void setup(tw::controlflow& cf) {
    // create window, opengl context, ...
  }

  void teardown() {
    // free opengl context and window
  }

  void poll_events(tw::controlflow& cf) {
    // process event, for example with SDL:
    SDL_Event evt;

    while (SDL_PollEvents(&evt)) {
      switch (evt.type) {
        case SDL_QUIT:
          cf = tw::controlflow::exit;
          break;

        default:
          // ...
          break;
      }
    }
  }

  void render() {
    // get current scene's entity registry
    auto& registry = tw::scene_manager::main().registry();

    SDL_RenderClear(renderer);

    // iterate over your entities to draw them

    // render UI with imgui, or nuklear, or other

    SDL_RenderPresent(renderer);
  }
};

int main() {
  auto back = sdl_backend{};
  auto loop = tw::game_loop{};

  loop
    .with_fps(60)
    .with_ups(50)
    .with_backend(back)
    .run();

  return 0;
}

Coroutines

First, create your coroutine function:

tw::coroutine count(int n) {
  for (auto i = 0; i < n; i++) {
    co_yield tw::coroutine::none{};
  }
}

Then, in your game loop:

tw::coroutine_manager::main().start_coroutine(count(5));

Coroutines are run after the update hook and before the late update hook.

Coroutines can also be chained, like in Unity:

tw::coroutine count2(int a, int b) {
  co_yield count(a);
  co_yield count(b);
}

Scene management

A scene is a class providing 2 methods (load and unload):

class my_scene final : public tw::scene {
  public:
    virtual void load(entt::registry& registry) override {
      // create entities and components
    }

    virtual void unload(entt::registry& registry) override {
      // destroy entities and components
    }
};

Then:

tw::scene_manager::main().load(my_scene{});

Assets

The asset manager provides a singleton per asset type. The singleton is simply a resource cache from EnTT, for more information consult this page.

struct my_asset {
  // ...

  struct loader_type {
    using result_type = std::shared_ptr<my_asset>;

    result_type operator()(/* ... */) const {
      // ...
    }
  };
};

auto& cache = tw::asset_manager<my_asset>::cache();

Messaging

The message bus is simply a singleton returning an entt::dispatcher. For more information, please consult this page.

auto& dispatcher = tw::message_bus::main();

Queued messages are dispatched after the late update hook an before rendering.

Jobs

The job manager is simply a singleton returing an entt::basic_scheduler<float>. For more information, please consult this page.

UI framework

using namespace entt::literals;

struct foo {
  void operator()(tw::ui::hooks& h) {
    auto& local_state = h.use_state<int>(0);

    // gui code
  }
};

struct bar {
  void operator()(tw::ui::hooks& h) {
    auto& local_state = h.use_state<float>(0.0f);

    // gui code
  }
};

struct root {
  bool condition;

  void operator()(tw::ui::hooks& h) {
    h.render<foo>("a"_hs);

    if (condition) {
      h.render<foo>("b"_hs);
    }

    h.render<bar>("c"_hs);
  }
};

Then in your render hook:

tw::ui::h<root>("root"_hs, root{.condition = true});

The ids given to the UI hooks must be unique within the component, not globally.

License

This project is released under the terms of the MIT License.

sdk-core's People

Contributors

linkdd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.