Giter Site home page Giter Site logo

phisko / kengine Goto Github PK

View Code? Open in Web Editor NEW
600.0 26.0 32.0 66.01 MB

Game engine with an Entity-Component-System (ECS) architecture. Focus on ease-of-use, runtime extensibility and compile-time type safety.

License: MIT License

CMake 4.76% C++ 90.69% Python 1.96% Batchfile 0.01% GLSL 0.46% C# 0.19% SWIG 1.21% C 0.72% Lua 0.01%
entity entity-component lua-script engine game gameobject ecs entity-component-system game-engine game-development

kengine's Introduction

Kengine

tests

The Koala engine is a game engine entirely implemented as an Entity Component System (ECS).

The engine is based on EnTT. Integration with other pieces of software using EnTT should be straightforward. This documentation assumes at least basic knowledge of EnTT and its terminology (entity, registry, handle...).

koala

Example

The example project showcases some of the core features. It should give you an idea of what the engine's support for reflection and runtime extensibility have to offer.

Installation

The engine uses Git submodules, and should therefore be cloned recursively with

git clone https://github.com/phisko/kengine --recursive

The engine has been tested on Windows with MSVC and MinGW.

Linux compilation works with GCC. At the time of writing, clang doesn't support C++ 20's constexpr std::string and std::vector.

C++ version

The engine requires a C++20 compiler.

Foreword

The engine started as a passion/student project in 2016-17. My friends/colleagues and I had a go at implementing an ECS from the ground up. We wanted absolute type safety and clarity, and while we'd already toyed with template metaprogramming, this was a chance for us to learn more about it.

Once the core ECS was working, the engine turned into a playground to learn more about game development. I learned OpenGL rendering, how to use navmeshes with Recast/Detour, setup physics with Bullet... All the while developing useful helpers and runtime reflection facilities compatible with an ECS.

After now over 5 years working on the engine, I realized the core ECS itself is no longer the focus of this project. Other libraries, and EnTT in particular, offers a very similar API, with much more advanced features. So I took the time to completely gut out the internal ECS and replace it with EnTT. All features remain the same, and this will give me more time to work on useful helpers, which can work with other EnTT projects.

Reflection

Many parts of the engine (such as the scripting systems or the ImGui entity editor) make use of putils' reflection API. Most of the components in the following samples are thus defined as reflectible.

Layout

The engine code is organized in three categories:

  • components: hold data or functions (see Component categories below)
  • systems: entities that implement an engine feature
  • helpers: functions to simplify component manipulation

Note that systems aren't objects of a specific class. Systems are simply entities with an execute component (or anything else they need to do their work). The entity then lives in the registry with the rest of the game state. This lets users introspect systems or add behavior to them just like any other entity.

These three categories are split into various libraries, e.g.:

Note that some libraries contain sub-libraries, e.g.:

The CMake section goes into more detail of how to work with these libraries.

Component categories

The engine comes with a (fairly large) number of pre-built components that can be used to bootstrap a game, or simply as examples that you can base your own implementations upon.

These components fit into three categories:

Data components

Data components hold data about their entity.

Data components are what first comes to mind when thinking of a component, such as a transform or a name.

Data components can sometimes hold functions:

  • input::handler lets an entity hold callbacks to be called whenever an input event occurs
  • collision lets an entity be notified when it collides with another

Function components

Function components hold functions to query, alter, or notify their entity.

Function components are simply holders for functors that can be attached as components to entities. This mechanic can be used to:

  • attach behaviors to entities: execute is called by the main loop each frame
  • register callbacks for system-wide events: on_click is called whenever the user clicks the entity
  • provide new functionality that is implemented in a specific system: query_position is typically implemented by a physics system

Function components are types that inherit from base_function, giving it the function signature as a template parameter.

To call a function component, one can use its operator() or its call function.

entt::registry r;
const auto e = r.create();
r.emplace<main_loop::execute>(e,
    [](float delta_time) { std::cout << "Yay!" << std::endl; }
);

