Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --!strict
- --!optimize 2
- export type SystemPhase = "pre" | "update" | "post"
- export type SystemFn = (world: World, dt: number) -> ()
- export type ComponentTable = { [number]: any }
- export type World = {
- _nextEntityId: number,
- _alive: { [number]: boolean },
- _components: { [string]: ComponentTable },
- _systemsPre: { SystemFn },
- _systemsUpdate: { SystemFn },
- _systemsPost: { SystemFn },
- Spawn: (self: World) -> number,
- Despawn: (self: World, entityId: number) -> (),
- HasEntity: (self: World, entityId: number) -> boolean,
- GetComponentTable: (self: World, name: string) -> ComponentTable,
- AddComponent: (self: World, entityId: number, name: string, data: any) -> (),
- GetComponent: (self: World, entityId: number, name: string) -> any?,
- RemoveComponent: (self: World, entityId: number, name: string) -> (),
- RegisterSystem: (self: World, phase: SystemPhase, system: SystemFn) -> (),
- Step: (self: World, dt: number) -> (),
- ForEach: (self: World, name: string, fn: (entityId: number, data: any) -> ()) -> (),
- }
- local ECSWorld = {}
- local function runSystems(list: { SystemFn }, world: World, dt: number)
- local count = #list
- for i = 1, count do
- list[i](world, dt)
- end
- end
- local function spawnEntity(self: World): number
- local id = self._nextEntityId + 1
- self._nextEntityId = id
- self._alive[id] = true
- return id
- end
- local function despawnEntity(self: World, entityId: number)
- if not self._alive[entityId] then
- return
- end
- self._alive[entityId] = nil
- local components = self._components
- for _, tableForComponent in pairs(components) do
- tableForComponent[entityId] = nil
- end
- end
- local function hasEntity(self: World, entityId: number): boolean
- return self._alive[entityId] == true
- end
- local function getComponentTable(self: World, name: string): ComponentTable
- local components = self._components
- local tbl = components[name]
- if tbl ~= nil then
- return tbl
- end
- local newTbl: ComponentTable = {}
- components[name] = newTbl
- return newTbl
- end
- local function addComponent(self: World, entityId: number, name: string, data: any)
- if not self._alive[entityId] then
- return
- end
- local tbl = getComponentTable(self, name)
- tbl[entityId] = data
- end
- local function getComponent(self: World, entityId: number, name: string): any?
- local tbl = self._components[name]
- if tbl == nil then
- return nil
- end
- return tbl[entityId]
- end
- local function removeComponent(self: World, entityId: number, name: string)
- local tbl = self._components[name]
- if tbl == nil then
- return
- end
- tbl[entityId] = nil
- end
- local function registerSystem(self: World, phase: SystemPhase, system: SystemFn)
- if phase == "pre" then
- local list = self._systemsPre
- list[#list + 1] = system
- elseif phase == "update" then
- local list = self._systemsUpdate
- list[#list + 1] = system
- else
- local list = self._systemsPost
- list[#list + 1] = system
- end
- end
- local function step(self: World, dt: number)
- if dt <= 0 then
- return
- end
- runSystems(self._systemsPre, self, dt)
- runSystems(self._systemsUpdate, self, dt)
- runSystems(self._systemsPost, self, dt)
- end
- local function forEach(self: World, name: string, fn: (entityId: number, data: any) -> ())
- local tbl = self._components[name]
- if tbl == nil then
- return
- end
- for entityId, data in tbl do
- if self._alive[entityId] then
- fn(entityId, data)
- end
- end
- end
- function ECSWorld.new(): World
- local world: World = {
- _nextEntityId = 0,
- _alive = {},
- _components = {},
- _systemsPre = {},
- _systemsUpdate = {},
- _systemsPost = {},
- Spawn = spawnEntity,
- Despawn = despawnEntity,
- HasEntity = hasEntity,
- GetComponentTable = getComponentTable,
- AddComponent = addComponent,
- GetComponent = getComponent,
- RemoveComponent = removeComponent,
- RegisterSystem = registerSystem,
- Step = step,
- ForEach = forEach,
- }
- return world
- end
- return ECSWorld
Advertisement
Add Comment
Please, Sign In to add comment