10 Commits

Author SHA1 Message Date
bakpakin
5978ace463 Update to version 1.1-3 2015-06-14 10:22:03 -04:00
bakpakin
a504bd6336 Add removeSystem to World metatable. 2015-06-14 10:17:18 -04:00
bakpakin
69ae37586e Fix scm rockspec. 2015-06-07 20:05:56 -04:00
bakpakin
44fb94c457 Add scm rockspec. Fix README. 2015-06-07 18:47:50 -04:00
bakpakin
9230dad1e1 Update README.md to direct users to demo. 2015-05-17 08:26:04 +08:00
bakpakin
e4bf3f3767 Update to version 1.1-2. 2015-05-07 19:53:51 +08:00
bakpakin
71e97c12f6 Improve System documentation. 2015-05-07 19:45:28 +08:00
bakpakin
7c4ff7747c Change names of tiny.requireOne and tiny.rejectOne to tiny.requireAny and tiny.rejectAny. 2015-05-07 17:32:32 +08:00
bakpakin
808407f7c4 Fix 'tiny.add' and 'tiny.remove' iterating nil values. 2015-05-05 22:21:39 +08:00
bakpakin
153f326612 Add two new filter functions - rejectAll and rejectOne. 2015-05-05 22:03:04 +08:00
6 changed files with 236 additions and 50 deletions
+7 -11
View File
@@ -5,9 +5,11 @@ for simulating large and complex systems. For more explanation on Entity
Component Systems, here is some
[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, 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 +31,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 +66,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
@@ -81,11 +83,5 @@ Tiny-ecs uses [busted](http://olivinelabs.com/busted/) for testing. Install and
## Documentation ##
See API [here](http://bakpakin.github.io/tiny-ecs/doc/).
Documentation can be generated locally with [LDoc](http://stevedonovan.github.io/ldoc/).
## TODO ##
* More testing
* Performance testing / optimization
* Add more System types
* Improve Documentation
For the most up-to-date documentation, read the source code, or generate the HTML
locally with [LDoc](http://stevedonovan.github.io/ldoc/).
+24
View File
@@ -0,0 +1,24 @@
package = "tiny-ecs"
version = "1.1-2"
source = {
url = "git://github.com/bakpakin/tiny-ecs",
tag = "1.1-2"
}
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.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"
}
}
+16 -1
View File
@@ -56,7 +56,14 @@ describe('tiny-ecs:', function()
local ftap = tiny.requireAll("spinalTap")
local fvel = tiny.requireAll("vel")
local fxform = tiny.requireAll("xform")
local fall = tiny.requireOne("spinalTap", "onlyTen", "littleMan")
local fall = tiny.requireAny("spinalTap", "onlyTen", "littleMan")
-- Only select Entities without "spinalTap"
local frtap = tiny.rejectAny("spinalTap")
-- Select Entities without all three: "spinalTap", "onlyTen", and
-- "littleMan"
local frall = tiny.rejectAll("spinalTap", "onlyTen", "littleMan")
assert.truthy(fall(nil, entity1))
assert.truthy(ftap(nil, entity1))
@@ -68,6 +75,14 @@ describe('tiny-ecs:', function()
assert.truthy(fall(nil, entity2))
assert.truthy(fall(nil, entity3))
assert.falsy(frtap(nil, entity1))
assert.truthy(frtap(nil, entity2))
assert.truthy(frtap(nil, entity3))
assert.truthy(frall(nil, entity1))
assert.truthy(frall(nil, entity2))
assert.truthy(frall(nil, entity3))
end)
end)
+23
View File
@@ -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"
}
}
+134 -30
View File
@@ -23,7 +23,7 @@ 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-1" }
local tiny = { _VERSION = "1.1-3" }
-- Local versions of standard lua functions
local tinsert = table.insert
@@ -33,6 +33,7 @@ local pairs = pairs
local ipairs = ipairs
local setmetatable = setmetatable
local type = type
local select = select
-- Local versions of the library functions
local tiny_manageEntities
@@ -50,11 +51,11 @@ 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.requireOne` are immutable
-- Filter's returned by `tiny.requireAll` and `tiny.requireAny` are immutable
-- and can be used by multiple Systems.
--
-- local f1 = tiny.requireAll("position", "velocity", "size")
-- local f2 = tiny.requireOne("position", "velocity", "size")
-- local f2 = tiny.requireAny("position", "velocity", "size")
--
-- local e1 = {
-- position = {2, 3},
@@ -75,6 +76,14 @@ local tiny_remove
-- print(f1(nil, e1), f1(nil, e2), f1(nil, e3)) -- prints true, false, false
-- print(f2(nil, e1), f2(nil, e2), f2(nil, e3)) -- prints true, true, true
--
-- Filters can also be passed as arguments to other Filter constructors. This is
-- a powerful way to create complex, custom Filters that select a very specific
-- set of Entities.
--
-- -- Selects Entities with an "image" Component, but not Entities with a
-- -- "Player" or "Enemy" Component.
-- filter = tiny.requireAll("image", tiny.rejectAny("Player", "Enemy"))
--
-- @section Filter
--- Makes a Filter that selects Entities with all specified Components and
@@ -102,7 +111,7 @@ 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.requireOne(...)
function tiny.requireAny(...)
local components = {...}
local len = #components
return function(system, e)
@@ -121,20 +130,53 @@ function tiny.requireOne(...)
end
end
--- System functions.
-- A System is a wrapper around function callbacks for manipulating Entities.
-- @section System
-- Use an empty table as a key for identifying Systems. Any table that contains
-- this key is considered a System rather than an Entity.
local systemTableKey = { "SYSTEM_TABLE_KEY" }
-- Check if tables are systems.
local function isSystem(table)
return table[systemTableKey]
--- 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
end
--- Creates a System. Systems are tables that contain at least one method;
--- 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
end
--- System functions.
-- A System is a wrapper around function callbacks for manipulating Entities.
-- Systems are implemented as tables that contain at least one method;
-- an update function that takes parameters like so:
--
-- * `function system:update(dt)`.
@@ -146,16 +188,45 @@ end
-- * `function system:onRemove(entity)`
-- * `function system:onModify(dt)`
--
-- For Filters, it is conveient to use `tiny.requireAll` or `tiny.requireOne`,
-- but one can write their own filters as well. Set the Filter of your System
-- like so:
-- 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
-- so:
-- system.filter = tiny.requireAll("a", "b", "c")
-- or
-- function system:filter(entity)
-- return entity.myRequiredComponentName ~= nil
-- end
--
-- All Systems also have a few important fields that are initialized when the
-- system is added to the World. A few are important, and few should be less
-- commonly used.
--
-- * 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
-- list can be used to quickly iterate through all Entities in a 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
-- the last update. If so, the `onModify` callback will be called on the System
-- in the next update, if it has one. This is usually managed by tiny-ecs, so
-- users should mostly ignore this, too.
--
-- @section System
-- Use an empty table as a key for identifying Systems. Any table that contains
-- this key is considered a System rather than an Entity.
local systemTableKey = { "SYSTEM_TABLE_KEY" }
-- Check if tables are systems.
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
@@ -204,6 +275,7 @@ end
-- @param table A table to be used as a System, or `nil` to create a new
-- Processing System.
-- @see system
-- @return A new Processing System or Processing System class
function tiny.processingSystem(table)
table = table or {}
table[systemTableKey] = true
@@ -243,6 +315,7 @@ end
-- Sorted System.
-- @see system
-- @see processingSystem
-- @return A new Sorted System or Sorted System class
function tiny.sortedSystem(table)
table = table or {}
table[systemTableKey] = true
@@ -256,13 +329,13 @@ end
-- A World is a container that manages Entities and Systems. Typically, a
-- program uses one World at a time.
--
-- The tiny-ecs module is set to be the `__index` of all World tables, so the
-- often clearer syntax of `world:method()` can be used for any function in the
-- library. For example, `tiny.add(world, e1, e2, e3)` is the same as
-- `world:add(e1, e2, e3).`
-- For all World functions except `tiny.world(...)`, object-oriented syntax can
-- be used instead of the documented syntax. For example,
-- `tiny.add(world, e1, e2, e3)` is the same as `world:add(e1, e2, e3)`.
-- @section World
local worldMetaTable = { __index = tiny }
-- Forward declaration
local worldMetaTable
--- Creates a new World.
-- Can optionally add default Systems and Entities.
@@ -335,14 +408,17 @@ tiny_addSystem = tiny.addSystem
-- @see addEntity
-- @see addSystem
function tiny.add(world, ...)
local args = {...}
for _, obj in ipairs(args) do
local obj
for i = 1, select("#", ...) do
obj = select(i, ...)
if obj then
if isSystem(obj) then
tiny_addSystem(world, obj)
else -- Assume obj is an Entity
tiny_addEntity(world, obj)
end
end
end
end
tiny_add = tiny.add
@@ -370,14 +446,17 @@ tiny_removeSystem = tiny.removeSystem
-- @see removeEntity
-- @see removeSystem
function tiny.remove(world, ...)
local args = {...}
for _, obj in ipairs(args) do
local obj
for i = 1, select("#", ...) do
obj = select(i, ...)
if obj then
if isSystem(obj) then
tiny_removeSystem(world, obj)
else -- Assume obj is an Entity
tiny_removeEntity(world, obj)
end
end
end
end
tiny_remove = tiny.remove
@@ -587,14 +666,16 @@ function tiny.clearSystems(world)
end
end
--- Gets count of Entities in World.
--- Gets number of Entities in the World.
-- @param world
-- @return An integer
function tiny.getEntityCount(world)
return world.entityCount
end
--- Gets count of Systems in World.
--- Gets number of Systems in World.
-- @param world
-- @return An integer
function tiny.getSystemCount(world)
return #(world.systems)
end
@@ -603,6 +684,7 @@ end
-- before higher indexed systems.
-- @param world
-- @param system
-- @return An integer between 1 and world:getSystemCount() inclusive
function tiny.getSystemIndex(world, system)
return world.systemIndices[system]
end
@@ -613,6 +695,7 @@ end
-- @param world
-- @param system
-- @param index
-- @return Old index
function tiny.setSystemIndex(world, system, index)
local systemIndices = world.systemIndices
local oldIndex = systemIndices[system]
@@ -625,6 +708,27 @@ function tiny.setSystemIndex(world, system, index)
for i = oldIndex, index, index >= oldIndex and 1 or -1 do
systemIndices[systems[i]] = i
end
return oldIndex
end
-- Construct world metatable.
worldMetaTable = {
__index = {
add = tiny.add,
addEntity = tiny.addEntity,
addSystem = tiny.addSystem,
remove = tiny.remove,
removeEntity = tiny.removeEntity,
removeSystem = tiny.removeSystem,
update = tiny.update,
clearEntities = tiny.clearEntities,
clearSystems = tiny.clearSystems,
getEntityCount = tiny.getEntityCount,
getSystemCount = tiny.getSystemCount,
getSystemIndex = tiny.getSystemIndex,
setSystemIndex = tiny.setSystemIndex
}
}
return tiny