mirror of
https://github.com/Keyslam-Group/Concord.git
synced 2025-12-07 21:54:50 -05:00
Update docs
This commit is contained in:
parent
f640258852
commit
b906e2a910
1 changed files with 68 additions and 134 deletions
200
README.md
200
README.md
|
|
@ -25,11 +25,10 @@ Auto generated docs for Concord can be found in `docs` folder, or on the [Github
|
||||||
[Contributors](#contributors)
|
[Contributors](#contributors)
|
||||||
[License](#licence)
|
[License](#licence)
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
Download the repository and copy the 'src' folder in your project. Rename it to something that makes sense (Probably 'concord'), then require it in your project like so:
|
Download the repository and copy the 'concord' folder into your project. Then require it in your project like so:
|
||||||
```lua
|
```lua
|
||||||
local Concord = require("path.to.concord")
|
local Concord = require("path.to.concord")
|
||||||
```
|
```
|
||||||
|
|
@ -42,13 +41,9 @@ local Entity = Concord.entity
|
||||||
local Component = Concord.component
|
local Component = Concord.component
|
||||||
local System = Concord.system
|
local System = Concord.system
|
||||||
local World = Concord.world
|
local World = Concord.world
|
||||||
local Assemblage = Concord.assemblage
|
|
||||||
|
|
||||||
-- Containers
|
-- Containers
|
||||||
local Components = Concord.components
|
local Components = Concord.components
|
||||||
local Systems = Concord.systems
|
|
||||||
local Worlds = Concord.worlds
|
|
||||||
local Assemblages = Concord.assemblages
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -71,7 +66,7 @@ What is most important is that Components are data and nothing more. They have 0
|
||||||
Entities are the actual objects in your game. Like a player, an enemy, a crate, or a bullet.
|
Entities are the actual objects in your game. Like a player, an enemy, a crate, or a bullet.
|
||||||
Every Entity has it's own set of Components, with their own values.
|
Every Entity has it's own set of Components, with their own values.
|
||||||
|
|
||||||
A crate might have the following components:
|
A crate might have the following components (Note: Not actual Concord syntax):
|
||||||
```lua
|
```lua
|
||||||
{
|
{
|
||||||
position = { x = 100, y = 200 },
|
position = { x = 100, y = 200 },
|
||||||
|
|
@ -100,7 +95,7 @@ For this they will only act on Entities that have the Components needed for this
|
||||||
In Concord this is done something alike this:
|
In Concord this is done something alike this:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
drawSystem = System({position, texture}) -- Define a System that takes all Entities with a position and texture Component
|
drawSystem = System({pool = {position, texture}}) -- Define a System that takes all Entities with a position and texture Component
|
||||||
|
|
||||||
function drawSystem:draw() -- Give it a draw function
|
function drawSystem:draw() -- Give it a draw function
|
||||||
for _, entity in ipairs(self.pool) do -- Iterate over all Entities that this System acts on
|
for _, entity in ipairs(self.pool) do -- Iterate over all Entities that this System acts on
|
||||||
|
|
@ -140,40 +135,26 @@ When you define a Component or System you are actually defining a `ComponentClas
|
||||||
For example. If you want to get a specific Component from an Entity, you'd do `Component = Entity:get(ComponentClass)`.
|
For example. If you want to get a specific Component from an Entity, you'd do `Component = Entity:get(ComponentClass)`.
|
||||||
When ComponentClasses or SystemClasses are required it will be written clearly in the Documentation.
|
When ComponentClasses or SystemClasses are required it will be written clearly in the Documentation.
|
||||||
|
|
||||||
#### Containers
|
#### Requiring files
|
||||||
Since you'll be defining or creating lots of Components, Systems, Worlds and Assemblages, Concord adds container tables for each of them so that they are easily accessible.
|
|
||||||
|
Since you'll have lots of Components and Systems in your game Concord makes it a bit easier to load things in.
|
||||||
|
|
||||||
These containers can be accessed through
|
|
||||||
```lua
|
```lua
|
||||||
local Components = require("path.to.concord").components
|
-- Loads all files in the directory, and puts the return value in the table Systems. The key is their filename without any extension
|
||||||
local Systems = require("path.to.concord").systems
|
local Systems = {}
|
||||||
local Worlds = require("path.to.concord").worlds
|
Concord.loadNamespace("path.to.systems", Systems)
|
||||||
local Assemblages = require("path.to.concord").aorlds
|
|
||||||
|
print(Systems.systemName)
|
||||||
|
|
||||||
|
-- Loads all files in the directory. Components automatically register to Concord, so loading them into a namespace isn't necessary.
|
||||||
|
Concord.loadNamespace("path.to.components")
|
||||||
|
|
||||||
|
print(Systems.componentName)
|
||||||
```
|
```
|
||||||
|
|
||||||
Concord has helper functions to fill these containers. There are the following options depending on your needs / preference:
|
|
||||||
```lua
|
|
||||||
-- Loads each file. They are put in the container according to it's filename ( 'src.components.component_1.lua' becomes 'component_1' )
|
|
||||||
Concord.loadComponents({"path.to.component_1", "path.to.component_2", "etc"})
|
|
||||||
|
|
||||||
-- Loads all files in the directory. They are put in the container according to it's filename ( 'src.components.component_1.lua' becomes 'component_1' )
|
|
||||||
Concord.loadComponents("path.to.directory.containing.components")
|
|
||||||
|
|
||||||
|
|
||||||
-- Put the ComponentClass into the container directly. Useful if you want more manual control. Note that you need to require the file in this case
|
|
||||||
Components.register("componentName", ComponentClass)
|
|
||||||
```
|
|
||||||
Things can then be accessed through their names:
|
|
||||||
```lua
|
|
||||||
local component_1_class = Components.component_1
|
|
||||||
local componentName_class = Components.componentName
|
|
||||||
```
|
|
||||||
|
|
||||||
All the above applies the same to all the other containers.
|
|
||||||
|
|
||||||
#### Method chaining
|
#### Method chaining
|
||||||
```lua
|
```lua
|
||||||
-- All functions that do something ( eg. Don't return anything ) will return self
|
-- Most (if not all) methods will return self
|
||||||
-- This allowes you to chain methods
|
-- This allowes you to chain methods
|
||||||
|
|
||||||
entity
|
entity
|
||||||
|
|
@ -182,8 +163,6 @@ entity
|
||||||
:remove(position)
|
:remove(position)
|
||||||
:destroy()
|
:destroy()
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
world
|
world
|
||||||
:addEntity(fooEntity)
|
:addEntity(fooEntity)
|
||||||
:addEntity(barEntity)
|
:addEntity(barEntity)
|
||||||
|
|
@ -192,13 +171,13 @@ world
|
||||||
```
|
```
|
||||||
|
|
||||||
### Components
|
### Components
|
||||||
When defining a ComponentClass you usually pass in a `populate` function. This will fill the Component with values.
|
When defining a ComponentClass you need to pass in a name and usually a `populate` function. This will fill the Component with values.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Create the ComponentClass with a populate function
|
-- Create the position class with a populate function
|
||||||
-- The component variable is the actual Component given to an Entity
|
-- The component variable is the actual Component given to an Entity
|
||||||
-- The x and y variables are values we pass in when we create the Component
|
-- The x and y variables are values we pass in when we create the Component
|
||||||
local positionComponentClass = Concord.component(function(component, x, y)
|
Concord.component("position" function(component, x, y)
|
||||||
component.x = x or 0
|
component.x = x or 0
|
||||||
component.y = y or 0
|
component.y = y or 0
|
||||||
end)
|
end)
|
||||||
|
|
@ -206,19 +185,11 @@ end)
|
||||||
-- Create a ComponentClass without a populate function
|
-- Create a ComponentClass without a populate function
|
||||||
-- Components of this type won't have any fields.
|
-- Components of this type won't have any fields.
|
||||||
-- This can be useful to indiciate state.
|
-- This can be useful to indiciate state.
|
||||||
local pushableComponentClass = Concord.component()
|
local pushableComponentClass = Concord.component("position")
|
||||||
```
|
|
||||||
|
|
||||||
```lua
|
|
||||||
-- Manually register the ComponentClass to the container if we want
|
|
||||||
Concord.components.register("positionComponent", positionComponentClass)
|
|
||||||
|
|
||||||
-- Otherwise return the ComponentClass so it can be required
|
|
||||||
return positionComponentClass
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Entities
|
### Entities
|
||||||
Entities can be freely made and be given Components. You pass the ComponentClass and the values you want to pass. It will then create the Component for you.
|
Entities can be freely made and be given Components. You pass the name of the ComponentClass and the values you want to pass. It will then create the Component for you.
|
||||||
|
|
||||||
Entities can only have a maximum of one of each Component.
|
Entities can only have a maximum of one of each Component.
|
||||||
Entities can not share Components.
|
Entities can not share Components.
|
||||||
|
|
@ -233,43 +204,41 @@ local myEntity = Entity(myWorld) -- To add it to a world immediately ( See World
|
||||||
```lua
|
```lua
|
||||||
-- Give the entity the position Component defined above
|
-- Give the entity the position Component defined above
|
||||||
-- x will become 100. y will become 50
|
-- x will become 100. y will become 50
|
||||||
myEntity:give(positionComponentClass, 100, 50)
|
myEntity:give("position", 100, 50)
|
||||||
```
|
```
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Retrieve a Component
|
-- Retrieve a Component
|
||||||
local positionComponent = myEntity[positionComponentClass]
|
local position = myEntity.position
|
||||||
-- or
|
|
||||||
local positionComponent = myEntity:get(positionComponentClass)
|
|
||||||
|
|
||||||
print(positionComponent.x, positionComponent.y) -- 100, 50
|
print(position.x, position.y) -- 100, 50
|
||||||
```
|
```
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Remove a Component
|
-- Remove a Component
|
||||||
myEntity:remove(positionComponentClass)
|
myEntity:remove("position")
|
||||||
```
|
```
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Check if the Entity has a Component
|
-- Check if the Entity has a Component
|
||||||
local hasPositionComponent = myEntity:has(positionComponentClass)
|
local hasPosition = myEntity.position and true of false
|
||||||
print(hasPositionComponent) -- false
|
print(hasPosition) -- false
|
||||||
```
|
```
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Entity:give will override a Component if the Entity already has it
|
-- Entity:give will override a Component if the Entity already has it
|
||||||
-- Entity:ensure will only put the Component if the Entity does not already have it
|
-- Entity:ensure will only put the Component if the Entity does not already have it
|
||||||
|
|
||||||
Entity:ensure(positionComponentClass, 0, 0) -- Will give
|
Entity:ensure("position", 0, 0) -- Will give
|
||||||
-- Position is {x = 0, y = 0}
|
-- Position is {x = 0, y = 0}
|
||||||
|
|
||||||
Entity:give(positionComponentClass, 50, 50) -- Will override
|
Entity:give("position", 50, 50) -- Will override
|
||||||
-- Position is {x = 50, y = 50}
|
-- Position is {x = 50, y = 50}
|
||||||
|
|
||||||
Entity:give(positionComponentClass, 100, 100) -- Will override
|
Entity:give("position", 100, 100) -- Will override
|
||||||
-- Position is {x = 100, y = 100}
|
-- Position is {x = 100, y = 100}
|
||||||
|
|
||||||
Entity:ensure(positionComponentClass, 0, 0) -- Wont do anything
|
Entity:ensure("position", 0, 0) -- Wont do anything
|
||||||
-- Position is {x = 100, y = 100}
|
-- Position is {x = 100, y = 100}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -285,7 +254,7 @@ end
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Assemble the Entity ( See Assemblages )
|
-- Assemble the Entity ( See Assemblages )
|
||||||
myEntity:assemble(myAssemblage, 100, true, "foo")
|
myEntity:assemble(assemblageFunction, 100, true, "foo")
|
||||||
```
|
```
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
|
|
@ -310,30 +279,21 @@ Systems can have multiple pools.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Create a System
|
-- Create a System
|
||||||
local mySystemClass = Concord.system({positionComponentClass}) -- Pool will contain all Entities with a position Component
|
local mySystemClass = Concord.system(pool = {"position"}) -- Pool named 'pool' will contain all Entities with a position Component
|
||||||
|
|
||||||
-- Create a System with multiple pools
|
-- Create a System with multiple pools
|
||||||
local mySystemClass = Concord.system(
|
local mySystemClass = Concord.system(
|
||||||
{ -- This Pool's name will default to 'pool'
|
pool = { -- This pool will be named 'pool'
|
||||||
positionCompomponentClass,
|
"position",
|
||||||
velocityComponentClass,
|
"velocity",
|
||||||
},
|
},
|
||||||
{ -- This Pool's name will be 'secondPool'
|
secondPool = { -- This pool's name will be 'secondPool'
|
||||||
healthComponentClass,
|
"health",
|
||||||
damageableComponentClass,
|
"damageable",
|
||||||
"secondPool",
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
```lua
|
|
||||||
-- Manually register the SystemClass to the container if we want
|
|
||||||
Concord.system.register("mySystem", mySystemClass)
|
|
||||||
|
|
||||||
-- Otherwise return the SystemClass so it can be required
|
|
||||||
return mySystemClass
|
|
||||||
```
|
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- If a System has a :init function it will be called on creation
|
-- If a System has a :init function it will be called on creation
|
||||||
|
|
||||||
|
|
@ -348,16 +308,11 @@ end
|
||||||
function mySystemClass:update(dt)
|
function mySystemClass:update(dt)
|
||||||
-- Iterate over all entities in the Pool
|
-- Iterate over all entities in the Pool
|
||||||
for _, e in ipairs(self.pool)
|
for _, e in ipairs(self.pool)
|
||||||
-- Get the Entity's Components
|
|
||||||
local positionComponent = e[positionComponentClass]
|
|
||||||
local velocityComponent = e[velocityComponentClass]
|
|
||||||
|
|
||||||
-- Do something with the Components
|
-- Do something with the Components
|
||||||
positionComponent.x = positionComponent.x + velocityComponent.x * dt
|
e.position.x = e.position.x + e.velocity.x * dt
|
||||||
positionComponent.y = positionComponent.y + velocityComponent.y * dt
|
e.position.y = e.position.y + e.velocity.y * dt
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Iterate over all entities in the second Pool
|
-- Iterate over all entities in the second Pool
|
||||||
for _, e in ipairs(self.secondPool)
|
for _, e in ipairs(self.secondPool)
|
||||||
-- Do something
|
-- Do something
|
||||||
|
|
@ -367,24 +322,20 @@ end
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Systems can be enabled and disabled
|
-- Systems can be enabled and disabled
|
||||||
|
-- When systems are disabled their callbacks won't be executed.
|
||||||
|
-- Note that pools will still be updated
|
||||||
|
-- This is mainly useful for systems that display debug information
|
||||||
-- Systems are enabled by default
|
-- Systems are enabled by default
|
||||||
|
|
||||||
-- Enable a System
|
-- Enable a System
|
||||||
mySystem:enable()
|
|
||||||
-- or
|
|
||||||
mySystem:setEnable(true)
|
mySystem:setEnable(true)
|
||||||
|
|
||||||
-- Disable a System
|
-- Disable a System
|
||||||
mySystem:disable()
|
|
||||||
-- or
|
|
||||||
mySystem:setEnable(false)
|
mySystem:setEnable(false)
|
||||||
|
|
||||||
-- Toggle the enable state
|
|
||||||
mySystem:toggleEnabled()
|
|
||||||
|
|
||||||
-- Get enabled state
|
-- Get enabled state
|
||||||
local isEnabled = mySystem:isEnabled()
|
local isEnabled = mySystem:isEnabled()
|
||||||
print(isEnabled) -- true
|
print(isEnabled) -- false
|
||||||
```
|
```
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
|
|
@ -405,14 +356,6 @@ Worlds can have any number of Entities.
|
||||||
local myWorld = Concord.world()
|
local myWorld = Concord.world()
|
||||||
```
|
```
|
||||||
|
|
||||||
```lua
|
|
||||||
-- Manually register the World to the container if we want
|
|
||||||
Concord.worlds.register("myWorld", myWorld)
|
|
||||||
|
|
||||||
-- Otherwise return the World so it can be required
|
|
||||||
return myWorld
|
|
||||||
```
|
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Add an Entity to the World
|
-- Add an Entity to the World
|
||||||
myWorld:addEntity(myEntity)
|
myWorld:addEntity(myEntity)
|
||||||
|
|
@ -471,33 +414,31 @@ end
|
||||||
|
|
||||||
### Assemblages
|
### Assemblages
|
||||||
|
|
||||||
Assemblages are helpers to 'make' Entities something.
|
Assemblages are functions to 'make' Entities something.
|
||||||
An important distinction is that they _append_ Components.
|
An important distinction is that they _append_ Components.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Make an Assemblage
|
-- Make an Assemblage function
|
||||||
-- e is the Entity being assembled.
|
-- e is the Entity being assembled.
|
||||||
-- cuteness and legs are variables passed in
|
-- cuteness and legs are variables passed in
|
||||||
local animalAssemblage(function(e, cuteness, legs)
|
function animal(e, cuteness, legs)
|
||||||
e
|
e
|
||||||
:give(cutenessComponentClass, cuteness)
|
:give(cutenessComponentClass, cuteness)
|
||||||
:give(limbs, legs, 0) -- Variable amount of legs. 0 arm.
|
:give(limbs, legs, 0) -- Variable amount of legs. 0 arm.
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- Make an Assemblage that used animalAssemblage
|
-- Make an Assemblage that uses animal
|
||||||
-- cuteness is a variables passed in
|
-- cuteness is a variables passed in
|
||||||
local catAssemblage(function(e, cuteness)
|
function cat(e, cuteness)
|
||||||
e
|
e
|
||||||
:assemble(animalAssemblage, cuteness * 2, 4) -- Cats are twice as cute, and have 4 legs.
|
:assemble(animal, cuteness * 2, 4) -- Cats are twice as cute, and have 4 legs.
|
||||||
:give(soundComponent, "meow.mp3")
|
:give(soundComponent, "meow.mp3")
|
||||||
end)
|
end)
|
||||||
```
|
```
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
-- Use an Assemblage
|
-- Use an Assemblage
|
||||||
myEntity:assemble(catAssemblage, 100) -- 100 cuteness
|
myEntity:assemble(cat, 100) -- 100 cuteness
|
||||||
-- or
|
|
||||||
catAssemblage:assemble(myEntity, 100) -- 100 cuteness
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -506,14 +447,13 @@ catAssemblage:assemble(myEntity, 100) -- 100 cuteness
|
||||||
```lua
|
```lua
|
||||||
local Concord = require("concord")
|
local Concord = require("concord")
|
||||||
|
|
||||||
-- Defining ComponentClasses
|
-- Defining components
|
||||||
-- I use UpperCamelCase to indicate its a class
|
Concord.component("position", function(c, x, y)
|
||||||
local Position = Concord.component(function(c, x, y)
|
|
||||||
c.x = x or 0
|
c.x = x or 0
|
||||||
c.y = y or 0
|
c.y = y or 0
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local Velocity = Concord.component(function(c, x, y)
|
Concord.component("velocity", function(c, x, y)
|
||||||
c.x = x or 0
|
c.x = x or 0
|
||||||
c.y = y or 0
|
c.y = y or 0
|
||||||
end)
|
end)
|
||||||
|
|
@ -522,27 +462,21 @@ local Drawable = Concord.component()
|
||||||
|
|
||||||
|
|
||||||
-- Defining Systems
|
-- Defining Systems
|
||||||
local MoveSystem = Concord.system({Position, Velocity})
|
local MoveSystem = Concord.system(pool = {"position", "velocity"})
|
||||||
|
|
||||||
function MoveSystem:update(dt)
|
function MoveSystem:update(dt)
|
||||||
for _, e in ipairs(self.pool) do
|
for _, e in ipairs(self.pool) do
|
||||||
-- I use lowerCamelCase to indicate its an instance
|
e.position.x = e.position.x + e.velocity.x * dt
|
||||||
local position = e[Position]
|
e.position.y = e.position.y + e.velocity.y * dt
|
||||||
local velocity = e[Velocity]
|
|
||||||
|
|
||||||
position.x = position.x + velocity.x * dt
|
|
||||||
position.y = position.y + velocity.y * dt
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
local DrawSystem = Concord.system({Position, Drawable})
|
local DrawSystem = Concord.system(pool = {"position", "drawable"})
|
||||||
|
|
||||||
function DrawSystem:draw()
|
function DrawSystem:draw()
|
||||||
for _, e in ipairs(self.pool) do
|
for _, e in ipairs(self.pool) do
|
||||||
local position = e[Position]
|
love.graphics.circle("fill", e.position.x, e.position.y, 5)
|
||||||
|
|
||||||
love.graphics.circle("fill", position.x, position.y, 5)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -555,18 +489,18 @@ world:addSystems(MoveSystem, DrawSystem)
|
||||||
|
|
||||||
-- This Entity will be rendered on the screen, and move to the right at 100 pixels a second
|
-- This Entity will be rendered on the screen, and move to the right at 100 pixels a second
|
||||||
local entity_1 = Concord.entity(world)
|
local entity_1 = Concord.entity(world)
|
||||||
:give(Position, 100, 100)
|
:give("position", 100, 100)
|
||||||
:give(Velocity, 100, 0)
|
:give("velocity", 100, 0)
|
||||||
:give(Drawable)
|
:give("drawable")
|
||||||
|
|
||||||
-- This Entity will be rendered on the screen, and stay at 50, 50
|
-- This Entity will be rendered on the screen, and stay at 50, 50
|
||||||
local entity_2 = Concord.entity(world)
|
local entity_2 = Concord.entity(world)
|
||||||
:give(Position, 50, 50)
|
:give("position", 50, 50)
|
||||||
:give(Drawable)
|
:give("drawable")
|
||||||
|
|
||||||
-- This Entity does exist in the World, but since it doesn't match any System's filters it won't do anything
|
-- This Entity does exist in the World, but since it doesn't match any System's filters it won't do anything
|
||||||
local entity_3 = Concord.entity(world)
|
local entity_3 = Concord.entity(world)
|
||||||
:give(Position, 200, 200)
|
:give("position", 200, 200)
|
||||||
|
|
||||||
|
|
||||||
-- Emit the events
|
-- Emit the events
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue