Entt meets sol2
Use EnTT in Lua with Sol2
[entt/wiki/registry](https://github.com/skypjack/entt/wiki/Crash-Course:-entity-component-system#the-registry-the-entity-and-the-component) The project is written primarily in C++, distributed under the Creative Commons Zero v1.0 Universal license, first published in 2021. Key topics include: cpp17, ecs, entt, gamedev, lua.
EnTT meets Sol2
Requirements
- EnTT v.3.16.0 (latest)
- sol2 v3.5.0 (latest)
Building
bash> git clone https://github.com/skaarj1989/entt-meets-sol2.git > cd entt-meets-sol2 > cmake -S . -B build
vcpkg quickstart
https://github.com/microsoft/vcpkg#getting-started
bash> git clone https://github.com/microsoft/vcpkg > ./vcpkg/bootstrap-vcpkg.bat
Add the following environment variables
bashVCPKG_ROOT=path_to_vcpkg VCPKG_DEFAULT_TRIPLET=x64-windows
Install required dependencies
bash> ./vcpkg install entt sol2 lua
Registry
Goal
- Expose
registryto Lua scripts:- Manage entity lifetime
- Set components
- Get component by reference
runtime_view- Some of MonoBehaviour functionality
c++ setup
cppstruct Transform { int x, y; }; register_meta_component<Transform>(); sol::state lua{}; lua.require("dispatcher" ...); lua.new_usertype<Transform>("Transform", "type_id", &entt::type_hash<Transform>::value, sol::call_constructor, sol::factories([](int x, int y) { return Transform{ x, y }; }), "x", &Transform::x, "y", &Transform::y );
cppentt::registry registry{}; lua["registry"] = std::ref(registry); // Make the registry available to Lua
Lua script
lua-- Create a registry inside a script registry = entt.registry.new()
luamario = registry:create() registry:emplace(mario, Transform(1, 2)) material = registry:get(mario, Material) if (registry:has(mario, Transform)) then registry:emplace(mario, DeletionFlag()) end
lua-- Utilizes variadic args - pass as many types as you want registry:runtime_view(Transform, DeletionFlag):each( function(entity) registry:remove(entity, DeletionFlag) end )
Want something like MonoBehaviour in Unity?
examples/system
Lua script
lualocal node = {} function node:init() self.owner:emplace(self.id(), Transform(5, 9)) end function node:update(dt) local transform = self.owner:get(self.id(), Transform) transform.x = transform.x + 1 end function node:destroy() -- ... end return node
c++ setup
cppstruct ScriptComponent { sol::table self; struct { sol::function update; } hooks; }; registry.emplace<ScriptComponent>(entity, lua.script_file("behavior.lua")); while (true) { auto view = registry.view<ScriptComponent>(); for (auto entity : view) { auto &script = view.get<ScriptComponent>(entity); script.hooks.update(script.self, delta_time); } }
Event dispatcher
Goal
- Either create new (inside script) or connect existing (native c++) dispatcher
- Trigger/enqueue events from Lua side
- Listen for events in Lua scripts
- Support disconnection of listeners
c++ setup
cppstruct an_event { int value; }; register_meta_event<an_event>(); sol::state lua{} lua.require("dispatcher", ...) lua.new_usertype<an_event>("an_event", "type_id", &entt::type_hash<an_event>::value, sol::call_constructor, sol::factories([](int value) { return an_event{ value }; }), "value", &an_event::value );
cppentt::dispatcher dispatcher{}; lua["dispatcher"] = std::ref(dispatcher); // Make the dispatcher available to Lua // load a script ... dispatcher.update(); // inside loop
Lua script
lua-- Create a dispatcher in a script dispatcher = entt.dispatcher.new()
lualistener = {} function listener.receive(evt) -- ... end function listener.method(evt) -- ... end -- You have to store result of 'connect()', otherwise listener will be -- disconnected in lua garbage collection step. conn = dispatcher:connect(an_event, listener.receive) dispatcher:connect(another_event, listener.method) -- Event type is deduced from bound 'type_id()' method dispatcher:trigger(an_event(42)) dispatcher:enqueue(another_event()) conn = nil -- to disconnect listener
Cooperative scheduler
entt/wiki/cooperative-scheduler
Goal
- Define process class in Lua and attach it to
schedulereither native c++ or dedicated to script - Allow process chaining
c++ setup
cppsol::state lua{}; lua.require("scheduler", ...);
cppentt::scheduler scheduler{}; lua["scheduler"] = std::ref(scheduler); // Make the scheduler available to Lua scheduler.update(dt); // inside loop
Lua script
lua-- Create a scheduler in a script scheduler = entt.scheduler.new()
lualocal process_a = {} function process:update(dt) -- ... end -- define init, succeeded and other methods ... -- This one differs from entt attach().then().then ... but works the same scheduler:attach( process_a, process_b, process_n -- etc ... )
License
Code released under CC0 1.0 Universal
Contributors
Showing top 1 contributor by commit count.
This article is auto-generated from skaarj1989/entt-meets-sol2 via the GitHub API.Last fetched: 6/14/2026
