beast/overview/index.html @ 19233527280d
beast: Update site.
| author | Steve Losh <steve@stevelosh.com> |
|---|---|
| date | Fri, 27 Jan 2017 17:41:22 +0000 |
| parents | f3fc28996523 |
| children | 4fd427fcd0a2 |
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>Overview / beast</title> <link rel="stylesheet" href="../_dmedia/pygments-clean.css"/> <link rel="stylesheet/less" type="text/css" href="../_dmedia/style.less"/> <script src="../_dmedia/less.js" type="text/javascript"> </script> </head> <body class="content"> <div class="wrap"> <header><h1><a href="..">beast</a></h1></header> <div class="markdown"> <h1 id="overview"><a href="">Overview</a></h1><p>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:</p> <ul> <li><a href="http://gameprogrammingpatterns.com/component.html">http://gameprogrammingpatterns.com/component.html</a></li> <li><a href="http://en.wikipedia.org/wiki/Entity_component_system">http://en.wikipedia.org/wiki/Entity_component_system</a></li> <li><a href="http://www.gamedev.net/page/resources/_/technical/game-programming/understanding-component-entity-systems-r3013">http://www.gamedev.net/page/resources/_/technical/game-programming/understanding-component-entity-systems-r3013</a></li> </ul> <p>There were a couple of ECS libraries for Common Lisp already:</p> <ul> <li>cl-ecs</li> <li>ecstasy</li> </ul> <p>Which were both superseded by <a href="https://github.com/mfiano/net.axity.common-lisp.gamedev/tree/master/ecs">net.axity.common-lisp.gamedev.ecs</a>.</p> <p>All of these favor composition over inheritance -- game objects (entities) <em>contain</em> various components, but they don't <em>inherit</em> from components.</p> <p>Beast takes the opposite approach, favoring (restricted) inheritance over composition.</p> <p>Components in Beast are called "aspects" to try to overload the word "component" a little bit less in this crazy world. Aspects are essentially <a href="https://en.wikipedia.org/wiki/Mixin">mixins</a>, with some sugar for defining them and running systems over them:</p> <div class="codehilite"><pre><span/><span class="p">(</span><span class="nv">define-aspect</span> <span class="nv">throwable</span> <span class="nv">accuracy</span> <span class="nv">damage</span><span class="p">)</span> <span class="p">(</span><span class="nv">define-aspect</span> <span class="nv">edible</span> <span class="nv">nutrition-value</span><span class="p">)</span> <span class="p">(</span><span class="nv">define-entity</span> <span class="nv">dart</span> <span class="p">(</span><span class="nv">throwable</span><span class="p">))</span> <span class="p">(</span><span class="nv">define-entity</span> <span class="nv">cheese</span> <span class="p">(</span><span class="nv">edible</span><span class="p">))</span> <span class="p">(</span><span class="nv">define-entity</span> <span class="nv">pie</span> <span class="p">(</span><span class="nv">throwable</span> <span class="nv">edible</span><span class="p">))</span> <span class="p">(</span><span class="nv">define-system</span> <span class="nv">rot-food</span> <span class="p">((</span><span class="nv">e</span> <span class="nv">edible</span><span class="p">))</span> <span class="p">(</span><span class="nb">decf</span> <span class="p">(</span><span class="nv">edible/nutrition-value</span> <span class="nv">e</span><span class="p">))</span> <span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nb">zerop</span> <span class="p">(</span><span class="nv">edible/nutrition-value</span> <span class="nv">e</span><span class="p">))</span> <span class="p">(</span><span class="nv">destroy-entity</span> <span class="nv">e</span><span class="p">)))</span> <span class="p">(</span><span class="nb">defparameter</span> <span class="vg">*steel-dart*</span> <span class="p">(</span><span class="nv">create-entity</span> <span class="ss">'dart</span> <span class="ss">:throwable/accuracy</span> <span class="mf">0.9</span> <span class="ss">:throwable/damage</span> <span class="mi">10</span><span class="p">))</span> <span class="p">(</span><span class="nb">defparameter</span> <span class="vg">*hunk-of-swiss*</span> <span class="p">(</span><span class="nv">create-entity</span> <span class="ss">'cheese</span> <span class="ss">:edible/nutrition-value</span> <span class="mi">50</span><span class="p">))</span> <span class="p">(</span><span class="nb">defparameter</span> <span class="vg">*banana-cream-pie*</span> <span class="p">(</span><span class="nv">create-entity</span> <span class="ss">'pie</span> <span class="ss">:throwable/accuracy</span> <span class="mf">0.3</span> <span class="ss">:throwable/damage</span> <span class="mi">5</span> <span class="ss">:edible/nutrition-value</span> <span class="mi">30</span><span class="p">))</span> </pre></div> <p>Beast tries to be just a very thin layer over CLOS, because CLOS is quite powerful. You can use <code>typep</code>, generic methods, before/after/around methods, and everything else CLOS gives you.</p> <p>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.</p> <p>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 <a href="../usage/">Usage</a> document.</p> </div> <footer><p><i>Made with Lisp and love by <a href="http://stevelosh.com/">Steve Losh</a> in Reykjavík, Iceland.</i></p> <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-15328874-3', 'auto'); ga('send', 'pageview'); </script></footer> </div> </body> </html>