{"id":419,"date":"2010-02-03T18:00:08","date_gmt":"2010-02-03T08:00:08","guid":{"rendered":"http:\/\/www.doolwind.com\/blog\/?p=419"},"modified":"2017-03-10T00:19:49","modified_gmt":"2017-03-10T00:19:49","slug":"fluent-game-design-with-fluent-interfaces","status":"publish","type":"post","link":"https:\/\/www.doolwind.com\/blog\/fluent-game-design-with-fluent-interfaces\/","title":{"rendered":"Fluent Game Design With Fluent Interfaces"},"content":{"rendered":"<p><a href=\"http:\/\/www.doolwind.com\/images\/blog\/fluentinterfaces.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignright\" title=\"Fluent Interfaces\" src=\"http:\/\/www.doolwind.com\/images\/blog\/fluentinterfacessm.jpg\" alt=\"\" width=\"200\" height=\"125\" \/><\/a>Game designers often find themselves writing code in modern games.\u00a0 Often, they have little to no programming experience and therefore must be taught the basics of programming (sequence, conditionals and loops).\u00a0 I propose utilizing a technique that simplifies the code written by game designers in their games.\u00a0 This technique is known as \u201c<a href=\"http:\/\/en.wikipedia.org\/wiki\/Fluent_interface\">Fluent Interfaces<\/a>\u201d.<\/p>\n<p><strong>What is Fluent?<\/strong><\/p>\n<p>Fluent interfaces allow game designers to <span class=\"pullquote pqRight\">write more fluid and readable code<\/span>.\u00a0 Through the use of method chaining, English like sentences can be written to express game functionality.\u00a0 Fluent interfaces can be implemented in any object oriented programming language.\u00a0 Below is an example of a line in the game design document, a standard implementation example and a fluent example:<\/p>\n<p><span style=\"text-decoration: underline;\">Game Design Document:<\/span><\/p>\n<p>&#8220;Do 5 damage to all enemy tanks within range 2 of an entity&#8221;<\/p>\n<p><span style=\"text-decoration: underline;\">Standard Example:<\/span><\/p>\n<pre class=\"csharpcode\">foreach( var unit in player.UnitsWithinRange(2) )\r\n{\r\n  if(!unit.IsType(Enemy) || !unit.IsType(Tank))\r\n  continue;\r\n\r\n  unit.Damage(5);\r\n}\r\n<\/pre>\n<p><span style=\"text-decoration: underline;\">Fluent Example:<\/span><\/p>\n<pre class=\"csharpcode \">player.UnitsWithinRange(2)\r\n  .Where(UnitIs.Enemy)\r\n  .Where(UnitIs.Tank)\r\n  .DoDamage(5);\r\n<\/pre>\n<p>This fluent example closely matches the design document and is easier to read.\u00a0 It also uses less language constructs like loops and conditions.\u00a0 With Intellisense, designers are given a context sensitive list of operations they can perform.\u00a0 Designers simply build up the expression that describes the original line in the game design document they are implementing.<\/p>\n<p><strong>How to implement Fluent Interfaces <\/strong><\/p>\n<p>Fluent interfaces are actually quite easy to implement.\u00a0 Objects expose methods that return a reference to the object itself allowing method chaining.\u00a0 The best way to describe this is by showing the implementation required for the examples above.<\/p>\n<p>First, we create the object we will be working on (I\u2019ve called it UnitsList in my examples).\u00a0 This gives us the first part of the fluent call (Get.UnitsWithinRange(2)).<\/p>\n<pre class=\"csharpcode\">public class ScriptObject\r\n{\r\n    UnitsList UnitsWithinRange(int range)\r\n    {\r\n        return new UnitsList(range);\r\n    }\r\n}\r\n\r\n<\/pre>\n<p>The UnitsList object must have a set of methods that return references to the object itself allowing method chanining:<\/p>\n<pre class=\"csharpcode\">public class UnitsList\r\n{\r\n    public UnitsList Where(UnitIs condition)\r\n    {\r\n        this.conditions.Add(condition);\r\n        return this;\r\n    }\r\n}\r\n\r\n\r\n\r\npublic class UnitsList\r\n{\r\n    public void DoDamage(int damage)\r\n    {\r\n        foreach( var unit in this.mainUnit.UnitsWithinRange(range) )\r\n        {\r\n            if(!PassesConditions(unit))\r\n                continue;\r\n\r\n            unit.Damage(damage);\r\n        }\r\n    }\r\n\r\n    private bool PassesConditions(Unit unit)\r\n    {\r\n        foreach( var condition in conditions)\r\n        {\r\n            if(!unit.IsType(condition))\r\n                return false;\r\n        }\r\n        return true;\r\n    }\r\n}\r\n<\/pre>\n<p>There are a couple of key things to notice:<\/p>\n<ol>\n<li>This last code example looks a lot like the original standard example<\/li>\n<li>A lot more \u201cengine\u201d code is required to setup a fluent interface than a standard interface<\/li>\n<\/ol>\n<p>So, in effect, an extra layer of abstraction is being placed over the original code.\u00a0 Rather than designers working on loops and conditions, they are calling (well named) methods.\u00a0 This makes their life a lot easier and simplifies maintenance of their gameplay code.\u00a0 It pushes the burden of maintenance down from the gameplay to the engine level and therefore on programmers, who are better suited to maintaining code.\u00a0 If there is a change in the engine or game, this extra level of abstraction serves to buffer the designers and reduce the amount of code that needs to be written.<\/p>\n<p><strong>Good Interface Design<\/strong><\/p>\n<p>Care needs to be taken when designing the interfaces and exposing methods to the designers. \u00a0Rather than exposing all functions off a single object my recommendation is to define different objects for different situations. \u00a0The example provided starts with the player and retrieves a list of units around it. \u00a0Filters are then added before the final operation is performed on the resulting list. \u00a0By limiting the methods\u00a0available\u00a0to the designer to simple filters there is little risk of them making a mistake. \u00a0Also, the fact that the &#8220;DoDamage&#8221; function returns void stops them from\u00a0chaining\u00a0anything further.<\/p>\n<p><strong>Other Syntaxes<\/strong><\/p>\n<p>One small point is that designers can structure their fluent \u201csentences\u201d in any way they please:<\/p>\n<pre class=\"csharpcode\">player.UnitsWithinRange(2).Where(UnitIs.Enemy).Where(UnitIs.Tank).DoDamage(5);\r\n\r\nplayer.UnitsWithinRange(2)\r\n  .Where(UnitIs.Enemy)\r\n  .Where(UnitIs.Tank)\r\n  .DoDamage(5);\r\n<\/pre>\n<p>There is no difference between the above two examples.\u00a0 It\u2019s simply a matter of coding style preferred by the writer.<\/p>\n<p><strong>Conclusion<\/strong><\/p>\n<p>What do you think of Fluent Interfaces? \u00a0Have you used a similar technique before? \u00a0Do you think the extra engine code and maintenance is too much hassle for the gain in clarity to designers?<\/p>\n<p>As an experiment, try exposing a small set of functionality through a fluent interface and see whether your designers like working with it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Game designers often find themselves writing code in modern games.\u00a0 Often, they have little to no programming experience and therefore must be taught the basics of programming (sequence, conditionals and loops).\u00a0 I propose utilizing a technique that simplifies the code written by game designers in their games.\u00a0 This technique is known as \u201cFluent Interfaces\u201d. What <a class=\"more-link\" href=\"https:\/\/www.doolwind.com\/blog\/fluent-game-design-with-fluent-interfaces\/\">Read More<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"enabled":false},"version":2}},"categories":[33],"tags":[19,29,31,112,63,64],"class_list":["post-419","post","type-post","status-publish","format-standard","hentry","category-game-development","tag-c","tag-game-coding","tag-game-designer","tag-game-development","tag-scripting","tag-scripting-language"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pgEc5-6L","_links":{"self":[{"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/posts\/419","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/comments?post=419"}],"version-history":[{"count":0,"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/posts\/419\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/media?parent=419"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/categories?post=419"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.doolwind.com\/blog\/wp-json\/wp\/v2\/tags?post=419"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}