# HG changeset patch # User Steve Losh # Date 1478611637 0 # Node ID a7af1952d336f29ea53a256cdb5ed39e6af9fd35 # Parent d337c4b0c1652ae816d0fba82e2de76d7f9241de Update docs diff -r d337c4b0c165 -r a7af1952d336 Makefile --- a/Makefile Thu Sep 08 14:12:48 2016 +0000 +++ b/Makefile Tue Nov 08 13:27:17 2016 +0000 @@ -2,7 +2,7 @@ sourcefiles = $(shell ffind --full-path --literal .lisp) docfiles = $(shell ls docs/*.markdown) -apidoc = docs/04-reference.markdown +apidoc = docs/03-reference.markdown # Vendor ---------------------------------------------------------------------- vendor/quickutils.lisp: vendor/make-quickutils.lisp diff -r d337c4b0c165 -r a7af1952d336 README.markdown --- a/README.markdown Thu Sep 08 14:12:48 2016 +0000 +++ b/README.markdown Tue Nov 08 13:27:17 2016 +0000 @@ -13,6 +13,10 @@ Lisp. It's a thin layer of sugar over CLOS that makes it easy to write flexible objects for video games. +Beast can be installed with [Quicklisp][]: + + (ql:quickload :beast) + Check out the [Overview](http://sjl.bitbucket.org/beast/overview/) for a three-minute description of what this is, or the [Usage](http://sjl.bitbucket.org/beast/usage/) for a full rundown. @@ -24,3 +28,5 @@ The test suite currently passes in SBCL, CCL, ECL, and ABCL on OS X and Debian. Further testing is welcome. + +[quicklisp]: https://quicklisp.org/ diff -r d337c4b0c165 -r a7af1952d336 docs/01-installation.markdown --- a/docs/01-installation.markdown Thu Sep 08 14:12:48 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -Installation -============ - -Beast is compatible with Quicklisp, but not *in* Quicklisp (yet?). You can -clone the repository into your [Quicklisp local-projects][local] directory for -now. - -[local]: https://www.quicklisp.org/beta/faq.html#local-project diff -r d337c4b0c165 -r a7af1952d336 docs/01-overview.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/01-overview.markdown Tue Nov 08 13:27:17 2016 +0000 @@ -0,0 +1,67 @@ +Overview +======== + +When you're making a video game you need a way to model things in the game +world. In the past couple of decades Entity/Component systems have become +popular: + +* +* +* + +There are a couple of ECS libraries for Common Lisp already: + +* [cl-ecs](https://github.com/lispgames/cl-ecs) +* [ecstasy](https://github.com/mfiano/ecstasy) + +Both of these favor composition over inheritance -- game objects (entities) +*contain* various components, but they don't *inherit* from components. + +Beast takes the opposite approach, favoring (restricted) inheritance over +composition. + +Components in Beast are called "aspects" to try to overload the word "component" +a little bit less in this crazy world. Aspects are essentially +[mixins](https://en.wikipedia.org/wiki/Mixin), with some sugar for defining them +and running systems over them: + + :::lisp + (define-aspect throwable accuracy damage) + (define-aspect edible nutrition-value) + + (define-entity dart (throwable)) + (define-entity cheese (edible)) + (define-entity pie (throwable edible)) + + (define-system rot-food ((e edible)) + (decf (edible/nutrition-value e)) + (when (zerop (edible/nutrition-value e)) + (destroy-entity e))) + + (defparameter *steel-dart* + (create-entity 'dart + :throwable/accuracy 0.9 + :throwable/damage 10)) + + (defparameter *hunk-of-swiss* + (create-entity 'cheese + :edible/nutrition-value 50)) + + (defparameter *banana-cream-pie* + (create-entity 'pie + :throwable/accuracy 0.3 + :throwable/damage 5 + :edible/nutrition-value 30)) + +Beast tries to be just a very thin layer over CLOS, because CLOS is quite +powerful. You can use `typep`, generic methods, before/after/around methods, +and everything else CLOS gives you. + +Like every engineering decision this comes with tradeoffs. You can't (easily) +add or remove aspects to/from a particular entity at runtime like you can with +cl-ecs. And there's no way to give an entity multiple "copies" of a single +aspect. + +The author has found this approach to work well for his needs. You should take +a look at both approaches and decide which is best for you. If you want to read +more, check out the [Usage](../usage/) document. diff -r d337c4b0c165 -r a7af1952d336 docs/02-overview.markdown --- a/docs/02-overview.markdown Thu Sep 08 14:12:48 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -Overview -======== - -When you're making a video game you need a way to model things in the game -world. In the past couple of decades Entity/Component systems have become -popular: - -* -* -* - -There are a couple of ECS libraries for Common Lisp already: - -* [cl-ecs](https://github.com/lispgames/cl-ecs) -* [ecstasy](https://github.com/mfiano/ecstasy) - -Both of these favor composition over inheritance -- game objects (entities) -*contain* various components, but they don't *inherit* from components. - -Beast takes the opposite approach, favoring (restricted) inheritance over -composition. - -Components in Beast are called "aspects" to try to overload the word "component" -a little bit less in this crazy world. Aspects are essentially -[mixins](https://en.wikipedia.org/wiki/Mixin), with some sugar for defining them -and running systems over them: - - :::lisp - (define-aspect throwable accuracy damage) - (define-aspect edible nutrition-value) - - (define-entity dart (throwable)) - (define-entity cheese (edible)) - (define-entity pie (throwable edible)) - - (define-system rot-food ((e edible)) - (decf (edible/nutrition-value e)) - (when (zerop (edible/nutrition-value e)) - (destroy-entity e))) - - (defparameter *steel-dart* - (create-entity 'dart - :throwable/accuracy 0.9 - :throwable/damage 10)) - - (defparameter *hunk-of-swiss* - (create-entity 'cheese - :edible/nutrition-value 50)) - - (defparameter *banana-cream-pie* - (create-entity 'pie - :throwable/accuracy 0.3 - :throwable/damage 5 - :edible/nutrition-value 30)) - -Beast tries to be just a very thin layer over CLOS, because CLOS is quite -powerful. You can use `typep`, generic methods, before/after/around methods, -and everything else CLOS gives you. - -Like every engineering decision this comes with tradeoffs. You can't (easily) -add or remove aspects to/from a particular entity at runtime like you can with -cl-ecs. And there's no way to give an entity multiple "copies" of a single -aspect. - -The author has found this approach to work well for his needs. You should take -a look at both approaches and decide which is best for you. If you want to read -more, check out the [Usage](../usage/) document. diff -r d337c4b0c165 -r a7af1952d336 docs/02-usage.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/02-usage.markdown Tue Nov 08 13:27:17 2016 +0000 @@ -0,0 +1,216 @@ +Usage +===== + +Beast aims to be a thin layer over CLOS, and so has a fairly small user-facing +API. + +[TOC] + +Aspects +------- + +Aspects are facets/traits of your game objects that you want to model. Some +examples could be things like: location, moveable, visible, edible, sentient. + +### Defining Aspects + +To define an aspect you use `define-aspect`: + + :::lisp + (define-aspect location x y) + (define-aspect edible nutrition-value) + +`define-aspect` takes the name of the aspect and zero or more slot definitions. + +The names of aspect slots will be have the aspect name prepended to them with +a slash to avoid clashing between aspects, and the `initargs` and `accessors` +will be added for you. So for example, this: + + :::lisp + (define-aspect inspectable text) + (define-aspect readable text) + +Would macroexpand into something roughly like: + + :::lisp + (defclass inspectable () + ((inspectable/text :initarg :inspectable/text + :accessor inspectable/text))) + + (defclass readable () + ((readable/text :initarg :readable/text + :accessor readable/text))) + +### Aspect Slot Options + +You can include extra slot options when defining an aspect's slots, and they'll +be passed along to the `defclass`. This is especially handy for `:initform` +and `:type`. + + :::lisp + (define-aspect container + (contents :initform nil)) + + (define-aspect throwable + (accuracy :type single-float) + (damage :type integer)) + +In the end it's just CLOS though, so if you want to add some `:documentation` or +use `:allocation :class` then go nuts! + +### Aspect Type Predicates + +When you define an aspect named `foo` Beast also defines a `foo?` predicate that +returns `(typep object 'foo)`, which comes in handy when using higher-order +functions: + + :::lisp + (defun whats-for-dinner? () + (remove-if-not #'edible? (container/contents *fridge*))) + +Entities +-------- + +Once you've got some aspects you'll want to define some entity classes that mix +them together. + +### Defining Entities + +You define entity classes using `define-entity`: + + :::lisp + (define-entity dart (throwable)) + (define-entity bread (edible)) + (define-entity pie (edible throwable)) + (define-entity icebox (container)) + +The resulting classes will inherit from `entity` and each of the aspects (in +order). This example would expand (roughly) into: + + :::lisp + (defclass dart (entity throwable) ()) + (defun dart? (object) (typep object 'dart)) + + (defclass bread (entity edible) ()) + (defun bread? (object) (typep object 'bread)) + + (defclass pie (entity edible throwable) ()) + (defun pie? (object) (typep object 'pie)) + + (defclass icebox (entity container) ()) + (defun icebox? (object) (typep object 'icebox)) + +### Entity Slot Definitions + +You can also specify slot definitions at the entity level, and they'll be passed +along to `defclass`: + + :::lisp + (define-entity cheese (edible) + (variety :type (member :swiss :cheddar :feta) + :initarg :variety + :reader :cheese-variety)) + +Note that slot definitions on entities are passed along **raw**, without the +name-mangling or default-slot-option-adding that's done for aspects. This may +change in the future. + +### Creating and Destroying Entities + +After you've defined your entity classes you can can create some entities using +`create-entity`: + + :::lisp + (defparameter *my-fridge* (create-entity 'icebox)) + + (dotimes (i 30) + (push (create-entity 'cheese + :edible/nutrition-value 10 + :variety (nth (random 3) '(:swiss :cheddar :feta))) + (container/contents *my-fridge*))) + +`create-entity` is a thin wrapper around `make-instance` that handles some extra +bookkeeping. When you create an entity, Beast will keep track of it in a global +index. We'll see the reason for this in the next section. + +To destroy an entity (i.e. remove it from Beast's index) you can use +`(destroy-entity the-entity)`. You can wipe the slate clean and remove all +entities at once with `(clear-entities)`. + +### Callbacks + +Beast also defines two generic functions called `entity-created` and +`entity-destroyed` which don't do anything by default, but are there for you to +add methods on if you want. For example: + + :::lisp + (define-aspect location x y) + + (defvar *world* (make-array (100 100) :initial-element nil)) + + (defmethod entity-created :after ((e location)) + (push e (aref *world* (location/x e) (location/y e)))) + + (defmethod entity-destroyed :after ((e location)) + (with-slots ((x location/x) (y location/y)) e + (setf (aref *world* x y) (delete e (aref *world* x y))))) + + +Systems +------- + +Beast's aspects and entities are just *very* thin sugar over CLOS, but systems +provide extra functionality that comes in handy when writing games. + +A system is essentially a function that takes an entity as an argument with +zero or more aspects as type specifiers. When you run a system the function +will be run on every entity that meet the requirements. For example: + + :::lisp + ; No specifiers, this just runs on every entity. + (define-system log-all-entities (entity) + (print entity)) + + ; Runs on entities with the lifetime aspect. + (define-system age ((entity lifetime)) + (when (> (incf (lifetime/age entity)) + (lifetime/lifespan entity)) + (destroy-entity entity))) + + ; Run on entities with both the visible and location aspects. + (define-system render ((entity visible location)) + (draw entity (location/x entity) + (location/y entity) + (visible/color entity))) + +Systems with more than one argument are currently supported, but should be +considered experimental. The API may change in the future. + + :::lisp + ; Run on all PAIRS of entities that have the appropriate aspects. + (define-system detect-collisions ((e1 location collidable) + (e2 location collidable)) + ; ... + ) + +`define-system` defines a function with the same name as the system, and +a `run-...` function that will do the actual running for you: + + :::lisp + (define-system log-all-entities (entity) + (print entity)) + + (run-log-all-entities) + +You should always use the `run-...` function, but the other one can be handy to +have around for tracing/debugging/disassembling purposes. + +Next Steps +---------- + +That's most of Beast in a nutshell. If you've gotten this far you can dive in +and make something, or take a look at the [API Reference](../reference/). + +Beast also does some stuff not discussed here like caching entities by +aspect/system and type-hinting system functions. If you're curious about how it +works you can [read the source](http://bitbucket.org/sjl/beast/src/). diff -r d337c4b0c165 -r a7af1952d336 docs/03-reference.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/03-reference.markdown Tue Nov 08 13:27:17 2016 +0000 @@ -0,0 +1,175 @@ +# API Reference + +The following is a list of all user-facing parts of Beast. + +If there are backwards-incompatible changes to anything listed here, they will +be noted in the changelog and the author will feel bad. + +Anything not listed here is subject to change at any time with no warning, so +don't touch it. + +[TOC] + +## Package `BEAST` + +### `CLEAR-ENTITIES` (function) + + (CLEAR-ENTITIES) + +Destroy all entities. + + `destroy-entity` will be called for each entity. + + Returns a list of all the destroyed entites. + + + +### `CREATE-ENTITY` (function) + + (CREATE-ENTITY CLASS &REST INITARGS) + +Create an entity of the given entity class and return it. + + `initargs` will be passed along to `make-instance`. + + The `entity-created` generic function will be called just before returning the + entity. + + + +### `DEFINE-ASPECT` (macro) + + (DEFINE-ASPECT NAME &REST FIELDS) + +Define an aspect class. + + `name` should be a symbol that will become the name of the class. + + `fields` should be zero or more field definitions. Each field definition can + be a symbol (the field name), or a list of the field name and extra CLOS slot + options. + + Field names will have the aspect name and a slash prepended to them to create + the slot names. `:initarg` and `:accessor` slot options will also be + automatically generated. + + Example: + + (define-aspect edible + energy + (taste :initform nil)) + => + (defclass edible () + ((edible/energy :initarg :edible/energy + :accessor edible/energy) + (edible/taste :initarg :edible/taste + :accessor edible/taste + :initform nil))) + + + +### `DEFINE-ENTITY` (macro) + + (DEFINE-ENTITY NAME ASPECTS &REST SLOTS) + +Define an entity class. + + `name` should be a symbol that will become the name of the class. + + `aspects` should be a list of the aspects this entity should inherit from. + + `slots` can be zero or more extra CLOS slot definitions. + + Examples: + + (define-entity potion (drinkable)) + + (define-entity cheese (edible visible) + (flavor :accessor cheese-flavor :initarg :flavor)) + + + +### `DEFINE-SYSTEM` (macro) + + (DEFINE-SYSTEM NAME-AND-OPTIONS + ARGLIST + &BODY + BODY) + +Define a system. + + `name-and-options` should be a list of the system name (a symbol) and any + system options. A bare symbol can be used if no options are needed. + + `arglist` should be a list of system arguments. Each argument should be + a list of the argument name and zero or more aspect/entity classes. + + Defining a system `foo` defines two functions: + + * `foo` runs `body` on a single entity and should only be used for debugging, + tracing, or disassembling. + * `run-foo` should be called to run the system on all applicable entities. + + Available system options: + + * `:inline`: when true, try to inline the system function into the + system-running function to avoid the overhead of a function call for every + entity. Defaults to `nil`. + + Examples: + + (define-system age ((entity lifetime)) + (when (> (incf (lifetime/age entity)) + (lifetime/lifespan entity)) + (destroy-entity entity))) + + + +### `DESTROY-ENTITY` (function) + + (DESTROY-ENTITY ENTITY) + +Destroy `entity` and return it. + + The `entity-destroyed` generic function will be called after the entity has + been destroyed and unindexed. + + + +### `ENTITY` (class) + +A single entity in the game world. + +### `ENTITY-CREATED` (generic function) + + (ENTITY-CREATED ENTITY) + +Called after an entity has been created and indexed. + + The default method does nothing, but users can implement their own auxillary + methods to run code when entities are created. + + + +### `ENTITY-DESTROYED` (generic function) + + (ENTITY-DESTROYED ENTITY) + +Called after an entity has been destroyed and unindexed. + + The default method does nothing, but users can implement their own auxillary + methods to run code when entities are destroyed. + + + +### `MAP-ENTITIES` (function) + + (MAP-ENTITIES FUNCTION &OPTIONAL (TYPE 'ENTITY)) + +Map `function` over all entities that are subtypes of `type`. + + Normally you should run code on entities using systems, but this function can + be handy for debugging purposes. + + + diff -r d337c4b0c165 -r a7af1952d336 docs/03-usage.markdown --- a/docs/03-usage.markdown Thu Sep 08 14:12:48 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,216 +0,0 @@ -Usage -===== - -Beast aims to be a thin layer over CLOS, and so has a fairly small user-facing -API. - -[TOC] - -Aspects -------- - -Aspects are facets/traits of your game objects that you want to model. Some -examples could be things like: location, moveable, visible, edible, sentient. - -### Defining Aspects - -To define an aspect you use `define-aspect`: - - :::lisp - (define-aspect location x y) - (define-aspect edible nutrition-value) - -`define-aspect` takes the name of the aspect and zero or more slot definitions. - -The names of aspect slots will be have the aspect name prepended to them with -a slash to avoid clashing between aspects, and the `initargs` and `accessors` -will be added for you. So for example, this: - - :::lisp - (define-aspect inspectable text) - (define-aspect readable text) - -Would macroexpand into something roughly like: - - :::lisp - (defclass inspectable () - ((inspectable/text :initarg :inspectable/text - :accessor inspectable/text))) - - (defclass readable () - ((readable/text :initarg :readable/text - :accessor readable/text))) - -### Aspect Slot Options - -You can include extra slot options when defining an aspect's slots, and they'll -be passed along to the `defclass`. This is especially handy for `:initform` -and `:type`. - - :::lisp - (define-aspect container - (contents :initform nil)) - - (define-aspect throwable - (accuracy :type single-float) - (damage :type integer)) - -In the end it's just CLOS though, so if you want to add some `:documentation` or -use `:allocation :class` then go nuts! - -### Aspect Type Predicates - -When you define an aspect named `foo` Beast also defines a `foo?` predicate that -returns `(typep object 'foo)`, which comes in handy when using higher-order -functions: - - :::lisp - (defun whats-for-dinner? () - (remove-if-not #'edible? (container/contents *fridge*))) - -Entities --------- - -Once you've got some aspects you'll want to define some entity classes that mix -them together. - -### Defining Entities - -You define entity classes using `define-entity`: - - :::lisp - (define-entity dart (throwable)) - (define-entity bread (edible)) - (define-entity pie (edible throwable)) - (define-entity icebox (container)) - -The resulting classes will inherit from `entity` and each of the aspects (in -order). This example would expand (roughly) into: - - :::lisp - (defclass dart (entity throwable) ()) - (defun dart? (object) (typep object 'dart)) - - (defclass bread (entity edible) ()) - (defun bread? (object) (typep object 'bread)) - - (defclass pie (entity edible throwable) ()) - (defun pie? (object) (typep object 'pie)) - - (defclass icebox (entity container) ()) - (defun icebox? (object) (typep object 'icebox)) - -### Entity Slot Definitions - -You can also specify slot definitions at the entity level, and they'll be passed -along to `defclass`: - - :::lisp - (define-entity cheese (edible) - (variety :type (member :swiss :cheddar :feta) - :initarg :variety - :reader :cheese-variety)) - -Note that slot definitions on entities are passed along **raw**, without the -name-mangling or default-slot-option-adding that's done for aspects. This may -change in the future. - -### Creating and Destroying Entities - -After you've defined your entity classes you can can create some entities using -`create-entity`: - - :::lisp - (defparameter *my-fridge* (create-entity 'icebox)) - - (dotimes (i 30) - (push (create-entity 'cheese - :edible/nutrition-value 10 - :variety (nth (random 3) '(:swiss :cheddar :feta))) - (container/contents *my-fridge*))) - -`create-entity` is a thin wrapper around `make-instance` that handles some extra -bookkeeping. When you create an entity, Beast will keep track of it in a global -index. We'll see the reason for this in the next section. - -To destroy an entity (i.e. remove it from Beast's index) you can use -`(destroy-entity the-entity)`. You can wipe the slate clean and remove all -entities at once with `(clear-entities)`. - -### Callbacks - -Beast also defines two generic functions called `entity-created` and -`entity-destroyed` which don't do anything by default, but are there for you to -add methods on if you want. For example: - - :::lisp - (define-aspect location x y) - - (defvar *world* (make-array (100 100) :initial-element nil)) - - (defmethod entity-created :after ((e location)) - (push e (aref *world* (location/x e) (location/y e)))) - - (defmethod entity-destroyed :after ((e location)) - (with-slots ((x location/x) (y location/y)) e - (setf (aref *world* x y) (delete e (aref *world* x y))))) - - -Systems -------- - -Beast's aspects and entities are just *very* thin sugar over CLOS, but systems -provide extra functionality that comes in handy when writing games. - -A system is essentially a function that takes an entity as an argument with -zero or more aspects as type specifiers. When you run a system the function -will be run on every entity that meet the requirements. For example: - - :::lisp - ; No specifiers, this just runs on every entity. - (define-system log-all-entities (entity) - (print entity)) - - ; Runs on entities with the lifetime aspect. - (define-system age ((entity lifetime)) - (when (> (incf (lifetime/age entity)) - (lifetime/lifespan entity)) - (destroy-entity entity))) - - ; Run on entities with both the visible and location aspects. - (define-system render ((entity visible location)) - (draw entity (location/x entity) - (location/y entity) - (visible/color entity))) - -Systems with more than one argument are currently supported, but should be -considered experimental. The API may change in the future. - - :::lisp - ; Run on all PAIRS of entities that have the appropriate aspects. - (define-system detect-collisions ((e1 location collidable) - (e2 location collidable)) - ; ... - ) - -`define-system` defines a function with the same name as the system, and -a `run-...` function that will do the actual running for you: - - :::lisp - (define-system log-all-entities (entity) - (print entity)) - - (run-log-all-entities) - -You should always use the `run-...` function, but the other one can be handy to -have around for tracing/debugging/disassembling purposes. - -Next Steps ----------- - -That's most of Beast in a nutshell. If you've gotten this far you can dive in -and make something, or take a look at the [API Reference](../reference/). - -Beast also does some stuff not discussed here like caching entities by -aspect/system and type-hinting system functions. If you're curious about how it -works you can [read the source](http://bitbucket.org/sjl/beast/src/). diff -r d337c4b0c165 -r a7af1952d336 docs/04-changelog.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/04-changelog.markdown Tue Nov 08 13:27:17 2016 +0000 @@ -0,0 +1,11 @@ +Changelog +========= + +Here's the list of changes in each released version. + +[TOC] + +v1.0.0 +------ + +Initial version. It works, but changes may happen in the future. diff -r d337c4b0c165 -r a7af1952d336 docs/04-reference.markdown --- a/docs/04-reference.markdown Thu Sep 08 14:12:48 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,190 +0,0 @@ -# API Reference - -The following is a list of all user-facing parts of Beast. - -If there are backwards-incompatible changes to anything listed here, they will -be noted in the changelog and the author will feel bad. - -Anything not listed here is subject to change at any time with no warning, so -don't touch it. - -[TOC] - -## Package `BEAST` - -### `CLEAR-ENTITIES` (function) - - (CLEAR-ENTITIES) - -Destroy all entities. - - `destroy-entity` will be called for each entity. - - Returns a list of all the destroyed entites. - - - -### `CREATE-ENTITY` (function) - - (CREATE-ENTITY CLASS &REST INITARGS) - -Create an entity of the given entity class and return it. - - `initargs` will be passed along to `make-instance`. - - The `entity-created` generic function will be called just before returning the - entity. - - - -### `DEFINE-ASPECT` (macro) - - (DEFINE-ASPECT NAME &REST FIELDS) - -Define an aspect class. - - `name` should be a symbol that will become the name of the class. - - `fields` should be zero or more field definitions. Each field definition can - be a symbol (the field name), or a list of the field name and extra CLOS slot - options. - - Field names will have the aspect name and a slash prepended to them to create - the slot names. `:initarg` and `:accessor` slot options will also be - automatically generated. - - Example: - - (define-aspect edible - energy - (taste :initform nil)) - => - (defclass edible () - ((edible/energy :initarg :edible/energy - :accessor edible/energy) - (edible/taste :initarg :edible/taste - :accessor edible/taste - :initform nil))) - - - -### `DEFINE-ENTITY` (macro) - - (DEFINE-ENTITY NAME ASPECTS &REST SLOTS) - -Define an entity class. - - `name` should be a symbol that will become the name of the class. - - `aspects` should be a list of the aspects this entity should inherit from. - - `slots` can be zero or more extra CLOS slot definitions. - - Examples: - - (define-entity potion (drinkable)) - - (define-entity cheese (edible visible) - (flavor :accessor cheese-flavor :initarg :flavor)) - - - -### `DEFINE-SYSTEM` (macro) - - (DEFINE-SYSTEM NAME-AND-OPTIONS - ARGLIST - &BODY - BODY) - -Define a system. - - `name-and-options` should be a list of the system name (a symbol) and any - system options. A bare symbol can be used if no options are needed. - - `arglist` should be a list of system arguments. Each argument should be - a list of the argument name and zero or more aspect/entity classes. - - Defining a system `foo` defines two functions: - - * `foo` runs `body` on a single entity and should only be used for debugging, - tracing, or disassembling. - * `run-foo` should be called to run the system on all applicable entities. - - Available system options: - - * `:inline`: when true, try to inline the system function into the - system-running function to avoid the overhead of a function call for every - entity. Defaults to `nil`. - - Examples: - - (define-system age ((entity lifetime)) - (when (> (incf (lifetime/age entity)) - (lifetime/lifespan entity)) - (destroy-entity entity))) - - - -### `DESTROY-ENTITY` (function) - - (DESTROY-ENTITY ENTITY) - -Destroy `entity` and return it. - - The `entity-destroyed` generic function will be called after the entity has - been destroyed and unindexed. - - - -### `ENTITY` (class) - -A single entity in the game world. - -#### Slot `ID` - -* Allocation: `:INSTANCE` -* Initform: `(INCF BEAST::*ENTITY-ID-COUNTER*)` -* Reader: `ENTITY-ID` - -The unique ID of the entity. This may go away in the future. - -#### Slot `%BEAST/ASPECTS` - -* Allocation: `:CLASS` -* Initform: `NIL` - -A list of the aspects this entity class inherits. **Don't touch this.** - -### `ENTITY-CREATED` (generic function) - - (ENTITY-CREATED ENTITY) - -Called after an entity has been created and indexed. - - The default method does nothing, but users can implement their own auxillary - methods to run code when entities are created. - - - -### `ENTITY-DESTROYED` (generic function) - - (ENTITY-DESTROYED ENTITY) - -Called after an entity has been destroyed and unindexed. - - The default method does nothing, but users can implement their own auxillary - methods to run code when entities are destroyed. - - - -### `MAP-ENTITIES` (function) - - (MAP-ENTITIES FUNCTION &OPTIONAL (TYPE 'ENTITY)) - -Map `function` over all entities that are subtypes of `type`. - - Normally you should run code on entities using systems, but this function can - be handy for debugging purposes. - - - diff -r d337c4b0c165 -r a7af1952d336 docs/05-changelog.markdown --- a/docs/05-changelog.markdown Thu Sep 08 14:12:48 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -Changelog -========= - -Here's the list of changes in each released version. - -[TOC] - -v1.0.0 ------- - -Initial version. It works, but changes may happen in the future. diff -r d337c4b0c165 -r a7af1952d336 docs/api.lisp --- a/docs/api.lisp Thu Sep 08 14:12:48 2016 +0000 +++ b/docs/api.lisp Tue Nov 08 13:27:17 2016 +0000 @@ -4,7 +4,7 @@ (list "BEAST")) (defparameter *output-path* - #p"docs/04-reference.markdown" ) + #p"docs/03-reference.markdown" ) (defparameter *header* "The following is a list of all user-facing parts of Beast. diff -r d337c4b0c165 -r a7af1952d336 docs/index.markdown --- a/docs/index.markdown Thu Sep 08 14:12:48 2016 +0000 +++ b/docs/index.markdown Tue Nov 08 13:27:17 2016 +0000 @@ -2,6 +2,10 @@ Lisp. It's a thin layer of sugar over CLOS that makes it easy to write flexible objects for video games. +Beast can be installed with [Quicklisp][]: + + (ql:quickload :beast) + Check out the [Overview](./overview/) for a three-minute description of what this is, or the [Usage](./usage/) for a full rundown. @@ -12,3 +16,5 @@ The test suite currently passes in SBCL, CCL, ECL, and ABCL on OS X and Debian. Further testing is welcome. + +[quicklisp]: https://quicklisp.org/