I am currently creating a small hobby project to get back into game development, and I have decided to structure my entities using an ECS (Entity Component System). This implementation of an ECS is structured like so:
- Entity: In my case it's a unique
intidentifier that is used as a key to a list of components.
- Component: Holds only data, e.g. the
Positioncomponent holds an
ycoordinate, and the
Movementcomponent holds a
- System: Handles components, e.g. it takes the
Movementcomponents and adds the
directionto the position's
This works fine, but now I wish to implement scripting into my games, in the form of a scripting language. In previous projects I've used an OOP implementation of game objects, which meant that scripting was pretty straight forwards. For example, a simple script could look something like this:
function start() local future = entity:moveTo(pos1) wait(future) local response = entity:showDialog(dialog1) if wait(response) == 1 then local itemStack = entity:getInventory():removeItemByName("apple", 1) world:getPlayer():getInventory():addItemStack(itemStack) else entity:setBehavior(world:getPlayer(), BEHAVIOR_HOSTILE) end end
However, when using an ECS, the entity itself does not have any functions like
getInventory, instead the above script written in ECS style would look something like this:
function start() local movement = world:getComponent(MOVEMENT, entity) movement:moveTo(pos1) local position = world:getComponent(POSITION, entity) local future = Future:untilEquals(position.pos, pos1) wait(future) local dialogComp = world:getComponent(DIALOG, entity) local response = dialogComp:showDialog(dialog1) if wait(response) == 1 then local entityInventory = world:getComponent(INVENTORY, entity) local playerInventory = world:getComponent(INVENTORY, world:getPlayer()) local itemStack = entityInventory:removeItemByName("apple", 1) playerInventory:addItemStack(itemStack) else local entityBehavior = world:getComponent(BEHAVIOR, entity) local playerBehavior = world:getComponent(BEHAVIOR, world:getPlayer()) entityBehavior:set(playerBehavior, BEHAVIOR_HOSTILE) end end
This is a lot more verbose compared to the OOP version, which is not desirable when the scripting is aimed towards mostly non-programmers (players of the game).
One solution would be to have some sort of wrapper object that encapsulates an
Entity and supplies functions such as
moveTo directly, and handles the rest internally, although such a solution seems sub-optimal since it takes a lot of work to cover all the components, and every time a new component is added you would need to change the wrapper object with new functions.
To all game developers that has implemented scripting in an ECS before - how did you do it? The main focus here is usability for the end user, with as little "maintenance" cost as possible (preferably you don't need to change it every time you add a component).