docs/01-overview.markdown @ bda2db860e5c
Add LICENSE
| author | Steve Losh <steve@stevelosh.com> |
|---|---|
| date | Tue, 14 Mar 2017 13:29:19 +0000 |
| parents | 42aaba702d24 |
| children | (none) |
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: * <http://gameprogrammingpatterns.com/component.html> * <http://en.wikipedia.org/wiki/Entity_component_system> * <http://www.gamedev.net/page/resources/_/technical/game-programming/understanding-component-entity-systems-r3013> There were a couple of ECS libraries for Common Lisp already: * cl-ecs * ecstasy Which were both superseded by [net.axity.common-lisp.gamedev.ecs](https://github.com/mfiano/net.axity.common-lisp.gamedev/tree/master/ecs). All 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.