Skip to content

porpoisepor/ecst

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ecst

Experimental & work-in-progress C++14 multithreaded compile-time entity-component-system library.

Slides available on SuperV1234/cppnow2016. (The repository may still be private at the moment.)


// Include "ECST".
#include <ecst.hpp>

// Define some components.
namespace c
{
    // Components are simple classes, usually POD structs. There is no need
    // for components to derive from a "base component" class or to satisfy
    // a particular interface.

    struct position
    {
        vec2f _v;
    };

    struct velocity
    {
        vec2f _v;
    };

    struct acceleration
    {
        vec2f _v;
    };
}

// Define component tags.
namespace ct
{
    namespace sc = ecst::signature::component;
    
    constexpr auto position = sc::tag<c::position>;
    constexpr auto velocity = sc::tag<c::velocity>;
    constexpr auto acceleration = sc::tag<c::acceleration>;
}

// Define some systems.
namespace s
{
    // Systems are simple classes as well, that do not need to satisfy any
    // particular interface. They can store data and have any method the
    // user desires.

    // This system accelerates the subscribed particles.
    struct acceleration
    {
        // The `process` method is not hardcoded or specially recognized by
        // ECST in any way. Using a lambda in the execution code, we can
        // tell an ECST context to execute a particular method (also
        // forwarding extra arguments to it).

        // The `data` parameter is a proxy object generated by the system
        // execution strategy that abstracts away the eventual underlying
        // parallelism.

        template <typename TData>
        void process(ft dt, TData& data)
        {
            // Notice that the code below does not know anything about the
            // multithreading strategy employed by the system: the same
            // syntax works with any kind (or lack) of parallel execution.
            data.for_entities([&](auto eid)
                {
                    auto& v = data.get(ct::velocity, eid)._v;
                    const auto& a = data.get(ct::acceleration, eid)._v;

                    v += a * dt;
                });
        }
    };

    // This system moves the subscribed particles.
    struct velocity
    {
        template <typename TData>
        void process(ft dt, TData& data)
        {
            data.for_entities([&](auto eid)
                {
                    auto& p = data.get(ct::position, eid)._v;
                    const auto& v = data.get(ct::velocity, eid)._v;

                    p += v * dt;
                });
        }
    };
}

// Setup compile-time settings.
namespace ecst_setup
{
    // Builds and returns a "component signature list".
    constexpr auto make_csl()
    {
        namespace slc = ecst::signature_list::component;

        return slc::v<                                 // .
            c::position, c::velocity, c::acceleration, // .
            c::color, c::circle                        // .
            >;
    }

    // Builds and returns a "system signature list".
    constexpr auto make_ssl()
    {
        // Signature namespace aliases.
        namespace ss = ecst::signature::system;
        namespace sls = ecst::signature_list::system;

        // Inner parallelism aliases and definitions.
        namespace ips = ecst::inner_parallelism::strategy;
        namespace ipc = ecst::inner_parallelism::composer;
        
        // "Split processing evenly between cores."
        constexpr auto par = ips::split_evenly_fn::v_cores();

        // Acceleration system.
        // * Multithreaded.
        // * No dependencies.
        constexpr auto ssig_acceleration =    // .
            ss::make<s::acceleration>(        // .
                par,                          // .
                ss::no_dependencies,          // .
                ss::component_use(            // .
                    ss::mutate<c::velocity>,  // .
                    ss::read<c::acceleration> // .
                    ),                        // .
                ss::output::none              // .
                );

        // Velocity system.
        // * Multithreaded.
        constexpr auto ssig_velocity =           // .
            ss::make<s::velocity>(               // .
                par,                             // .
                ss::depends_on<s::acceleration>, // .
                ss::component_use(               // .
                    ss::mutate<c::position>,     // .
                    ss::read<c::velocity>        // .
                    ),                           // .
                ss::output::none                 // .
                );

        // Build and return the "system signature list".
        return sls::make(              // .
            ssig_acceleration,         // .
            ssig_velocity
            );
    }
}

// Create a particle, return its ID.
template <typename TProxy>
auto mk_particle(TProxy& proxy, const vec2f& position)
{
    auto eid = proxy.create_entity();

    auto& ca = proxy.add_component(ct::acceleration, eid);
    ca._v.y = 1;

    auto& cv = proxy.add_component(ct::velocity, eid);
    cv._v = rndvec2f(-3, 3);

    return eid;
}


int main()
{
    // Namespace aliases.
    using namespace ecst_setup;
    namespace cs = ecst::settings;
    namespace ss = ecst::scheduler;

    // Define ECST context settings.
    constexpr auto s = ecst::settings::make(            // .
        cs::multithreaded(cs::allow_inner_parallelism), // .
        cs::dynamic,                                    // .
        make_csl(),                                     // .
        make_ssl(),                                     // .
        cs::scheduler<ss::s_atomic_counter>             // .
        );

    // Create an ECST context.
    auto ctx_uptr = ecst::context::make_uptr(s);
    auto& ctx = *ctx_uptr;

    // Initialize context with some entities.
    ctx.step([&](auto& proxy)
        {
            for(sz_t i = 0; i < 1000; ++i)
            {
                mk_particle(proxy, random_position());
            }
        });

    // "Game loop."
    while(true)
    {
        auto dt = delta_time();

        ctx.step([dt](auto& proxy)
        {
            proxy.execute_systems_overload( // .
                [dt](s::acceleration& s, auto& data)
                {
                    s.process(dt, data);
                },
                [dt](s::velocity& s, auto& data)
                {
                    s.process(dt, data);
                });
        });
    }
}

About

[WIP] C++14 multithreaded compile-time entity-component-system library.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C++ 97.7%
  • Shell 1.8%
  • CMake 0.5%