mirror of
https://github.com/bakpakin/tiny-ecs.git
synced 2026-07-22 07:56:52 -06:00
Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbf71d2cb2 | ||
|
|
93a19d93c8 | ||
|
|
4148855233 | ||
|
|
27f881444a | ||
|
|
3b4bd9920b | ||
|
|
206361ca38 | ||
|
|
29158282bd | ||
|
|
2403a9019c | ||
|
|
6234e4b741 | ||
|
|
b870b5a34e | ||
|
|
f3b16a40f6 | ||
|
|
5035d2c8a7 | ||
|
|
18270cd60a | ||
|
|
dba8e7c89f | ||
|
|
fccff0329e | ||
|
|
8a759edca2 | ||
|
|
d9d311d858 | ||
|
|
9834dfa9d6 | ||
|
|
a5af4b6ecd | ||
|
|
f0e6ce7880 | ||
|
|
26f8259f2b | ||
|
|
b1c7e2ba83 | ||
|
|
6b549fcbc1 | ||
|
|
b9d994ad50 | ||
|
|
ce8ca35f7e | ||
|
|
19ae03707f | ||
|
|
c1f1225248 | ||
|
|
45e8552054 | ||
|
|
f187dce4fd | ||
|
|
927652597c | ||
|
|
6b3af0f2da | ||
|
|
31f3396db1 | ||
|
|
cb9ab332d2 | ||
|
|
1fd32dab9a | ||
|
|
0a12897695 | ||
|
|
e44ac6cdb3 | ||
|
|
6f299470d0 | ||
|
|
61ffd2551b | ||
|
|
c66ed98a5a | ||
|
|
2621bd16a3 | ||
|
|
c408267932 | ||
|
|
557927577d | ||
|
|
cbfc3d360f | ||
|
|
d35d62ed3c | ||
|
|
74666ca0c3 | ||
|
|
5978ace463 | ||
|
|
a504bd6336 | ||
|
|
69ae37586e | ||
|
|
44fb94c457 | ||
|
|
9230dad1e1 |
+39
@@ -0,0 +1,39 @@
|
||||
language: erlang
|
||||
|
||||
env:
|
||||
global:
|
||||
- LUAROCKS_BASE=luarocks-2.2.2
|
||||
matrix:
|
||||
- LUA=lua5.1 LUA_DEV=liblua5.1-dev LUA_VER=5.1 LUA_SFX=5.1 LUA_INCDIR=/usr/include/lua5.1
|
||||
- LUA=lua5.2 LUA_DEV=liblua5.2-dev LUA_VER=5.2 LUA_SFX=5.2 LUA_INCDIR=/usr/include/lua5.2
|
||||
- LUA=luajit LUA_DEV=libluajit-5.1-dev LUA_VER=5.1 LUA_SFX=jit LUA_INCDIR=/usr/include/luajit-2.0
|
||||
|
||||
before_install:
|
||||
- if [ $LUA = "luajit" ]; then
|
||||
sudo add-apt-repository ppa:mwild1/ppa -y && sudo apt-get update -y;
|
||||
sudo apt-get install lua5.1;
|
||||
sudo apt-get install liblua5.1-dev;
|
||||
fi
|
||||
- sudo apt-get install $LUA
|
||||
- sudo apt-get install $LUA_DEV
|
||||
- lua$LUA_SFX -v
|
||||
# Install a recent luarocks release
|
||||
- wget http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz
|
||||
- tar zxvpf $LUAROCKS_BASE.tar.gz
|
||||
- cd $LUAROCKS_BASE
|
||||
- ./configure
|
||||
--lua-version=$LUA_VER --lua-suffix=$LUA_SFX --with-lua-include="$LUA_INCDIR"
|
||||
- sudo make
|
||||
- sudo make install
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
|
||||
install:
|
||||
- sudo -E luarocks install busted
|
||||
|
||||
script:
|
||||
- sudo -E busted -v
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: always
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2015 Calvin Rose
|
||||
Copyright (c) 2016 Calvin Rose
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
# tiny-ecs #
|
||||
|
||||
[](https://travis-ci.org/bakpakin/tiny-ecs)
|
||||
|
||||
[](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
|
||||
for simulating large and complex systems. For more explanation on Entity
|
||||
@@ -8,6 +13,8 @@ Component Systems, here is some
|
||||
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, 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
|
||||
demo branch, specifically the systems and entities sub-directories.
|
||||
|
||||
## Overview ##
|
||||
Tiny-ecs has four important types: Worlds, Filters, Systems, and Entities.
|
||||
@@ -29,7 +36,7 @@ Systems in tiny-ecs describe how to update Entities. Systems select certain Enti
|
||||
using a Filter, and then only update those select Entities. Some Systems don't
|
||||
update Entities, and instead just act as function callbacks every update. Tiny-ecs
|
||||
provides functions for creating Systems easily, as well as creating Systems that
|
||||
can be used in an object orientented fashion.
|
||||
can be used in an object oriented fashion.
|
||||
|
||||
### Filters ###
|
||||
Filters are used to select Entities. Filters can be any lua function, but
|
||||
@@ -64,7 +71,7 @@ end
|
||||
## Use It ##
|
||||
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
|
||||
number in `tiny._VERSION`, while other commits will just have the string 'dev'.
|
||||
number in `tiny._VERSION`, while other commits will just have the string 'scm'.
|
||||
|
||||
## Luarocks ##
|
||||
Tiny-ecs is also on [Luarocks](https://luarocks.org/) and can be installed with
|
||||
@@ -73,7 +80,7 @@ Tiny-ecs is also on [Luarocks](https://luarocks.org/) and can be installed with
|
||||
## Demo ##
|
||||
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
|
||||
[LOVE](https://love2d.org/), an amazing game framework for lua.
|
||||
[LÖVE](https://love2d.org/), an amazing game framework for lua.
|
||||
|
||||
## Testing ##
|
||||
Tiny-ecs uses [busted](http://olivinelabs.com/busted/) for testing. Install and run
|
||||
@@ -83,10 +90,4 @@ Tiny-ecs uses [busted](http://olivinelabs.com/busted/) for testing. Install and
|
||||
See API [here](http://bakpakin.github.io/tiny-ecs/doc/).
|
||||
For the most up-to-date documentation, read the source code, or generate the HTML
|
||||
locally with [LDoc](http://stevedonovan.github.io/ldoc/).
|
||||
|
||||
## TODO ##
|
||||
|
||||
* More testing
|
||||
* Performance testing / optimization
|
||||
* Add more System types
|
||||
* Improve Documentation
|
||||
See the original forum thread [here](https://love2d.org/forums/viewtopic.php?f=5&t=79937&p=182589).
|
||||
|
||||
@@ -10,3 +10,4 @@ style = '!fixed'
|
||||
package = 'tiny-ecs'
|
||||
not_luadoc = true
|
||||
boilerplate = true
|
||||
no_return_or_parms = true
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package = "tiny-ecs"
|
||||
version = "1.1-3"
|
||||
source = {
|
||||
url = "git://github.com/bakpakin/tiny-ecs",
|
||||
tag = "1.1-3"
|
||||
}
|
||||
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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package = "tiny-ecs"
|
||||
version = "1.1-4"
|
||||
source = {
|
||||
url = "git://github.com/bakpakin/tiny-ecs",
|
||||
tag = "1.1-4"
|
||||
}
|
||||
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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package = "tiny-ecs"
|
||||
version = "1.1-5"
|
||||
source = {
|
||||
url = "git://github.com/bakpakin/tiny-ecs",
|
||||
tag = "1.1-5"
|
||||
}
|
||||
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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package = "tiny-ecs"
|
||||
version = "1.1-6"
|
||||
source = {
|
||||
url = "git://github.com/bakpakin/tiny-ecs",
|
||||
tag = "1.1-6"
|
||||
}
|
||||
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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package = "tiny-ecs"
|
||||
version = "1.1-7"
|
||||
source = {
|
||||
url = "git://github.com/bakpakin/tiny-ecs",
|
||||
tag = "1.1-7"
|
||||
}
|
||||
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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package = "tiny-ecs"
|
||||
version = "1.2-1"
|
||||
source = {
|
||||
url = "git://github.com/bakpakin/tiny-ecs",
|
||||
tag = "1.2-1"
|
||||
}
|
||||
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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package = "tiny-ecs"
|
||||
version = "1.3-1"
|
||||
source = {
|
||||
url = "git://github.com/bakpakin/tiny-ecs",
|
||||
tag = "1.3-1"
|
||||
}
|
||||
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"
|
||||
}
|
||||
}
|
||||
+74
-4
@@ -1,3 +1,8 @@
|
||||
local GLOBALS = {}
|
||||
for k, v in pairs(_G) do
|
||||
GLOBALS[k] = v
|
||||
end
|
||||
|
||||
local tiny = require "tiny"
|
||||
|
||||
local function deep_copy(x)
|
||||
@@ -85,6 +90,49 @@ describe('tiny-ecs:', function()
|
||||
|
||||
end)
|
||||
|
||||
it("Can use functions as subfilters", function()
|
||||
|
||||
local f1 = tiny.requireAny('a', 'b', 'c')
|
||||
local f2 = tiny.requireAll('x', 'y', 'z')
|
||||
local f = tiny.requireAll(f1, f2)
|
||||
|
||||
assert.truthy(f(nil, {
|
||||
x = true, y = true, z = true, a = true, b = true, c = true
|
||||
}))
|
||||
assert.truthy(f(nil, {
|
||||
x = true, y = true, z = true, a = true
|
||||
}))
|
||||
assert.falsy(f(nil, {
|
||||
x = true, y = true, a = true
|
||||
}))
|
||||
assert.falsy(f(nil, {
|
||||
x = true, y = true, z = true
|
||||
}))
|
||||
|
||||
end)
|
||||
|
||||
it("Can use string filters", function()
|
||||
|
||||
local f = tiny.filter('a|b|c')
|
||||
|
||||
assert.truthy(f(nil, {
|
||||
a = true, b = true, c = true
|
||||
}))
|
||||
assert.truthy(f(nil, {
|
||||
a = true
|
||||
}))
|
||||
assert.truthy(f(nil, {
|
||||
b = true
|
||||
}))
|
||||
assert.truthy(f(nil, {
|
||||
c = true
|
||||
}))
|
||||
assert.falsy(f(nil, {
|
||||
x = true, y = true, z = true
|
||||
}))
|
||||
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
describe('World:', function()
|
||||
@@ -115,6 +163,11 @@ describe('tiny-ecs:', function()
|
||||
timePassed = 0
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
world:clearSystems()
|
||||
world:refresh()
|
||||
end)
|
||||
|
||||
it("Create World", function()
|
||||
assert.equals(world:getEntityCount(), 3)
|
||||
assert.equals(world:getSystemCount(), 2)
|
||||
@@ -191,7 +244,7 @@ describe('tiny-ecs:', function()
|
||||
|
||||
it("Add Systems Multiple Times", function()
|
||||
world:update(1)
|
||||
world:add(moveSystem, oneTimeSystem)
|
||||
assert.has_error(function() world:add(moveSystem, oneTimeSystem) end, "System already belongs to a World.")
|
||||
world:update(2)
|
||||
assert.equals(2, world:getSystemCount())
|
||||
assert.equals(3, world:getEntityCount())
|
||||
@@ -201,7 +254,7 @@ describe('tiny-ecs:', function()
|
||||
world:update(1)
|
||||
world:remove(moveSystem)
|
||||
world:update(2)
|
||||
world:remove(moveSystem)
|
||||
assert.has_error(function() world:remove(moveSystem) end, "System does not belong to this World.")
|
||||
world:update(2)
|
||||
assert.equals(1, world:getSystemCount())
|
||||
assert.equals(3, world:getEntityCount())
|
||||
@@ -211,10 +264,27 @@ describe('tiny-ecs:', function()
|
||||
world:update(1)
|
||||
world:setSystemIndex(moveSystem, 2)
|
||||
world:update(1)
|
||||
assert.equals(2, world:getSystemIndex(moveSystem))
|
||||
assert.equals(1, world:getSystemIndex(oneTimeSystem))
|
||||
assert.equals(2, moveSystem.index)
|
||||
assert.equals(1, oneTimeSystem.index)
|
||||
end)
|
||||
|
||||
it("Sorts Entities in Sorting Systems", function()
|
||||
local sortsys = tiny.sortedProcessingSystem()
|
||||
sortsys.filter = tiny.requireAll("vel")
|
||||
function sortsys:compare(e1, e2)
|
||||
return e1.vel.x < e2.vel.x
|
||||
end
|
||||
world:add(sortsys)
|
||||
world:update(0)
|
||||
assert.equals(sortsys.entities[1], entity2)
|
||||
assert.equals(sortsys.entities[2], entity3)
|
||||
assert.equals(sortsys.entities[3], entity1)
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
it("Doesn't pollute the global namespace", function()
|
||||
assert.are.same(_G, GLOBALS)
|
||||
end)
|
||||
|
||||
end)
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package = "tiny-ecs"
|
||||
version = "scm-0"
|
||||
source = {
|
||||
url = "git://github.com/bakpakin/tiny-ecs",
|
||||
}
|
||||
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"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
--[[
|
||||
Copyright (c) 2015 Calvin Rose
|
||||
Copyright (c) 2016 Calvin Rose
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
@@ -23,14 +23,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
-- @author Calvin Rose
|
||||
-- @license MIT
|
||||
-- @copyright 2015
|
||||
local tiny = { _VERSION = "1.1-2" }
|
||||
local tiny = { _VERSION = "1.3-1" }
|
||||
|
||||
-- Local versions of standard lua functions
|
||||
local tinsert = table.insert
|
||||
local tremove = table.remove
|
||||
local tsort = table.sort
|
||||
local pairs = pairs
|
||||
local ipairs = ipairs
|
||||
local setmetatable = setmetatable
|
||||
local type = type
|
||||
local select = select
|
||||
@@ -51,8 +50,8 @@ local tiny_remove
|
||||
-- value indicating if the Entity should be processed by the System.
|
||||
--
|
||||
-- Filters must be added to Systems by setting the `filter` field of the System.
|
||||
-- Filter's returned by `tiny.requireAll` and `tiny.requireAny` are immutable
|
||||
-- and can be used by multiple Systems.
|
||||
-- Filter's returned by tiny-ecs's Filter functions are immutable and can be
|
||||
-- used by multiple Systems.
|
||||
--
|
||||
-- local f1 = tiny.requireAll("position", "velocity", "size")
|
||||
-- local f2 = tiny.requireAny("position", "velocity", "size")
|
||||
@@ -86,92 +85,121 @@ local tiny_remove
|
||||
--
|
||||
-- @section Filter
|
||||
|
||||
-- A helper function to compile filters.
|
||||
local filterJoin
|
||||
|
||||
-- A helper function to filters from string
|
||||
local filterBuildString
|
||||
|
||||
do
|
||||
|
||||
local loadstring = loadstring or load
|
||||
local function getchr(c)
|
||||
return "\\" .. c:byte()
|
||||
end
|
||||
local function make_safe(text)
|
||||
return ("%q"):format(text):gsub('\n', 'n'):gsub("[\128-\255]", getchr)
|
||||
end
|
||||
|
||||
local function filterJoinRaw(prefix, seperator, ...)
|
||||
local accum = {}
|
||||
local build = {}
|
||||
for i = 1, select('#', ...) do
|
||||
local item = select(i, ...)
|
||||
if type(item) == 'string' then
|
||||
accum[#accum + 1] = ("(e[%s] ~= nil)"):format(make_safe(item))
|
||||
elseif type(item) == 'function' then
|
||||
build[#build + 1] = ('local subfilter_%d_ = select(%d, ...)'):format(i, i)
|
||||
accum[#accum + 1] = ('(subfilter_%d_(system, e))'):format(i)
|
||||
else
|
||||
error 'Filter token must be a string or a filter function.'
|
||||
end
|
||||
end
|
||||
local source = ('do %s\n return function(system, e) return %s(%s) end end'):format(
|
||||
table.concat(build, '\n'),
|
||||
prefix,
|
||||
table.concat(accum, seperator)
|
||||
)
|
||||
local loader, err = loadstring(source)
|
||||
if err then error(err) end
|
||||
return loader(...)
|
||||
end
|
||||
|
||||
function filterJoin(...)
|
||||
local state, value = pcall(filterJoinRaw, ...)
|
||||
if state then return value else return nil, value end
|
||||
end
|
||||
|
||||
local function buildPart(str)
|
||||
local accum = {}
|
||||
local subParts = {}
|
||||
str = str:gsub('%b()', function(p)
|
||||
subParts[#subParts + 1] = buildPart(p:sub(2, -2))
|
||||
return ('\255%d'):format(#subParts)
|
||||
end)
|
||||
for invert, part, sep in str:gmatch('(%!?)([^%|%&%!]+)([%|%&%!]?)') do
|
||||
if part:match('^\255%d+$') then
|
||||
local partIndex = tonumber(part:match(part:sub(2)))
|
||||
accum[#accum + 1] = ('%s(%s)'):format(invert == '' and '' or 'not', subParts[partIndex])
|
||||
else
|
||||
accum[#accum + 1] = ("(e[%s] %s nil)"):format(make_safe(part), invert == '' and '~=' or '==')
|
||||
end
|
||||
if sep ~= '' then
|
||||
accum[#accum + 1] = (sep == '|' and ' or ' or ' and ')
|
||||
end
|
||||
end
|
||||
return table.concat(accum)
|
||||
end
|
||||
|
||||
function filterBuildString(str)
|
||||
local source = ("return function(_, e) return %s end"):format(buildPart(str))
|
||||
local loader, err = loadstring(source)
|
||||
if err then
|
||||
error(err)
|
||||
end
|
||||
return loader()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--- Makes a Filter that selects Entities with all specified Components and
|
||||
-- Filters.
|
||||
-- @param ... List of required Components and other Filters.
|
||||
function tiny.requireAll(...)
|
||||
local components = {...}
|
||||
local len = #components
|
||||
return function(system, e)
|
||||
local c
|
||||
for i = 1, len do
|
||||
c = components[i]
|
||||
if type(c) == 'function' then
|
||||
if not c(system, e) then
|
||||
return false
|
||||
end
|
||||
elseif e[c] == nil then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
return filterJoin('', ' and ', ...)
|
||||
end
|
||||
|
||||
--- Makes a Filter that selects Entities with at least one of the specified
|
||||
-- Components and Filters.
|
||||
-- @param ... List of required Components and other Filters.
|
||||
function tiny.requireAny(...)
|
||||
local components = {...}
|
||||
local len = #components
|
||||
return function(system, e)
|
||||
local c
|
||||
for i = 1, len do
|
||||
c = components[i]
|
||||
if type(c) == 'function' then
|
||||
if c(system, e) then
|
||||
return true
|
||||
end
|
||||
elseif e[c] ~= nil then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
return filterJoin('', ' or ', ...)
|
||||
end
|
||||
|
||||
--- Makes a Filter that rejects Entities with all specified Components and
|
||||
-- Filters, and selects all other Entities.
|
||||
-- @param ... List of required Components and other Filters.
|
||||
function tiny.rejectAll(...)
|
||||
local components = {...}
|
||||
local len = #components
|
||||
return function(system, e)
|
||||
local c
|
||||
for i = 1, len do
|
||||
c = components[i]
|
||||
if type(c) == 'function' then
|
||||
if not c(system, e) then
|
||||
return true
|
||||
end
|
||||
elseif e[c] == nil then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
return filterJoin('not', ' and ', ...)
|
||||
end
|
||||
|
||||
--- Makes a Filter that rejects Entities with at least one of the specified
|
||||
-- Components and Filters, and selects all other Entities.
|
||||
-- @param ... List of required Components and other Filters.
|
||||
function tiny.rejectAny(...)
|
||||
local components = {...}
|
||||
local len = #components
|
||||
return function(system, e)
|
||||
local c
|
||||
for i = 1, len do
|
||||
c = components[i]
|
||||
if type(c) == 'function' then
|
||||
if c(system, e) then
|
||||
return false
|
||||
end
|
||||
elseif e[c] ~= nil then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
return filterJoin('not', ' or ', ...)
|
||||
end
|
||||
|
||||
--- Makes a Filter from a string. Syntax of `pattern` is as follows.
|
||||
--
|
||||
-- * Tokens are alphanumeric strings including underscores.
|
||||
-- * Tokens can be separated by |, &, or surrounded by parentheses.
|
||||
-- * Tokens can be prefixed with !, and are then operated on with a boolean 'not'.
|
||||
--
|
||||
-- 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' component AND NOT a 'b' component AND a 'c' component.
|
||||
-- 'a|(b&c&d)|e - Matches 'a' OR ('b' AND 'c' AND 'd') OR 'e'
|
||||
-- @param pattern
|
||||
function tiny.filter(pattern)
|
||||
local state, value = pcall(filterBuildString, pattern)
|
||||
if state then return value else return nil, value end
|
||||
end
|
||||
|
||||
--- System functions.
|
||||
@@ -183,10 +211,19 @@ end
|
||||
--
|
||||
-- There are also a few other optional callbacks:
|
||||
--
|
||||
-- * `function system:filter(entity)`
|
||||
-- * `function system:onAdd(entity)`
|
||||
-- * `function system:onRemove(entity)`
|
||||
-- * `function system:onModify(dt)`
|
||||
-- * `function system:filter(entity)` - Returns true if this System should
|
||||
-- include this Entity, otherwise should return false. If this isn't specified,
|
||||
-- no Entities are included in the System.
|
||||
-- * `function system:onAdd(entity)` - Called when an Entity is added to the
|
||||
-- System.
|
||||
-- * `function system:onRemove(entity)` - Called when an Entity is removed
|
||||
-- from the System.
|
||||
-- * `function system:onModify(dt)` - Called when the System is modified by
|
||||
-- adding or removing Entities from the System.
|
||||
-- * `function system:onAddToWorld(world)` - Called when the System is added
|
||||
-- to the World, before any entities are added to the system.
|
||||
-- * `function system:onRemoveFromWorld(world)` - Called when the System is
|
||||
-- removed from the world, after all Entities are removed from the System.
|
||||
--
|
||||
-- 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
|
||||
@@ -201,11 +238,20 @@ end
|
||||
-- system is added to the World. A few are important, and few should be less
|
||||
-- commonly used.
|
||||
--
|
||||
-- * The `world` field points to the World that the System belongs to. Useful
|
||||
-- for adding and removing Entities from the world dynamically via the System.
|
||||
-- * The `active` flag is whether or not the System is updated automatically.
|
||||
-- Inactive Systems should be updated manually or not at all via
|
||||
-- `system:update(dt)`. Defaults to true.
|
||||
-- * The 'entities' field is an ordered list of Entities in the System. This
|
||||
-- * The `entities` field is an ordered list of Entities in the System. This
|
||||
-- list can be used to quickly iterate through all Entities in a System.
|
||||
-- * The `interval` field is an optional field that makes Systems update at
|
||||
-- certain intervals using buffered time, regardless of World update frequency.
|
||||
-- For example, to make a System update once a second, set the System's interval
|
||||
-- to 1.
|
||||
-- * The `index` field is the System's index in the World. Lower indexed
|
||||
-- Systems are processed before higher indices. The `index` is a read only
|
||||
-- field; to set the `index`, use `tiny.setSystemIndex(world, system)`.
|
||||
-- * The `indices` field is a table of Entity keys to their indices in the
|
||||
-- `entities` list. Most Systems can ignore this.
|
||||
-- * The `modified` flag is an indicator if the System has been modified in
|
||||
@@ -219,36 +265,26 @@ end
|
||||
-- this key is considered a System rather than an Entity.
|
||||
local systemTableKey = { "SYSTEM_TABLE_KEY" }
|
||||
|
||||
-- Check if tables are systems.
|
||||
-- Checks if a table is a System.
|
||||
local function isSystem(table)
|
||||
return table[systemTableKey]
|
||||
end
|
||||
|
||||
--- Creates a default System.
|
||||
-- @param table A table to be used as a System, or `nil` to create a new System.
|
||||
-- @return A new System or System class
|
||||
function tiny.system(table)
|
||||
table = table or {}
|
||||
table[systemTableKey] = true
|
||||
return table
|
||||
end
|
||||
|
||||
-- Update function for all Processing Systems.
|
||||
local function processingSystemUpdate(system, dt)
|
||||
local entities = system.entities
|
||||
local preProcess = system.preProcess
|
||||
local process = system.process
|
||||
local postProcess = system.postProcess
|
||||
local entity
|
||||
|
||||
if preProcess then
|
||||
preProcess(system, dt)
|
||||
end
|
||||
|
||||
if process then
|
||||
local entities = system.entities
|
||||
local len = #entities
|
||||
for i = 1, len do
|
||||
entity = entities[i]
|
||||
local entity = entities[i]
|
||||
process(system, entity, dt)
|
||||
end
|
||||
end
|
||||
@@ -258,24 +294,45 @@ local function processingSystemUpdate(system, dt)
|
||||
end
|
||||
end
|
||||
|
||||
--- Creates a Processing System.
|
||||
-- Sorts Systems by a function system.sort(entity1, entity2) on modify.
|
||||
local function sortedSystemOnModify(system, dt)
|
||||
local entities = system.entities
|
||||
local indices = system.indices
|
||||
local sortDelegate = system.sortDelegate
|
||||
if not sortDelegate then
|
||||
local compare = system.compare
|
||||
sortDelegate = function(e1, e2)
|
||||
return compare(system, e1, e2)
|
||||
end
|
||||
system.sortDelegate = sortDelegate
|
||||
end
|
||||
tsort(entities, sortDelegate)
|
||||
for i = 1, #entities do
|
||||
local entity = entities[i]
|
||||
indices[entity] = i
|
||||
end
|
||||
end
|
||||
|
||||
--- Creates a new System or System class from the supplied table. If `table` is
|
||||
-- nil, creates a new table.
|
||||
function tiny.system(table)
|
||||
table = table or {}
|
||||
table[systemTableKey] = true
|
||||
return table
|
||||
end
|
||||
|
||||
--- Creates a new Processing System or Processing System class. Processing
|
||||
-- Systems process each entity individual, and are usually what is needed.
|
||||
-- Processing Systems have three extra callbacks besides those inheritted from
|
||||
-- vanilla Systems.
|
||||
--
|
||||
-- A Processing System iterates through its Entities in no particluar order, and
|
||||
-- updates them individually. It has two important fields:
|
||||
-- function system:preProcess(dt) -- Called before iteration.
|
||||
-- function system:process(entity, dt) -- Process each entity.
|
||||
-- function system:postProcess(dt) -- Called after iteration.
|
||||
--
|
||||
-- * `function system:process(entity, dt)`
|
||||
-- * `function system:filter(entity)`
|
||||
--
|
||||
-- There are also a few other optional callbacks, including the optional
|
||||
-- callbacks in `tiny.system`:
|
||||
--
|
||||
-- * `function system:preProcess(entities, dt)`
|
||||
-- * `function system:postProcess(entities, dt)`
|
||||
--
|
||||
-- @param table A table to be used as a System, or `nil` to create a new
|
||||
-- Processing System.
|
||||
-- Processing Systems have their own `update` method, so don't implement a
|
||||
-- a custom `update` callback for Processing Systems.
|
||||
-- @see system
|
||||
-- @return A new Processing System or Processing System class
|
||||
function tiny.processingSystem(table)
|
||||
table = table or {}
|
||||
table[systemTableKey] = true
|
||||
@@ -283,45 +340,31 @@ function tiny.processingSystem(table)
|
||||
return table
|
||||
end
|
||||
|
||||
-- Sorts Systems by a function system.sort(entity1, entity2) on modify.
|
||||
local function sortedSystemOnModify(system, dt)
|
||||
local entities = system.entities
|
||||
local entityIndices = system.entityIndices
|
||||
local sortDelegate = system.sortDelegate
|
||||
if not sortDelegate then
|
||||
local compare = system.compare
|
||||
sortDelegate = function(e1, e2)
|
||||
compare(system, e1, e2)
|
||||
end
|
||||
system.sortDelegate = sortDelegate
|
||||
end
|
||||
tsort(entities, sortDelegate)
|
||||
for i = 1, #entities do
|
||||
local entity = entities[i]
|
||||
entityIndices[entity] = i
|
||||
end
|
||||
--- Creates a new Sorted System or Sorted System class. Sorted Systems sort
|
||||
-- their Entities according to a user-defined method, `system:compare(e1, e2)`,
|
||||
-- which should return true if `e1` should come before `e2` and false otherwise.
|
||||
-- Sorted Systems also override the default System's `onModify` callback, so be
|
||||
-- careful if defining a custom callback. However, for processing the sorted
|
||||
-- entities, consider `tiny.sortedProcessingSystem(table)`.
|
||||
-- @see system
|
||||
function tiny.sortedSystem(table)
|
||||
table = table or {}
|
||||
table[systemTableKey] = true
|
||||
table.onModify = sortedSystemOnModify
|
||||
return table
|
||||
end
|
||||
|
||||
--- Creates a Sorted Processing System. A Sorted System iterates through its
|
||||
-- Entities in a specific order, and updates them individually. It has three
|
||||
-- important methods:
|
||||
--
|
||||
-- * `function system:process(entity, dt)`
|
||||
-- * `function system:compare(entity1, entity2)`
|
||||
-- * `function system:filter(entity)`
|
||||
--
|
||||
-- Sorted Systems have the same optitonal callbacks as ProcessingSystems.
|
||||
-- @param table A table to be used as a System, or `nil` to create a new
|
||||
-- Sorted System.
|
||||
--- Creates a new Sorted Processing System or Sorted Processing System class.
|
||||
-- Sorted Processing Systems have both the aspects of Processing Systems and
|
||||
-- Sorted Systems.
|
||||
-- @see system
|
||||
-- @see processingSystem
|
||||
-- @return A new Sorted System or Sorted System class
|
||||
function tiny.sortedSystem(table)
|
||||
-- @see sortedSystem
|
||||
function tiny.sortedProcessingSystem(table)
|
||||
table = table or {}
|
||||
table[systemTableKey] = true
|
||||
table.update = processingSystemUpdate
|
||||
table.onModify = sortedSystemOnModify
|
||||
table.sort = sortedSystemOnModify
|
||||
return table
|
||||
end
|
||||
|
||||
@@ -338,12 +381,10 @@ end
|
||||
local worldMetaTable
|
||||
|
||||
--- Creates a new World.
|
||||
-- Can optionally add default Systems and Entities.
|
||||
-- @param ... Systems and Entities to add to the World
|
||||
-- @return A new World
|
||||
-- Can optionally add default Systems and Entities. Returns the new World along
|
||||
-- with default Entities and Systems.
|
||||
function tiny.world(...)
|
||||
|
||||
local ret = {
|
||||
local ret = setmetatable({
|
||||
|
||||
-- List of Entities to add
|
||||
entitiesToAdd = {},
|
||||
@@ -351,6 +392,9 @@ function tiny.world(...)
|
||||
-- List of Entities to remove
|
||||
entitiesToRemove = {},
|
||||
|
||||
-- List of Entities to change
|
||||
entitiesToChange = {},
|
||||
|
||||
-- List of Entities to add
|
||||
systemsToAdd = {},
|
||||
|
||||
@@ -360,57 +404,50 @@ function tiny.world(...)
|
||||
-- Set of Entities
|
||||
entities = {},
|
||||
|
||||
-- Number of Entities in World.
|
||||
-- Number of Entities in World
|
||||
entityCount = 0,
|
||||
|
||||
-- List of System Data. A data element is a table with 4
|
||||
-- keys: system, indices, entities, and active.
|
||||
systems = {},
|
||||
|
||||
-- Table of Systems to System Indices
|
||||
systemIndices = {}
|
||||
}
|
||||
-- List of Systems
|
||||
systems = {}
|
||||
}, worldMetaTable)
|
||||
|
||||
tiny_add(ret, ...)
|
||||
tiny_manageSystems(ret)
|
||||
tiny_manageEntities(ret)
|
||||
|
||||
return setmetatable(ret, worldMetaTable)
|
||||
|
||||
return ret, ...
|
||||
end
|
||||
|
||||
--- Adds an Entity to the world.
|
||||
-- Also call this on Entities that have changed Components such that they
|
||||
-- match different Filters.
|
||||
-- @param world
|
||||
-- @param entity
|
||||
-- match different Filters. Returns the Entity.
|
||||
function tiny.addEntity(world, entity)
|
||||
if world.entities[entity] then
|
||||
local e2c = world.entitiesToChange
|
||||
e2c[#e2c + 1] = entity
|
||||
else
|
||||
local e2a = world.entitiesToAdd
|
||||
e2a[#e2a + 1] = entity
|
||||
if world.entities[entity] then
|
||||
tiny_removeEntity(world, entity)
|
||||
end
|
||||
return entity
|
||||
end
|
||||
tiny_addEntity = tiny.addEntity
|
||||
|
||||
--- Adds a System to the world.
|
||||
-- @param world
|
||||
-- @param system
|
||||
--- Adds a System to the world. Returns the System.
|
||||
function tiny.addSystem(world, system)
|
||||
assert(system.world == nil, "System already belongs to a World.")
|
||||
local s2a = world.systemsToAdd
|
||||
s2a[#s2a + 1] = system
|
||||
system.world = world
|
||||
return system
|
||||
end
|
||||
tiny_addSystem = tiny.addSystem
|
||||
|
||||
--- Shortcut for adding multiple Entities and Systems to the World.
|
||||
-- @param world
|
||||
-- @param ... Systems and Entities
|
||||
-- @see addEntity
|
||||
-- @see addSystem
|
||||
--- Shortcut for adding multiple Entities and Systems to the World. Returns all
|
||||
-- added Entities and Systems.
|
||||
function tiny.add(world, ...)
|
||||
local obj
|
||||
for i = 1, select("#", ...) do
|
||||
obj = select(i, ...)
|
||||
local obj = select(i, ...)
|
||||
if obj then
|
||||
if isSystem(obj) then
|
||||
tiny_addSystem(world, obj)
|
||||
@@ -419,36 +456,32 @@ function tiny.add(world, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
return ...
|
||||
end
|
||||
tiny_add = tiny.add
|
||||
|
||||
--- Removes an Entity to the World.
|
||||
-- @param world
|
||||
-- @param entity
|
||||
--- Removes an Entity to the World. Returns the Entity.
|
||||
function tiny.removeEntity(world, entity)
|
||||
local e2r = world.entitiesToRemove
|
||||
e2r[#e2r + 1] = entity
|
||||
return entity
|
||||
end
|
||||
tiny_removeEntity = tiny.removeEntity
|
||||
|
||||
--- Removes a System from the world.
|
||||
-- @param world
|
||||
-- @param system
|
||||
--- Removes a System from the world. Returns the System.
|
||||
function tiny.removeSystem(world, system)
|
||||
assert(system.world == world, "System does not belong to this World.")
|
||||
local s2r = world.systemsToRemove
|
||||
s2r[#s2r + 1] = system
|
||||
return system
|
||||
end
|
||||
tiny_removeSystem = tiny.removeSystem
|
||||
|
||||
--- Shortcut for removing multiple Entities and Systems from the World.
|
||||
-- @param world
|
||||
-- @param ... Systems and Entities
|
||||
-- @see removeEntity
|
||||
-- @see removeSystem
|
||||
--- Shortcut for removing multiple Entities and Systems from the World. Returns
|
||||
-- all removed Systems and Entities
|
||||
function tiny.remove(world, ...)
|
||||
local obj
|
||||
for i = 1, select("#", ...) do
|
||||
obj = select(i, ...)
|
||||
local obj = select(i, ...)
|
||||
if obj then
|
||||
if isSystem(obj) then
|
||||
tiny_removeSystem(world, obj)
|
||||
@@ -457,12 +490,12 @@ function tiny.remove(world, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
return ...
|
||||
end
|
||||
tiny_remove = tiny.remove
|
||||
|
||||
-- Adds and removes Systems that have been marked from the World.
|
||||
function tiny_manageSystems(world)
|
||||
|
||||
local s2a, s2r = world.systemsToAdd, world.systemsToRemove
|
||||
|
||||
-- Early exit
|
||||
@@ -470,54 +503,68 @@ function tiny_manageSystems(world)
|
||||
return
|
||||
end
|
||||
|
||||
local systemIndices = world.systemIndices
|
||||
world.systemsToAdd = {}
|
||||
world.systemsToRemove = {}
|
||||
|
||||
local entities = world.entities
|
||||
local systems = world.systems
|
||||
local system, index, filter
|
||||
local entityList, entityIndices, entityIndex, onRemove, onAdd
|
||||
|
||||
-- Remove Systems
|
||||
for i = 1, #s2r do
|
||||
system = s2r[i]
|
||||
index = systemIndices[system]
|
||||
if index then
|
||||
onRemove = system.onRemove
|
||||
local system = s2r[i]
|
||||
local index = system.index
|
||||
local onRemove = system.onRemove
|
||||
if onRemove then
|
||||
entityList = system.entities
|
||||
local entityList = system.entities
|
||||
for j = 1, #entityList do
|
||||
onRemove(system, entityList[j])
|
||||
end
|
||||
end
|
||||
systemIndices[system] = nil
|
||||
tremove(systems, index)
|
||||
for j = index, #systems do
|
||||
systemIndices[systems[j]] = j
|
||||
systems[j].index = j
|
||||
end
|
||||
local onRemoveFromWorld = system.onRemoveFromWorld
|
||||
if onRemoveFromWorld then
|
||||
onRemoveFromWorld(system, world)
|
||||
end
|
||||
s2r[i] = nil
|
||||
|
||||
-- Clean up System
|
||||
system.world = nil
|
||||
system.entities = nil
|
||||
system.indices = nil
|
||||
system.index = nil
|
||||
end
|
||||
|
||||
-- Add Systems
|
||||
for i = 1, #s2a do
|
||||
system = s2a[i]
|
||||
if not systemIndices[system] then
|
||||
entityList = {}
|
||||
entityIndices = {}
|
||||
local system = s2a[i]
|
||||
if systems[system.index] ~= system then
|
||||
local entityList = {}
|
||||
local entityIndices = {}
|
||||
system.entities = entityList
|
||||
system.indices = entityIndices
|
||||
if system.active == nil then
|
||||
system.active = true
|
||||
end
|
||||
system.modified = true
|
||||
index = #systems + 1
|
||||
systemIndices[system] = index
|
||||
system.world = world
|
||||
local index = #systems + 1
|
||||
system.index = index
|
||||
systems[index] = system
|
||||
local onAddToWorld = system.onAddToWorld
|
||||
if onAddToWorld then
|
||||
onAddToWorld(system, world)
|
||||
end
|
||||
|
||||
-- Try to add Entities
|
||||
onAdd = system.onAdd
|
||||
filter = system.filter
|
||||
local onAdd = system.onAdd
|
||||
local filter = system.filter
|
||||
if filter then
|
||||
for entity in pairs(entities) do
|
||||
if filter(system, entity) then
|
||||
entityIndex = #entityList + 1
|
||||
local entityIndex = #entityList + 1
|
||||
entityList[entityIndex] = entity
|
||||
entityIndices[entity] = entityIndex
|
||||
if onAdd then
|
||||
@@ -529,120 +576,171 @@ function tiny_manageSystems(world)
|
||||
end
|
||||
s2a[i] = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Adds and removes Entities that have been marked.
|
||||
-- Adds, removes, and changes Entities that have been marked.
|
||||
function tiny_manageEntities(world)
|
||||
|
||||
local e2a, e2r = world.entitiesToAdd, world.entitiesToRemove
|
||||
local e2a = world.entitiesToAdd
|
||||
local e2r = world.entitiesToRemove
|
||||
local e2c = world.entitiesToChange
|
||||
|
||||
-- Early exit
|
||||
if #e2a == 0 and #e2r == 0 then
|
||||
if #e2a == 0 and #e2r == 0 and #e2c == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
world.entitiesToChange = {}
|
||||
world.entitiesToAdd = {}
|
||||
world.entitiesToRemove = {}
|
||||
|
||||
local entities = world.entities
|
||||
local systems = world.systems
|
||||
local entityCount = world.entityCount
|
||||
local entity, system, index
|
||||
local onRemove, onAdd, ses, seis, filter, tmpEntity
|
||||
|
||||
-- Remove Entities
|
||||
for i = 1, #e2r do
|
||||
entity = e2r[i]
|
||||
-- Change Entities
|
||||
for i = 1, #e2c do
|
||||
local entity = e2c[i]
|
||||
if entities[entity] then
|
||||
entities[entity] = nil
|
||||
|
||||
for j = 1, #systems do
|
||||
system = systems[j]
|
||||
ses = system.entities
|
||||
seis = system.indices
|
||||
index = seis[entity]
|
||||
|
||||
if index then
|
||||
system.modified = true
|
||||
tmpEntity = ses[#ses]
|
||||
ses[index] = tmpEntity
|
||||
seis[tmpEntity] = index
|
||||
seis[entity] = nil
|
||||
ses[#ses] = nil
|
||||
entityCount = entityCount - 1
|
||||
onRemove = system.onRemove
|
||||
if onRemove then
|
||||
onRemove(system, entity)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
e2r[i] = nil
|
||||
end
|
||||
|
||||
|
||||
-- Add Entities
|
||||
for i = 1, #e2a do
|
||||
entity = e2a[i]
|
||||
if not entities[entity] then
|
||||
entities[entity] = true
|
||||
|
||||
for j = 1, #systems do
|
||||
system = systems[j]
|
||||
ses = system.entities
|
||||
seis = system.indices
|
||||
filter = system.filter
|
||||
local system = systems[j]
|
||||
local ses = system.entities
|
||||
local seis = system.indices
|
||||
local index = seis[entity]
|
||||
local filter = system.filter
|
||||
if filter and filter(system, entity) then
|
||||
if not index then
|
||||
system.modified = true
|
||||
index = #ses + 1
|
||||
ses[index] = entity
|
||||
seis[entity] = index
|
||||
entityCount = entityCount + 1
|
||||
onAdd = system.onAdd
|
||||
local onAdd = system.onAdd
|
||||
if onAdd then
|
||||
onAdd(system, entity)
|
||||
end
|
||||
end
|
||||
|
||||
elseif index then
|
||||
system.modified = true
|
||||
local tmpEntity = ses[#ses]
|
||||
ses[index] = tmpEntity
|
||||
seis[tmpEntity] = index
|
||||
seis[entity] = nil
|
||||
ses[#ses] = nil
|
||||
local onRemove = system.onRemove
|
||||
if onRemove then
|
||||
onRemove(system, entity)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
e2c[i] = nil
|
||||
end
|
||||
|
||||
-- Remove Entities
|
||||
for i = 1, #e2r do
|
||||
local entity = e2r[i]
|
||||
if entities[entity] then
|
||||
entities[entity] = nil
|
||||
entityCount = entityCount - 1
|
||||
for j = 1, #systems do
|
||||
local system = systems[j]
|
||||
local ses = system.entities
|
||||
local seis = system.indices
|
||||
local index = seis[entity]
|
||||
if index then
|
||||
system.modified = true
|
||||
local tmpEntity = ses[#ses]
|
||||
ses[index] = tmpEntity
|
||||
seis[tmpEntity] = index
|
||||
seis[entity] = nil
|
||||
ses[#ses] = nil
|
||||
local onRemove = system.onRemove
|
||||
if onRemove then
|
||||
onRemove(system, entity)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
e2r[i] = nil
|
||||
end
|
||||
|
||||
-- Add Entities
|
||||
for i = 1, #e2a do
|
||||
local entity = e2a[i]
|
||||
if not entities[entity] then
|
||||
entities[entity] = true
|
||||
entityCount = entityCount + 1
|
||||
for j = 1, #systems do
|
||||
local system = systems[j]
|
||||
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
|
||||
e2a[i] = nil
|
||||
end
|
||||
|
||||
-- Update Entity count
|
||||
world.entityCount = entityCount
|
||||
|
||||
end
|
||||
|
||||
--- Updates the World.
|
||||
-- Put this in your main loop.
|
||||
-- @param world
|
||||
-- @param dt Delta time
|
||||
function tiny.update(world, dt)
|
||||
--- Manages Entities and Systems marked for deletion or addition. Call this
|
||||
-- before modifying Systems and Entities outside of a call to `tiny.update`.
|
||||
-- Do not call this within a call to `tiny.update`.
|
||||
function tiny.refresh(world)
|
||||
tiny_manageSystems(world)
|
||||
tiny_manageEntities(world)
|
||||
end
|
||||
|
||||
--- Updates the World by dt (delta time). Takes an optional parameter, `filter`,
|
||||
-- which is a Filter that selects Systems from the World, and updates only those
|
||||
-- Systems. If `filter` is not supplied, all Systems are updated. Put this
|
||||
-- function in your main loop.
|
||||
function tiny.update(world, dt, filter)
|
||||
|
||||
tiny_manageSystems(world)
|
||||
tiny_manageEntities(world)
|
||||
|
||||
local systems = world.systems
|
||||
local system, update, onModify, entities
|
||||
|
||||
-- Iterate through Systems IN ORDER
|
||||
for i = 1, #systems do
|
||||
system = systems[i]
|
||||
if system.active then
|
||||
local system = systems[i]
|
||||
if system.active and ((not filter) or filter(world, system)) then
|
||||
|
||||
-- Call the modify callback on Systems that have been modified.
|
||||
onModify = system.onModify
|
||||
local onModify = system.onModify
|
||||
if onModify and system.modified then
|
||||
onModify(system, dt)
|
||||
end
|
||||
|
||||
--Update Systems that have an update method (most Systems)
|
||||
update = system.update
|
||||
-- Update Systems that have an update method (most Systems)
|
||||
local update = system.update
|
||||
if update then
|
||||
local interval = system.interval
|
||||
if interval then
|
||||
local bufferedTime = (system.bufferedTime or 0) + dt
|
||||
while bufferedTime >= interval do
|
||||
bufferedTime = bufferedTime - interval
|
||||
if update then
|
||||
update(system, interval)
|
||||
end
|
||||
end
|
||||
system.bufferedTime = bufferedTime
|
||||
else
|
||||
update(system, dt)
|
||||
end
|
||||
end
|
||||
|
||||
system.modified = false
|
||||
end
|
||||
@@ -650,7 +748,6 @@ function tiny.update(world, dt)
|
||||
end
|
||||
|
||||
--- Removes all Entities from the World.
|
||||
-- @param world
|
||||
function tiny.clearEntities(world)
|
||||
for e in pairs(world.entities) do
|
||||
tiny_removeEntity(world, e)
|
||||
@@ -658,7 +755,6 @@ function tiny.clearEntities(world)
|
||||
end
|
||||
|
||||
--- Removes all Systems from the World.
|
||||
-- @param world
|
||||
function tiny.clearSystems(world)
|
||||
local systems = world.systems
|
||||
for i = #systems, 1, -1 do
|
||||
@@ -667,46 +763,37 @@ function tiny.clearSystems(world)
|
||||
end
|
||||
|
||||
--- Gets number of Entities in the World.
|
||||
-- @param world
|
||||
-- @return An integer
|
||||
function tiny.getEntityCount(world)
|
||||
return world.entityCount
|
||||
end
|
||||
|
||||
--- Gets number of Systems in World.
|
||||
-- @param world
|
||||
-- @return An integer
|
||||
function tiny.getSystemCount(world)
|
||||
return #(world.systems)
|
||||
end
|
||||
|
||||
--- Gets the index of a System in the World. Lower indexed Systems are processed
|
||||
-- before higher indexed systems.
|
||||
-- @param world
|
||||
-- @param system
|
||||
-- @return An integer between 1 and world:getSystemCount() inclusive
|
||||
--- Gets the index of the System in the World.
|
||||
-- A simpler alternative is `system.index`.
|
||||
function tiny.getSystemIndex(world, system)
|
||||
return world.systemIndices[system]
|
||||
return system.index
|
||||
end
|
||||
|
||||
--- Sets the index of a System in the World. Changes the order in
|
||||
-- which they Systems processed, because lower indexed Systems are processed
|
||||
-- first.
|
||||
-- @param world
|
||||
-- @param system
|
||||
-- @param index
|
||||
-- @return Old index
|
||||
--- Sets the index of a System in the World, and returns the old index. Changes
|
||||
-- the order in which they Systems processed, because lower indexed Systems are
|
||||
-- processed first. Returns the old system.index.
|
||||
function tiny.setSystemIndex(world, system, index)
|
||||
local systemIndices = world.systemIndices
|
||||
local oldIndex = systemIndices[system]
|
||||
local oldIndex = system.index
|
||||
local systems = world.systems
|
||||
local system = systems[oldIndex]
|
||||
|
||||
if index < 0 then
|
||||
index = tiny.getSystemCount(world) + 1 + index
|
||||
end
|
||||
|
||||
tremove(systems, oldIndex)
|
||||
tinsert(systems, index, system)
|
||||
|
||||
for i = oldIndex, index, index >= oldIndex and 1 or -1 do
|
||||
systemIndices[systems[i]] = i
|
||||
systems[i].index = i
|
||||
end
|
||||
|
||||
return oldIndex
|
||||
@@ -720,6 +807,8 @@ worldMetaTable = {
|
||||
addSystem = tiny.addSystem,
|
||||
remove = tiny.remove,
|
||||
removeEntity = tiny.removeEntity,
|
||||
removeSystem = tiny.removeSystem,
|
||||
refresh = tiny.refresh,
|
||||
update = tiny.update,
|
||||
clearEntities = tiny.clearEntities,
|
||||
clearSystems = tiny.clearSystems,
|
||||
@@ -727,7 +816,10 @@ worldMetaTable = {
|
||||
getSystemCount = tiny.getSystemCount,
|
||||
getSystemIndex = tiny.getSystemIndex,
|
||||
setSystemIndex = tiny.setSystemIndex
|
||||
}
|
||||
},
|
||||
__tostring = function(self)
|
||||
return "<tiny-ecs_World>"
|
||||
end
|
||||
}
|
||||
|
||||
return tiny
|
||||
|
||||
Reference in New Issue
Block a user