const auto & execute = r.get<main_loop::execute>(e); // Get the function
execute(0.f); // Call it with its parameters
execute.call(42.f); // Alternatively

Meta components

Meta components are components for components.

The engine uses "type entities" to hold information about the various components in use. Each type entity represents a different component type, and can be used to query the component's properties at runtime.

Meta components are attached to these "type entities", and hold a generic function's implementation for that specific type. Because they hold functions, they are very similar to function components.

An example makes this clearer: meta::imgui::edit is a meta component that, when called, will draw its "parent component"'s properties using ImGui for the given entity. The following code will display a window to edit e's name component.

// r is a registry with the "type entity" for `name` already setup

const auto e = r.create();
r.emplace<core::name>(e);

const auto type_entity = type_helper::get_type_entity<core::name>(r);
const auto & edit = r.get<meta::imgui::edit>(type_entity);
if (ImGui::Begin("Edit name"))
    edit({ r, e });
ImGui::End();

If you generalize this, you can edit all the components for an entity with the following code:

// r is a registry with the "type entities" for all used components already setup
// e is an entity with an unknown set of components

if (ImGui::Begin("Edit entity"))
    for (const auto & [type_entity, edit] : r.view<meta::imgui::edit>()) {
        edit({ r, e });
    }
ImGui::End();

Libraries

See CMake for instructions on how to enable each library.

Scripts

A generate_type_registration Python script is provided, which can be used to generate C++ files containing functions that will register a set of given types with the engine.

This is absolutely not mandatory.

CMake

The engine uses CMake as a build system. A custom framework has been put in place to simplify the creation of libraries. The root CMakeLists iterates over sub-directories and automatically adds them as libraries if they match a few conditions.

A base kengine interface library is created that links against all enabled libraries, so clients may simply link against that.

Options

The following CMake options are exposed.

KENGINE_TESTS

Compiles test executables for the libraries that implement tests.

KENGINE_NDEBUG

Disables debug code.

KENGINE_TYPE_REGISTRATION

Will generate type registration code for engine types. This is central to many of the engine's reflection capabilities, as it provides the implementation for meta components.

KENGINE_GENERATE_REFLECTION

Will update the reflection headers for engine types. These are pre-generated, so unless you're modifying the engine's source code you shouldn't need to enable this.

Libraries

All libraries are disabled by default, to avoid building unwanted dependencies. Each library can be enabled individually by setting its CMake option to ON. See Library naming for the option name.

Alternatively, all libraries can be enabled with the KENGINE_ALL_SYSTEMS option.

Note that sub-libraries need their parent library to be enabled: kengine_imgui_entity_editor requires kengine_imgui.

Library naming

Libraries are named depending on their relative path to the engine root. The slashes in the path are simply replaced by underscores, e.g.:

These names are:

  • used when linking against a specific library
  • used for the CMake option to enable a library (e.g. KENGINE_CORE for kengine_core)
  • used for a library's internal export macro (e.g. KENGINE_CORE_EXPORT for kengine_core)

It is possible to test for the existence of a library during compilation thanks to C++ define macros. These have the same name as the CMake options, e.g.:

#ifdef KENGINE_CORE
// The kengine_core library exists
#endif

Third-party dependencies

Some libraries make use of vcpkg for dependency management.

Library creation

Since libraries are automatically detected by the root CMakeLists.txt, creating a new library is fairly easy.

Libraries automatically link against kengine_core, since it provides helpers that should be used by all libraries (such as the log_helper and the profiling_helper).

Sub-libraries automatically link against their parent. For instance, kengine_imgui_entity_editor automatically links against kengine_imgui.

Sources

Source files from a library's helpers and systems subdirectories are automatically added. If none are found, the library will be a CMake interface library.

Type registration and reflection code generation

Type registration and reflection code may be automatically generated for components. By default, all headers in a library's data and functions subdirectories will be passed to the generation scripts.

