Essence is an entity-component-system (ECS) library for Clojure.
- Entities are maps of components
- Components have constructors and support most of clojure function definition
(
defn) features) - Entity prototypes all defining what components an entity will have. They also support prototypal inheritance]
- Systems can filter to entities they should process
- Systems can have their own state (i.e. mappings between entities and OpenGL VBOs)
- Everything is immutable
Essence is not yet available on Clojars. It will be available after I clean it up a bit and improve the documentation.
Remember, Essence is immutable, so all functions that "modify" a value, actually returns the modified value.
A game is a simple wrapper around entities and systems. I game can be created
using the create function:
(require [essence.game as g])
(let [game (g/create)]
...)
An entity is a map of of components. Components can be added or removed.
Entities can be created directly or from a prototype (see essence.prototype
section).
(create-entity)
(create-entity component-map)
Creates a new entity, suitable for adding to a game.
(add game entity)
Adds an entity to the game.
(attach entity component)
Attaches a component to an entity.
(detach entity component-name)
Detaches a component from an entity.
(data entity component-name)
Fetches data from a component attached to an entity.
(find-entity game entity-id)
Finds an entity in a game by id.
(query game components)
Return a sequence of entities with components named by the components vector.
(update entity component name fn & args)
Updates the data of a cojponent using fn and args. Like Clojure's
update-in.
(spawn protoype-name)
Spawns an entity using a prototype as a template.
(despawn game entity)
Removes an entity from the game.
This namespace is primarily responsible for allowing you to define new components.
(create name data)
Creates a raw component with name and data. This doesn't have much use and
you should probably use defcomponent to define components instead.
(defcomponent name [params] body)
Defines a new component with name. Instantiating this component using
component calls body with the passed parameters.
Simple example:
(defcomponent sprite)
No function body or parameters means this component simply passing the arguments
passed to component straight through.
Multiple arity example:
(defcomponent position
([x y] (position x y 0))
([[x y z] {:x x :y y :z z}))
Here, two the position component supports an arity of two or three. The two
arity version simply calls the three arity version with 0 as its third
parameter.
(component name & args)
Instantiates a component with name passing args to the component
constructor. Here's how you would instantiate components from the two previous
examples:
(component sprite :bad-guy)
(component position 2 3)