Finish first version of documentation

This commit is contained in:
Tjakka5 2020-01-04 11:46:10 +01:00
parent cf51bccb81
commit 3b52f28fe0

245
README.md
View file

@ -9,6 +9,25 @@ This readme will explain how to use Concord.
Additionally all of Concord is documented using the LDoc format. Additionally all of Concord is documented using the LDoc format.
Auto generated docs for Concord can be found in `docs` folder, or on the [Github page](https://tjakka5.github.io/Concord/). Auto generated docs for Concord can be found in `docs` folder, or on the [Github page](https://tjakka5.github.io/Concord/).
---
## Table of Contents
[Installation](#installation)
[ECS](#ecs)
[API](#api) :
- [Components](#components)
- [Entities](#entities)
- [Systems](#systems)
- [Worlds](#worlds)
- [Assemblages](#assemblages)
[Quick Example](#quick-example)
[Contributors](#contributors)
[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 'src' folder in your project. Rename it to something that makes sense (Probably 'concord'), then require it in your project like so:
```lua ```lua
@ -32,6 +51,8 @@ local Worlds = Concord.worlds
local Assemblages = Concord.assemblages local Assemblages = Concord.assemblages
``` ```
---
## ECS ## ECS
Concord is an Entity Component System (ECS for short) library. Concord is an Entity Component System (ECS for short) library.
This is a coding paradigm where _composition_ is used over _inheritance_. This is a coding paradigm where _composition_ is used over _inheritance_.
@ -104,13 +125,16 @@ Or what if the enemy shot bullets with a `health` Component? It would create bul
And all that without writing a single extra line of code. Just reusing code that already existed and is guaranteed to be reuseable. And all that without writing a single extra line of code. Just reusing code that already existed and is guaranteed to be reuseable.
## Documentation ---
## API
### General design ### General design
#### Classes
Concord does a few things that might not be immediately clear. This segment should help understanding. Concord does a few things that might not be immediately clear. This segment should help understanding.
#### Classes
When you define a Component or System you are actually defining a `ComponentClass` and `SystemClass` respectively. From these instances of them can be created. They also act as identifiers for Concord. When you define a Component or System you are actually defining a `ComponentClass` and `SystemClass` respectively. From these instances of them can be created. They also act as identifiers for Concord.
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)`.
@ -147,6 +171,26 @@ local componentName_class = Components.componentName
All the above applies the same to all the other containers. All the above applies the same to all the other containers.
#### Method chaining
```lua
-- All functions that do something ( eg. Don't return anything ) will return self
-- This allowes you to chain methods
entity
:give(position, 100, 50)
:give(velocity, 200, 0)
:remove(position)
:destroy()
--
world
:addEntity(fooEntity)
:addEntity(barEntity)
:clear()
:emit("test")
```
### 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 usually pass in a `populate` function. This will fill the Component with values.
@ -166,10 +210,10 @@ local pushableComponentClass = Concord.component()
``` ```
```lua ```lua
-- Manually register the Component to the container if we want -- Manually register the ComponentClass to the container if we want
Concord.components.register("positionComponent", positionComponentClass) Concord.components.register("positionComponent", positionComponentClass)
-- Otherwise return the Component so it can be required -- Otherwise return the ComponentClass so it can be required
return positionComponentClass return positionComponentClass
``` ```
@ -283,10 +327,10 @@ local mySystemClass = Concord.system(
``` ```
```lua ```lua
-- Manually register the Component to the container if we want -- Manually register the SystemClass to the container if we want
Concord.system.register("mySystem", mySystemClass) Concord.system.register("mySystem", mySystemClass)
-- Otherwise return the Component so it can be required -- Otherwise return the SystemClass so it can be required
return mySystemClass return mySystemClass
``` ```
@ -350,15 +394,192 @@ local world = System:getWorld()
### Worlds ### Worlds
TODO Worlds are the thing your System and Entities live in.
With Worlds you can `:emit` a callback. All Systems with this callback will then be called.
Worlds can have 1 instance of every SystemClass.
Worlds can have any number of Entities.
```lua
-- Create 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
-- Add an Entity to the World
myWorld:addEntity(myEntity)
-- Remove an Entity from the World
myWorld:removeEntity(myEntity)
```
```lua
-- Add a System to the World
myWorld:addSystem(mySystemClass)
-- Add multiple Systems to the World
myWorld:addSystems(moveSystemClass, renderSystemClass, controlSystemClass)
```
```lua
-- Check if the World has a System
local hasSystem = myWorld:hasSystem(mySystemClass)
-- Get a System from the World
local mySystem = myWorld:getSystem(mySystemClass)
```
```lua
-- Emit an event
-- This will call the 'update' function of any added Systems
-- They will be called in the order they were added
myWorld:emit("update", dt)
-- You can emit any event with any parameters
myWorld:emit("customCallback", 100, true, "Hello World")
```
```lua
-- Remove all Entities from the World
myWorld:clear()
```
```lua
-- Override-able callbacks
-- Called when an Entity is added to the World
-- e is the Entity added
function myWorld:onEntityAdded(e)
-- Do something
end
-- Called when an Entity is removed from the World
-- e is the Entity removed
function myWorld:onEntityRemoved(e)
-- Do something
end
```
### Assemblages ### Assemblages
TODO Assemblages are helpers to 'make' Entities something.
An important distinction is that they _append_ Components.
### Type ```lua
-- Make an Assemblage
-- e is the Entity being assembled.
-- cuteness and legs are variables passed in
local animalAssemblage(function(e, cuteness, legs)
e
:give(cutenessComponentClass, cuteness)
:give(limbs, legs, 0) -- Variable amount of legs. 0 arm.
end)
TODO -- Make an Assemblage that used animalAssemblage
-- cuteness is a variables passed in
local catAssemblage(function(e, cuteness)
e
:assemble(animalAssemblage, cuteness * 2, 4) -- Cats are twice as cute, and have 4 legs.
:give(soundComponent, "meow.mp3")
end)
```
```lua
-- Use an Assemblage
myEntity:assemble(catAssemblage, 100) -- 100 cuteness
-- or
catAssemblage:assemble(myEntity, 100) -- 100 cuteness
```
---
## Quick Example
```lua
local Concord = require("concord")
-- Defining ComponentClasses
-- I use UpperCamelCase to indicate its a class
local Position = Concord.component(function(c, x, y)
c.x = x or 0
c.y = y or 0
end)
local Velocity = Concord.component(function(c, x, y)
c.x = x or 0
c.y = y or 0
end)
local Drawable = Concord.component()
-- Defining Systems
local MoveSystem = Concord.system({Position, Velocity})
function MoveSystem:update(dt)
for _, e in ipairs(self.pool) do
-- I use lowerCamelCase to indicate its an instance
local position = e[Position]
local velocity = e[Velocity]
position.x = position.x + velocity.x * dt
position.y = position.y + velocity.y * dt
end
end
local DrawSystem = Concord.System({Position, Drawable})
function DrawSystem:draw()
for _, e in ipairs(self.pool) do
local position = e[Position]
love.graphics.circle("fill", position.x, position.y, 5)
end
end
-- Create the World
local world = World()
-- Add the Systems
world:addSystems(MoveSystem, DrawSystem)
-- This Entity will be rendered on the screen, and move to the right at 100 pixels a second
local entity_1 = Concord.entity(world)
:give(Position, 100, 100)
:give(Velocity, 100, 0)
:give(Drawable)
-- This Entity will be rendered on the screen, and stay at 50, 50
local entity_2 = Concord.entity(world)
:give(Position, 50, 50)
:give(Drawable)
-- This Entity does exist in the World, but since it doesn't match any System's filters it won't do anything
local entity_2 = Concord.entity(world)
:give(Position, 200, 200)
-- Emit the events
function love.update(dt)
world:emit(dt)
end
function love.draw()
world:draw()
end
```
---
## Contributors ## Contributors
- __Positive07__: Constant support and a good rubberduck - __Positive07__: Constant support and a good rubberduck
@ -367,6 +588,8 @@ TODO
- __Erasio__: I took inspiration from HooECS. He also introduced me to ECS - __Erasio__: I took inspiration from HooECS. He also introduced me to ECS
- __Speak__: Lots of testing for new features of Concord - __Speak__: Lots of testing for new features of Concord
- __Tesselode__: Brainstorming and helpful support - __Tesselode__: Brainstorming and helpful support
---
## Licence ## Licence
MIT Licensed - Copyright Justin van der Leij (Tjakka5) MIT Licensed - Copyright Justin van der Leij (Tjakka5)