Similarly to source files, if any *.tests.cpp files are found in a library's helpers/tests or systems/tests subdirectories, a GoogleTest executable will be automatically added.

Custom CMakeLists.txt

Basic libraries shouldn't need their own CMakeLists.txt, since their source files will be automatically. However, if a library needs custom behavior (e.g. to add extra sources or to link against a third-party library), it may add its own CMakeLists.txt. That CMakeLists.txt will be called after the call to add_library.

The following variables and functions are defined before calling the CMakeLists.txt:

  • kengine_library_name: the library's name
  • kengine_library_tests_name: the library's GoogleTest target's name
  • link_type: the library's link type (PUBLIC or INTERFACE, depending on whether sources were found or not)
  • kengine_library_link_public_libraries(libraries): links against other libraries (publicly)
  • kengine_library_link_private_libraries(libraries): links against other libraries (privately)
  • register_types_from_headers(headers): adds headers for which type registration and reflection headers may be generated
  • subdirectory_is_not_kengine_library(path): indicates to the root CMakeLists.txt that it shouldn't process path as a kengine library

kengine's People

Contributors

phisko 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  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  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  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  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

kengine's Issues

Example lua script error

When running the bundled example/main.cpp I get the following error spammed in the terminal:

[LuaSystem] Error in 'scripts/test.lua': lua: error: scripts/test.lua:2: attempt to call a nil value (field 'new')

I am using Lua 5.3 on Arch linux.

cmake configure failed on MSYS2 MINGW64

$ cmake ..
-- Building for: Ninja
-- The C compiler identification is GNU 12.2.0
-- The CXX compiler identification is GNU 12.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/msys64/mingw64/bin/cc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/msys64/mingw64/bin/c++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Performing Test COMPILER_HAS_DEPRECATED_ATTR
-- Performing Test COMPILER_HAS_DEPRECATED_ATTR - Success
CMake Error at putils/CMakeLists.txt:49 (find_package):
  Could not find a package configuration file provided by "scn" with any of
  the following names:

    scnConfig.cmake
    scn-config.cmake

  Add the installation prefix of "scn" to CMAKE_PREFIX_PATH or set "scn_DIR"
  to a directory containing one of the above files.  If "scn" provides a
  separate development package or SDK, be sure it has been installed.


-- Configuring incomplete, errors occurred!

Note: the repo was cloned with --recursive as the guide said.

Compile error when compiling with clang/gcc

third_party/kengine/EntityManager.hpp:3:10: fatal error: 'execution' file not found
#include <execution>
         ^~~~~~~~~~~
1 error generated.

The latest versions of both libc++ and libstdc++ do not include this header yet, so kengine cannot be compiled with GCC or Clang at the moment.

fail to clone recursive

Please check the module path to putils.

I get Permission denied error, if I try to clone kengine recursive,

$ git clone --recurse-submodules https://github.com/phisko/kengine.git
Cloning into 'kengine'...
remote: Enumerating objects: 46, done.
remote: Counting objects: 100% (46/46), done.
remote: Compressing objects: 100% (43/43), done.
remote: Total 4620 (delta 9), reused 18 (delta 2), pack-reused 4574
Receiving objects: 100% (4620/4620), 12.64 MiB | 2.96 MiB/s, done.
Resolving deltas: 100% (2515/2515), done.
Submodule 'putils' ([email protected]:phisko/putils) registered for path 'putils'
Cloning into 'D:/src/kengine/putils'...
[email protected]: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
fatal: clone of '[email protected]:phisko/putils' into submodule path 'D:/src/kengine/putils' failed
Failed to clone 'putils'. Retry scheduled
Cloning into 'D:/src/kengine/putils'...
[email protected]: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
fatal: clone of '[email protected]:phisko/putils' into submodule path 'D:/src/kengine/putils' failed
Failed to clone 'putils' a second time, aborting

Regards.
Sven

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.