Skip to content

Latest commit

 

History

History
102 lines (55 loc) · 5.91 KB

README.md

File metadata and controls

102 lines (55 loc) · 5.91 KB

ecst

Experimental & work-in-progress C++14 multithreaded compile-time Entity-Component-System header-only library.

stability license gratipay badge.cpp

Overview

Successful development of complex real-time applications and games requires a flexible and efficient entity management system. As a project becomes more intricate, it’s critical to find an elegant way to compose objects in order to prevent code repetition, improve modularity and open up powerful optimization possibilities.

The Entity-Component-System architectural pattern was designed to achieve the aforementioned benefits, by separating data from logic.

  • Entities can be composed of small, reusable, and generic components.

  • Components can be stored in contiguous memory areas, thus improving data locality and cache- friendliness.

  • Application logic can be easily parallelized and abstracted away from the objects themselves and their storage policies.

  • The state of the application can be serialized and shared over the network with less effort.

  • A more modular, generic and easily-testable codebase.

"ecst" was developed as my BCS graduation project.


Getting started


More information


Terminology

  • Entities: defined by Adam Martin (see thesis) as “fundamental conceptual building blocks” of a system, which represent concrete application ob-jects. They have no application-specific data or logic.

  • Components: small, reusable, types that compose entities. Again, citing Adam Martin in (see thesis), a component type “labels an entity as possess-ing a particular aspect”. Components store data but do not contain any logic.

  • Systems: providers of implementation logic for entities possessing a specific set of component types.

  • Outer parallelism: term used in ECST which defines the concept of running multiple systems that do not depend on each other in parallel. Its implementation details will be analyzed in Chapter 10 (see thesis). Conceptually, an implicit directed acyclic graph is created at compile-time thanks to the knowledge of system dependencies. The execution of the implicit DAG is handled by a system scheduler type specified during settings definition.

  • Inner parallelism: other that running separate systems in parallel, ECST supports splitting a single system into multiple sub-tasks, which can be executed on separate threads. Many systems, such as the ones that represent functionally pure com- putations, do not contain side-effects that modify their own state or that define interactions between the subscribed entities: these are prime examples of “embarrassingly parallel” computations.


FAQ

  • "Where can I find documentation for the API?"

  • "Can we have components that aren't default constructible?"

    • This has come up before in the past. The answer is no - see issue #8.
  • "I'm trying to read/write to/from my component, but I'm getting a compilation error. What is happening?"

    • Systems need to know at compile-time which component types they will access and how (read-only or write access). This has to be specified when defining system signatures. See issue #4 for more info.
  • "Is it possible to iterate over the components attached to entities, without being inside of a system's process function?"

  • "How do control whether my system runs in parallel, or as a single thread?"

    • Context-wide inner parallelism must be enabled by calling allow_inner_parallelism() in order to allow systems to be split in multiple sub-tasks. Inner parallelism strategies can be customized and composed at compile-time for particular systems, during system signature definition.
  • "What is the difference between making my system single-threaded vs disabling inner paralellism?"

    • Disabling inner parallelism prevents all systems to be split in multiple sub-tasks, regardless of their inner parallelism strategy. Making a system single-threaded prevents only that system from being split in multiple sub-tasks: this may be necessary for systems that maintain data-structures or that rely on iterating over all entities in the same thread.