19 Commits

Author SHA1 Message Date
bakpakin
8a3c22e74f Add new rockspec. 2016-08-10 19:45:58 -04:00
bakpakin
a0fa0904f6 Update filer documentation to be more explicit. 2016-08-10 19:36:20 -04:00
Calvin Rose
80bb6b8d31 Remove world.entityCount and world.entityList. 2016-08-10 17:23:48 -04:00
bakpakin
83d806011b Combine the 'add entities' procedure in manage_entities with 'change
entities'
2016-08-10 07:23:05 -04:00
Calvin Rose
d720d361e6 Remove redundant non-nil check 2016-07-13 09:43:36 -04:00
Calvin Rose
d94b178670 Make source pass luacheck. Remove tiny.getSystemIndex(). 2016-07-05 17:15:18 -04:00
Calvin Rose
5997f949cd Update rockspecs. 2016-06-19 11:01:57 -04:00
Calvin Rose
ea6009a8d2 Add a rockspec. 2016-06-18 22:47:06 -04:00
Calvin Rose
7da4efb7df Edit README and remove version from library code for easier release cycle.
I don't like git hooks for that kind of thing and its not really necessary.
2016-06-18 13:35:26 -04:00
Calvin Rose
9bc366a2fb Merge branch 'master' of https://github.com/bakpakin/tiny-ecs 2016-06-18 13:22:08 -04:00
Calvin Rose
80b7b48703 Conform to 80 column lines. 2016-06-18 13:21:34 -04:00
bakpakin
0488bff1d9 Fix slightly incorrect pattern for matching filters (only matters on incorrect filters). 2016-05-19 18:18:39 +08:00
bakpakin
ee192d94af Add init.lua for easy require if used as a submodule. 2016-05-19 17:50:54 +08:00
Calvin Rose
a518e15e44 Merge pull request #7 from tst2005/patch-1
typo fix
2016-04-27 10:30:25 -04:00
TsT
37c2c49300 typo fix
Currenty the `doc = doc` is equal to `doc = nil`.
The "doc" directory is used because it's the internal LDoc default.
2016-04-27 13:55:10 +02:00
Calvin Rose
195c882bbd Add documentation for preWrap and postWrap. 2016-04-13 15:01:53 -04:00
Calvin Rose
29a4a02f30 Add tests for postWrap and preWrap. 2016-04-13 14:39:39 -04:00
Calvin Rose
df5c84033b Add code for preWrap and postWrap to system. 2016-04-13 14:28:38 -04:00
bakpakin
d9c296dae6 Update documentation. 2016-03-06 18:20:18 -05:00
17 changed files with 214 additions and 152 deletions
+12 -15
View File
@@ -1,28 +1,26 @@
# tiny-ecs # # tiny-ecs #
[![Build Status](https://travis-ci.org/bakpakin/tiny-ecs.png?branch=master)](https://travis-ci.org/bakpakin/tiny-ecs) [![Build Status](https://travis-ci.org/bakpakin/tiny-ecs.png?branch=master)](https://travis-ci.org/bakpakin/tiny-ecs)[![License](http://img.shields.io/badge/Licence-MIT-brightgreen.svg)](LICENSE)
[![License](http://img.shields.io/badge/Licence-MIT-brightgreen.svg)](LICENSE) Tiny-ecs is an Entity Component System for Lua that's simple, flexible, and useful.
Because of Lua's tabular nature, Entity Component Systems are a natural choice
Tiny-ecs is an Entity Component System for lua that's simple, flexible, and useful.
Because of lua's tabular nature, Entity Component Systems are a natural choice
for simulating large and complex systems. For more explanation on Entity for simulating large and complex systems. For more explanation on Entity
Component Systems, here is some Component Systems, here is some
[basic info](http://en.wikipedia.org/wiki/Entity_component_system "Wikipedia"). [basic info](http://en.wikipedia.org/wiki/Entity_component_system "Wikipedia").
Tiny-ecs also works well with objected oriented programming in lua because Tiny-ecs also works well with objected oriented programming in Lua because
Systems and Entities do not use metatables. This means you can subclass your Systems and Entities do not use metatables. This means you can subclass your
Systems and Entities, and use existing lua class frameworks with tiny-ecs, no problem. Systems and Entities, and use existing Lua class frameworks with tiny-ecs, no problem.
For an example on how to use tiny-ecs with object-oriented lua, take a look at the For an example on how to use tiny-ecs with object-oriented Lua, take a look at the
demo branch, specifically the systems and entities sub-directories. demo branch, specifically the systems and entities sub-directories.
## Overview ## ## Overview ##
Tiny-ecs has four important types: Worlds, Filters, Systems, and Entities. Tiny-ecs has four important types: Worlds, Filters, Systems, and Entities.
Entities, however, can be any lua table, and Filters are just functions that Entities, however, can be any Lua table, and Filters are just functions that
take an Entity as a parameter. take an Entity as a parameter.
### Entities ### ### Entities ###
Entities are simply lua tables of data that gets processed by Systems. Entities Entities are simply Lua tables of data that gets processed by Systems. Entities
should contain primarily data rather than code, as it is the Systems's job to should contain primarily data rather than code, as it is the Systems's job to
do logic on data. Henceforth, a key-value pair in an Entity will do logic on data. Henceforth, a key-value pair in an Entity will
be referred to as a Component. be referred to as a Component.
@@ -39,7 +37,7 @@ provides functions for creating Systems easily, as well as creating Systems that
can be used in an object oriented fashion. can be used in an object oriented fashion.
### Filters ### ### Filters ###
Filters are used to select Entities. Filters can be any lua function, but Filters are used to select Entities. Filters can be any Lua function, but
tiny-ecs provides some functions for generating common ones, like selecting tiny-ecs provides some functions for generating common ones, like selecting
only Entities that have all required components. only Entities that have all required components.
@@ -51,7 +49,7 @@ local talkingSystem = tiny.processingSystem()
talkingSystem.filter = tiny.requireAll("name", "mass", "phrase") talkingSystem.filter = tiny.requireAll("name", "mass", "phrase")
function talkingSystem:process(e, dt) function talkingSystem:process(e, dt)
e.mass = e.mass + dt * 3 e.mass = e.mass + dt * 3
print(e.name .. ", who weighs " .. e.mass .. " pounds, says, \"" .. e.phrase .. "\"") print(("%s who weighs %d pounds, says %q."):format(e.name, e.mass, e.phrase)
end end
local joe = { local joe = {
@@ -70,8 +68,7 @@ end
## Use It ## ## Use It ##
Copy paste tiny.lua into your source folder. For stability and consistent API, Copy paste tiny.lua into your source folder. For stability and consistent API,
please use a tagged release or use luarocks. Tagged releases will have a version please use a tagged release or use luarocks.
number in `tiny._VERSION`, while other commits will just have the string 'scm'.
## Luarocks ## ## Luarocks ##
Tiny-ecs is also on [Luarocks](https://luarocks.org/) and can be installed with Tiny-ecs is also on [Luarocks](https://luarocks.org/) and can be installed with
@@ -80,7 +77,7 @@ Tiny-ecs is also on [Luarocks](https://luarocks.org/) and can be installed with
## Demo ## ## Demo ##
Check out the [demo](https://github.com/bakpakin/tiny-ecs/tree/demo-commandokibbles), a game Check out the [demo](https://github.com/bakpakin/tiny-ecs/tree/demo-commandokibbles), a game
originally written for Ludum Dare 32 with the theme 'An Unconventional Weapon'. The demo uses originally written for Ludum Dare 32 with the theme 'An Unconventional Weapon'. The demo uses
[LÖVE](https://love2d.org/), an amazing game framework for lua. [LÖVE](https://love2d.org/), an amazing game framework for Lua.
## Testing ## ## Testing ##
Tiny-ecs uses [busted](http://olivinelabs.com/busted/) for testing. Install and run Tiny-ecs uses [busted](http://olivinelabs.com/busted/) for testing. Install and run
+1 -1
View File
@@ -5,7 +5,7 @@ backtick_references = true
format = 'discount' format = 'discount'
title = "tiny-ecs API" title = "tiny-ecs API"
one = true one = true
dir = doc dir = "doc"
style = '!fixed' style = '!fixed'
package = 'tiny-ecs' package = 'tiny-ecs'
not_luadoc = true not_luadoc = true
+5
View File
@@ -0,0 +1,5 @@
-- Helper Lua file for easy require if tiny-ecs is used as a git submodule or
-- folder. Not needed in many cases, including luarocks distribution.
local directory = (...):match("(.-)[^%.]+$")
return require(directory .. 'tiny')
+1 -1
View File
@@ -2,7 +2,7 @@ package = "tiny-ecs"
version = "1.0-2" version = "1.0-2"
source = { source = {
url = "git://github.com/bakpakin/tiny-ecs", url = "git://github.com/bakpakin/tiny-ecs",
tag = "1.0-2" tag = version
} }
description = { description = {
summary = "Entity Component System for Lua.", summary = "Entity Component System for Lua.",
+1 -1
View File
@@ -2,7 +2,7 @@ package = "tiny-ecs"
version = "1.1-1" version = "1.1-1"
source = { source = {
url = "git://github.com/bakpakin/tiny-ecs", url = "git://github.com/bakpakin/tiny-ecs",
tag = "1.1-1" tag = version
} }
description = { description = {
summary = "Entity Component System for Lua.", summary = "Entity Component System for Lua.",
+1 -1
View File
@@ -2,7 +2,7 @@ package = "tiny-ecs"
version = "1.1-2" version = "1.1-2"
source = { source = {
url = "git://github.com/bakpakin/tiny-ecs", url = "git://github.com/bakpakin/tiny-ecs",
tag = "1.1-2" tag = version
} }
description = { description = {
summary = "Entity Component System for Lua.", summary = "Entity Component System for Lua.",
+1 -1
View File
@@ -2,7 +2,7 @@ package = "tiny-ecs"
version = "1.1-3" version = "1.1-3"
source = { source = {
url = "git://github.com/bakpakin/tiny-ecs", url = "git://github.com/bakpakin/tiny-ecs",
tag = "1.1-3" tag = version
} }
description = { description = {
summary = "Entity Component System for Lua.", summary = "Entity Component System for Lua.",
+1 -1
View File
@@ -2,7 +2,7 @@ package = "tiny-ecs"
version = "1.1-4" version = "1.1-4"
source = { source = {
url = "git://github.com/bakpakin/tiny-ecs", url = "git://github.com/bakpakin/tiny-ecs",
tag = "1.1-4" tag = version
} }
description = { description = {
summary = "Entity Component System for Lua.", summary = "Entity Component System for Lua.",
+1 -1
View File
@@ -2,7 +2,7 @@ package = "tiny-ecs"
version = "1.1-5" version = "1.1-5"
source = { source = {
url = "git://github.com/bakpakin/tiny-ecs", url = "git://github.com/bakpakin/tiny-ecs",
tag = "1.1-5" tag = version
} }
description = { description = {
summary = "Entity Component System for Lua.", summary = "Entity Component System for Lua.",
+1 -1
View File
@@ -2,7 +2,7 @@ package = "tiny-ecs"
version = "1.1-6" version = "1.1-6"
source = { source = {
url = "git://github.com/bakpakin/tiny-ecs", url = "git://github.com/bakpakin/tiny-ecs",
tag = "1.1-6" tag = version
} }
description = { description = {
summary = "Entity Component System for Lua.", summary = "Entity Component System for Lua.",
+1 -1
View File
@@ -2,7 +2,7 @@ package = "tiny-ecs"
version = "1.1-7" version = "1.1-7"
source = { source = {
url = "git://github.com/bakpakin/tiny-ecs", url = "git://github.com/bakpakin/tiny-ecs",
tag = "1.1-7" tag = version
} }
description = { description = {
summary = "Entity Component System for Lua.", summary = "Entity Component System for Lua.",
+1 -1
View File
@@ -2,7 +2,7 @@ package = "tiny-ecs"
version = "1.2-1" version = "1.2-1"
source = { source = {
url = "git://github.com/bakpakin/tiny-ecs", url = "git://github.com/bakpakin/tiny-ecs",
tag = "1.2-1" tag = version
} }
description = { description = {
summary = "Entity Component System for Lua.", summary = "Entity Component System for Lua.",
+1 -1
View File
@@ -2,7 +2,7 @@ package = "tiny-ecs"
version = "1.3-1" version = "1.3-1"
source = { source = {
url = "git://github.com/bakpakin/tiny-ecs", url = "git://github.com/bakpakin/tiny-ecs",
tag = "1.3-1" tag = version
} }
description = { description = {
summary = "Entity Component System for Lua.", summary = "Entity Component System for Lua.",
+24
View File
@@ -0,0 +1,24 @@
package = "tiny-ecs"
version = "1.3-2"
source = {
url = "git://github.com/bakpakin/tiny-ecs",
tag = version
}
description = {
summary = "Entity Component System for Lua.",
detailed = [[
Pure Lua implementation of an easy to use, compact, fast, and flexible
Entity Component System. Works well with Object Orientation.
]],
homepage = "https://github.com/bakpakin/tiny-ecs",
license = "MIT"
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "builtin",
modules = {
tiny = "tiny.lua"
}
}
+24
View File
@@ -0,0 +1,24 @@
package = "tiny-ecs"
version = "1.3-3"
source = {
url = "git://github.com/bakpakin/tiny-ecs",
tag = version
}
description = {
summary = "Entity Component System for Lua.",
detailed = [[
Pure Lua implementation of an easy to use, compact, fast, and flexible
Entity Component System. Works well with Object Orientation.
]],
homepage = "https://github.com/bakpakin/tiny-ecs",
license = "MIT"
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "builtin",
modules = {
tiny = "tiny.lua"
}
}
+21
View File
@@ -283,6 +283,27 @@ describe('tiny-ecs:', function()
assert.equals(sortsys.entities[3], entity1) assert.equals(sortsys.entities[3], entity1)
end) end)
it("Runs preWrap and postWrap for systems.", function()
local str = ""
local sys1 = tiny.system()
local sys2 = tiny.system()
function sys1:preWrap(dt)
str = str .. "<"
end
function sys2:preWrap(dt)
str = str .. "{"
end
function sys1:postWrap(dt)
str = str .. ">"
end
function sys2:postWrap(dt)
str = str .. "}"
end
world:add(sys1, sys2)
world:update(1)
assert.equals(str, "{<>}")
end)
end) end)
it("Doesn't pollute the global namespace", function() it("Doesn't pollute the global namespace", function()
+86 -95
View File
@@ -22,8 +22,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--- @module tiny-ecs --- @module tiny-ecs
-- @author Calvin Rose -- @author Calvin Rose
-- @license MIT -- @license MIT
-- @copyright 2015 -- @copyright 2016
local tiny = { _VERSION = "scm" } local tiny = {}
-- Local versions of standard lua functions -- Local versions of standard lua functions
local tinsert = table.insert local tinsert = table.insert
@@ -41,12 +41,13 @@ local tiny_addSystem
local tiny_add local tiny_add
local tiny_removeEntity local tiny_removeEntity
local tiny_removeSystem local tiny_removeSystem
local tiny_remove
--- Filter functions. --- Filter functions.
-- A Filter is a function that selects which Entities apply to a System. -- A Filter is a function that selects which Entities apply to a System.
-- Filters take two parameters, the System and the Entity, and return a boolean -- Filters take two parameters, the System and the Entity, and return a boolean
-- value indicating if the Entity should be processed by the System. -- value indicating if the Entity should be processed by the System. A truthy
-- value includes the entity, while a falsey (nil or false) value excludes the
-- entity.
-- --
-- Filters must be added to Systems by setting the `filter` field of the System. -- Filters must be added to Systems by setting the `filter` field of the System.
-- Filter's returned by tiny-ecs's Filter functions are immutable and can be -- Filter's returned by tiny-ecs's Filter functions are immutable and can be
@@ -108,17 +109,18 @@ do
if type(item) == 'string' then if type(item) == 'string' then
accum[#accum + 1] = ("(e[%s] ~= nil)"):format(make_safe(item)) accum[#accum + 1] = ("(e[%s] ~= nil)"):format(make_safe(item))
elseif type(item) == 'function' then elseif type(item) == 'function' then
build[#build + 1] = ('local subfilter_%d_ = select(%d, ...)'):format(i, i) build[#build + 1] = ('local subfilter_%d_ = select(%d, ...)')
:format(i, i)
accum[#accum + 1] = ('(subfilter_%d_(system, e))'):format(i) accum[#accum + 1] = ('(subfilter_%d_(system, e))'):format(i)
else else
error 'Filter token must be a string or a filter function.' error 'Filter token must be a string or a filter function.'
end end
end end
local source = ('do %s\n return function(system, e) return %s(%s) end end'):format( local source = ('%s\nreturn function(system, e) return %s(%s) end')
:format(
table.concat(build, '\n'), table.concat(build, '\n'),
prefix, prefix,
table.concat(accum, seperator) table.concat(accum, seperator))
)
local loader, err = loadstring(source) local loader, err = loadstring(source)
if err then error(err) end if err then error(err) end
return loader(...) return loader(...)
@@ -136,12 +138,14 @@ do
subParts[#subParts + 1] = buildPart(p:sub(2, -2)) subParts[#subParts + 1] = buildPart(p:sub(2, -2))
return ('\255%d'):format(#subParts) return ('\255%d'):format(#subParts)
end) end)
for invert, part, sep in str:gmatch('(%!?)([^%|%&%!]+)([%|%&%!]?)') do for invert, part, sep in str:gmatch('(%!?)([^%|%&%!]+)([%|%&]?)') do
if part:match('^\255%d+$') then if part:match('^\255%d+$') then
local partIndex = tonumber(part:match(part:sub(2))) local partIndex = tonumber(part:match(part:sub(2)))
accum[#accum + 1] = ('%s(%s)'):format(invert == '' and '' or 'not', subParts[partIndex]) accum[#accum + 1] = ('%s(%s)')
:format(invert == '' and '' or 'not', subParts[partIndex])
else else
accum[#accum + 1] = ("(e[%s] %s nil)"):format(make_safe(part), invert == '' and '~=' or '==') accum[#accum + 1] = ("(e[%s] %s nil)")
:format(make_safe(part), invert == '' and '~=' or '==')
end end
if sep ~= '' then if sep ~= '' then
accum[#accum + 1] = (sep == '|' and ' or ' or ' and ') accum[#accum + 1] = (sep == '|' and ' or ' or ' and ')
@@ -151,7 +155,8 @@ do
end end
function filterBuildString(str) function filterBuildString(str)
local source = ("return function(_, e) return %s end"):format(buildPart(str)) local source = ("return function(_, e) return %s end")
:format(buildPart(str))
local loader, err = loadstring(source) local loader, err = loadstring(source)
if err then if err then
error(err) error(err)
@@ -189,11 +194,11 @@ end
-- --
-- * Tokens are alphanumeric strings including underscores. -- * Tokens are alphanumeric strings including underscores.
-- * Tokens can be separated by |, &, or surrounded by parentheses. -- * Tokens can be separated by |, &, or surrounded by parentheses.
-- * Tokens can be prefixed with !, and are then operated on with a boolean 'not'. -- * Tokens can be prefixed with !, and are then inverted.
-- --
-- Examples are best: -- Examples are best:
-- 'a|b|c' - Matches entities with an 'a' component OR a 'b' component or a 'c' component. -- 'a|b|c' - Matches entities with an 'a' OR 'b' OR 'c'.
-- 'a&!b&c' - Matches entities with an 'a' component AND NOT a 'b' component AND a 'c' component. -- 'a&!b&c' - Matches entities with an 'a' AND NOT 'b' AND 'c'.
-- 'a|(b&c&d)|e - Matches 'a' OR ('b' AND 'c' AND 'd') OR 'e' -- 'a|(b&c&d)|e - Matches 'a' OR ('b' AND 'c' AND 'd') OR 'e'
-- @param pattern -- @param pattern
function tiny.filter(pattern) function tiny.filter(pattern)
@@ -223,6 +228,19 @@ end
-- to the World, before any entities are added to the system. -- to the World, before any entities are added to the system.
-- * `function system:onRemoveFromWorld(world)` - Called when the System is -- * `function system:onRemoveFromWorld(world)` - Called when the System is
-- removed from the world, after all Entities are removed from the System. -- removed from the world, after all Entities are removed from the System.
-- * `function system:preWrap(dt)` - Called on each system before update is
-- called on any system.
-- * `function system:postWrap(dt) - Called on each system in reverse order
-- after update is called on each system. The idea behind `preWrap` and
-- `postWrap` is to allow for systems that modify the behavior of other systems.
-- Say there is a DrawingSystem, which draws sprites to the screen, and a
-- PostProcessingSystem, that adds some blur and bloom effects. In the preWrap
-- method of the PostProcessingSystem, the System could set the drawing target
-- for the DrawingSystem to a special buffer instead the screen. In the postWrap
-- method, the PostProcessingSystem could then modify the buffer and render it
-- to the screen. In this setup, the PostProcessingSystem would be added to the
-- World after the drawingSystem (A similar but less flexible behavior could
-- be accomplished with a single custom update function in the DrawingSystem).
-- --
-- For Filters, it is convenient to use `tiny.requireAll` or `tiny.requireAny`, -- For Filters, it is convenient to use `tiny.requireAll` or `tiny.requireAny`,
-- but one can write their own filters as well. Set the Filter of a System like -- but one can write their own filters as well. Set the Filter of a System like
@@ -258,6 +276,14 @@ end
-- in the next update, if it has one. This is usually managed by tiny-ecs, so -- in the next update, if it has one. This is usually managed by tiny-ecs, so
-- users should mostly ignore this, too. -- users should mostly ignore this, too.
-- --
-- There is another option to (hopefully) increase performance in systems that
-- have items added to or removed from them often, and have lots of entities in
-- them. Setting the `nocache' field of the system might improve performance.
-- It is still experimental. There are some restriction to systems without
-- caching, however. * There is no `entities` table. * Callbacks such onAdd,
-- onRemove, and onModify will never be called * Noncached systems cannot be
-- sorted (There is no entities list to sort).
--
-- @section System -- @section System
-- Use an empty table as a key for identifying Systems. Any table that contains -- Use an empty table as a key for identifying Systems. Any table that contains
@@ -305,7 +331,7 @@ local function processingSystemUpdate(system, dt)
end end
-- Sorts Systems by a function system.sortDelegate(entity1, entity2) on modify. -- Sorts Systems by a function system.sortDelegate(entity1, entity2) on modify.
local function sortedSystemOnModify(system, dt) local function sortedSystemOnModify(system)
local entities = system.entities local entities = system.entities
local indices = system.indices local indices = system.indices
local sortDelegate = system.sortDelegate local sortDelegate = system.sortDelegate
@@ -395,9 +421,6 @@ local worldMetaTable
function tiny.world(...) function tiny.world(...)
local ret = setmetatable({ local ret = setmetatable({
-- List of Entities to add
entitiesToAdd = {},
-- List of Entities to remove -- List of Entities to remove
entitiesToRemove = {}, entitiesToRemove = {},
@@ -413,14 +436,9 @@ function tiny.world(...)
-- Set of Entities -- Set of Entities
entities = {}, entities = {},
-- List of Entities
entityList = {},
-- Number of Entities in World
entityCount = 0,
-- List of Systems -- List of Systems
systems = {} systems = {}
}, worldMetaTable) }, worldMetaTable)
tiny_add(ret, ...) tiny_add(ret, ...)
@@ -434,13 +452,8 @@ end
-- Also call this on Entities that have changed Components such that they -- Also call this on Entities that have changed Components such that they
-- match different Filters. Returns the Entity. -- match different Filters. Returns the Entity.
function tiny.addEntity(world, entity) function tiny.addEntity(world, entity)
if world.entities[entity] then
local e2c = world.entitiesToChange local e2c = world.entitiesToChange
e2c[#e2c + 1] = entity e2c[#e2c + 1] = entity
else
local e2a = world.entitiesToAdd
e2a[#e2a + 1] = entity
end
return entity return entity
end end
tiny_addEntity = tiny.addEntity tiny_addEntity = tiny.addEntity
@@ -472,7 +485,7 @@ function tiny.add(world, ...)
end end
tiny_add = tiny.add tiny_add = tiny.add
--- Removes an Entity to the World. Returns the Entity. --- Removes an Entity from the World. Returns the Entity.
function tiny.removeEntity(world, entity) function tiny.removeEntity(world, entity)
local e2r = world.entitiesToRemove local e2r = world.entitiesToRemove
e2r[#e2r + 1] = entity e2r[#e2r + 1] = entity
@@ -504,7 +517,6 @@ function tiny.remove(world, ...)
end end
return ... return ...
end end
tiny_remove = tiny.remove
-- Adds and removes Systems that have been marked from the World. -- Adds and removes Systems that have been marked from the World.
function tiny_manageSystems(world) function tiny_manageSystems(world)
@@ -518,7 +530,7 @@ function tiny_manageSystems(world)
world.systemsToAdd = {} world.systemsToAdd = {}
world.systemsToRemove = {} world.systemsToRemove = {}
local worldEntityList = world.entityList local worldEntityList = world.entities
local systems = world.systems local systems = world.systems
-- Remove Systems -- Remove Systems
@@ -598,28 +610,29 @@ end
-- Adds, removes, and changes Entities that have been marked. -- Adds, removes, and changes Entities that have been marked.
function tiny_manageEntities(world) function tiny_manageEntities(world)
local e2a = world.entitiesToAdd
local e2r = world.entitiesToRemove local e2r = world.entitiesToRemove
local e2c = world.entitiesToChange local e2c = world.entitiesToChange
-- Early exit -- Early exit
if #e2a == 0 and #e2r == 0 and #e2c == 0 then if #e2r == 0 and #e2c == 0 then
return return
end end
world.entitiesToChange = {} world.entitiesToChange = {}
world.entitiesToAdd = {}
world.entitiesToRemove = {} world.entitiesToRemove = {}
local entities = world.entities local entities = world.entities
local entityList = world.entityList
local systems = world.systems local systems = world.systems
local entityCount = world.entityCount
-- Change Entities -- Change Entities
for i = 1, #e2c do for i = 1, #e2c do
local entity = e2c[i] local entity = e2c[i]
if entities[entity] then -- Add if needed
if not entities[entity] then
local index = #entities + 1
entities[entity] = index
entities[index] = entity
end
for j = 1, #systems do for j = 1, #systems do
local system = systems[j] local system = systems[j]
if not system.nocache then if not system.nocache then
@@ -652,7 +665,6 @@ function tiny_manageEntities(world)
end end
end end
end end
end
e2c[i] = nil e2c[i] = nil
end end
@@ -663,12 +675,11 @@ function tiny_manageEntities(world)
local listIndex = entities[entity] local listIndex = entities[entity]
if listIndex then if listIndex then
-- Remove Entity from world state -- Remove Entity from world state
local lastEntity = entityList[#entityList] local lastEntity = entities[#entities]
entities[lastEntity] = listIndex entities[lastEntity] = listIndex
entities[entity] = nil entities[entity] = nil
entityList[listIndex] = lastEntity entities[listIndex] = lastEntity
entityList[#entityList] = nil entities[#entities] = nil
entityCount = entityCount - 1
-- Remove from cached systems -- Remove from cached systems
for j = 1, #systems do for j = 1, #systems do
local system = systems[j] local system = systems[j]
@@ -692,39 +703,6 @@ function tiny_manageEntities(world)
end end
end end
end end
-- Add Entities
for i = 1, #e2a do
local entity = e2a[i]
if not entities[entity] then
local listIndex = #entityList + 1
entities[entity] = listIndex
entityList[listIndex] = entity
entityCount = entityCount + 1
for j = 1, #systems do
local system = systems[j]
if not system.nocache then
local ses = system.entities
local seis = system.indices
local filter = system.filter
if filter and filter(system, entity) then
system.modified = true
local index = #ses + 1
ses[index] = entity
seis[entity] = index
local onAdd = system.onAdd
if onAdd then
onAdd(system, entity)
end
end
end
end
end
e2a[i] = nil
end
-- Update Entity count
world.entityCount = entityCount
end end
--- Manages Entities and Systems marked for deletion or addition. Call this --- Manages Entities and Systems marked for deletion or addition. Call this
@@ -734,7 +712,7 @@ function tiny.refresh(world)
tiny_manageSystems(world) tiny_manageSystems(world)
tiny_manageEntities(world) tiny_manageEntities(world)
local systems = world.systems local systems = world.systems
for i = 1, #systems do for i = #systems, 1, -1 do
local system = systems[i] local system = systems[i]
if system.active then if system.active then
local onModify = system.onModify local onModify = system.onModify
@@ -757,16 +735,27 @@ function tiny.update(world, dt, filter)
local systems = world.systems local systems = world.systems
-- Iterate through Systems IN ORDER -- Iterate through Systems IN REVERSE ORDER
for i = 1, #systems do for i = #systems, 1, -1 do
local system = systems[i] local system = systems[i]
if system.active and ((not filter) or filter(world, system)) then if system.active then
-- Call the modify callback on Systems that have been modified. -- Call the modify callback on Systems that have been modified.
local onModify = system.onModify local onModify = system.onModify
if onModify and system.modified then if onModify and system.modified then
onModify(system, dt) onModify(system, dt)
end end
local preWrap = system.preWrap
if preWrap and
((not filter) or filter(world, system)) then
preWrap(system, dt)
end
end
end
-- Iterate through Systems IN ORDER
for i = 1, #systems do
local system = systems[i]
if system.active and ((not filter) or filter(world, system)) then
-- Update Systems that have an update method (most Systems) -- Update Systems that have an update method (most Systems)
local update = system.update local update = system.update
@@ -776,10 +765,8 @@ function tiny.update(world, dt, filter)
local bufferedTime = (system.bufferedTime or 0) + dt local bufferedTime = (system.bufferedTime or 0) + dt
while bufferedTime >= interval do while bufferedTime >= interval do
bufferedTime = bufferedTime - interval bufferedTime = bufferedTime - interval
if update then
update(system, interval) update(system, interval)
end end
end
system.bufferedTime = bufferedTime system.bufferedTime = bufferedTime
else else
update(system, dt) update(system, dt)
@@ -789,11 +776,22 @@ function tiny.update(world, dt, filter)
system.modified = false system.modified = false
end end
end end
-- Iterate through Systems IN ORDER AGAIN
for i = 1, #systems do
local system = systems[i]
local postWrap = system.postWrap
if postWrap and system.active and
((not filter) or filter(world, system)) then
postWrap(system, dt)
end
end
end end
--- Removes all Entities from the World. --- Removes all Entities from the World.
function tiny.clearEntities(world) function tiny.clearEntities(world)
local el = world.entityList local el = world.entities
for i = 1, #el do for i = 1, #el do
tiny_removeEntity(world, el[i]) tiny_removeEntity(world, el[i])
end end
@@ -809,18 +807,12 @@ end
--- Gets number of Entities in the World. --- Gets number of Entities in the World.
function tiny.getEntityCount(world) function tiny.getEntityCount(world)
return world.entityCount return #world.entities
end end
--- Gets number of Systems in World. --- Gets number of Systems in World.
function tiny.getSystemCount(world) function tiny.getSystemCount(world)
return #(world.systems) return #world.systems
end
--- Gets the index of the System in the World.
-- A simpler alternative is `system.index`.
function tiny.getSystemIndex(world, system)
return system.index
end end
--- Sets the index of a System in the World, and returns the old index. Changes --- Sets the index of a System in the World, and returns the old index. Changes
@@ -859,10 +851,9 @@ worldMetaTable = {
clearSystems = tiny.clearSystems, clearSystems = tiny.clearSystems,
getEntityCount = tiny.getEntityCount, getEntityCount = tiny.getEntityCount,
getSystemCount = tiny.getSystemCount, getSystemCount = tiny.getSystemCount,
getSystemIndex = tiny.getSystemIndex,
setSystemIndex = tiny.setSystemIndex setSystemIndex = tiny.setSystemIndex
}, },
__tostring = function(self) __tostring = function()
return "<tiny-ecs_World>" return "<tiny-ecs_World>"
end end
} }