{"id":3373,"date":"2014-09-29T00:35:10","date_gmt":"2014-09-29T05:35:10","guid":{"rendered":"http:\/\/www.himeworks.com\/?p=3373"},"modified":"2014-09-29T13:55:15","modified_gmt":"2014-09-29T18:55:15","slug":"script-compatibility-talk-object-composition","status":"publish","type":"post","link":"https:\/\/himeworks.com\/2014\/09\/script-compatibility-talk-object-composition\/","title":{"rendered":"Script Compatibility Talk: Object Composition"},"content":{"rendered":"<p>As a scripter, I write scripts with the\u00a0goal of being\u00a0plugged into any project and suddenly a developer has just solved a problem.<\/p>\n<p>In this article I discuss a certain technique that I personally have not seen being used very often in RPG Maker scripts, though it is something I feel is extremely important for\u00a0compatibility between scripts. Or Maybe I just don&#8217;t look at enough scripts.<\/p>\n<h2>Object Composition<\/h2>\n<p>In software engineering. there is a concept\u00a0called <a href=\"http:\/\/en.wikipedia.org\/wiki\/Object_composition\">Object Composition<\/a>. You can read about it\u00a0on Wikipedia but basically you have\u00a0an object that contains another object. Wikipedia uses the analogy of a car being composed of an engine, wheels,\u00a0and all of the other parts that\u00a0you may expect from a fantasy automobile, such as laser turret or warp drives.<\/p>\n<h2><!--more-->Where would I use it?<\/h2>\n<p>In RPG Maker, you can see examples of object composition.\u00a0A battler sprite holds a reference to the battler object that it represents.<\/p>\n<pre>class Sprite_Battler &lt; Sprite_Base\n\u00a0 def initialize(viewport, battler = nil)\n\u00a0   super(viewport)\n  \u00a0 @battler = battler # &lt;---\n  \u00a0 @battler_visible = false\n    # ...<\/pre>\n<p>Similarly, a character sprite holds a reference to the character object that it represents.<\/p>\n<pre>class Sprite_Character &lt; Sprite_Base\n  #--------------------------------------------------------------------------\n  # * Object Initialization\n  # character : Game_Character\n  #--------------------------------------------------------------------------\n  def initialize(viewport, character = nil)\n    super(viewport)\n    @character = character # &lt;---\n    @balloon_duration = 0<\/pre>\n<p>Rather than creating a single object that handles both the logic (moving around, keeping track of HP and skills) as well as the presentation (updating animations, drawing the\u00a0picture), we logically separate the two sets of responsibilities into their own classes, and use object composition to link them together. There is also something called MVC which appears to be useful\u00a0but that&#8217;s a different topic.<\/p>\n<h2>Revisiting Alias<\/h2>\n<p>Aliasing is a common\u00a0technique that is used to increase compatibility between scripts. It is usually quite effective as well, since you are simply adding extra logic on top of existing code. However, there are times when aliasing is not the best solution.<\/p>\n<p>For example, let&#8217;s say you are writing a battle system that provides a number of mechanics such as\u00a0battler positions on the\u00a0battlefield as well as limiting your skills to the equips that you are currently holding. If you don&#8217;t know what those\u00a0mean, that&#8217;s ok. Basically, you\u00a0are going to have to add new logic to classes like <code>Game_Battler<\/code> and <code>Game_Unit<\/code>. Adding new attributes and changing the way skills are determined can be done using aliases, while allowing you to preserve existing logic that may have been added by other scripts.<\/p>\n<h2>Everyone shares everything<\/h2>\n<p>This is a\u00a0consequence\u00a0behind aliasing methods. When you add more logic to a method, everyone else now has to cope with it, even if you didn&#8217;t intend it yourself.<\/p>\n<p>This starts to become a problem when you have two or more scripts\u00a0want to use the same method, but they will conflict with each other because the logic they&#8217;re adding is not what the other scripts want.<\/p>\n<p>Going with the example of battle\u00a0skills, the default system makes it so that you can use basically any skill you want as long as\u00a0the requirements are met. If I added logic to only limit it to skills that are associated with certain equips, this change may be incompatible with the default battle system (or even outside of battle, such as in the menu screen).<\/p>\n<p>There are many ways to come up with a situation where\u00a0two scripts aliasing the same method causes problems, and for sufficiently complex scripts such as battle systems, you will very likely have many conflicting methods. Aliasing in these situations is\u00a0effective, but what could we do?<\/p>\n<h2>Introducing composition<\/h2>\n<p>Imagine\u00a0you have your basic <code>Game_Actor<\/code>\u00a0object, and you want to use it in a custom battle system. You can alias all of the methods that you need like before, or you can consider\u00a0&#8220;wrapping&#8221; or &#8220;decorating&#8221; it with a custom actor object that is specifically made for that battle system.<\/p>\n<p>It might look something like this<\/p>\n<pre>class Custom_Battle_Actor\n\n  attr_reader :x\n  attr_reader :y\n  attr_reader :atb\n  \n  #----------------------------------------------------\n  # Pass in an actor that you want to decorate\n  #----------------------------------------------------\n  def initialize(game_actor)\n    @actor = game_actor\n    @atb = 0\n    @x = 0   \n    @y = 0\n  end\n  \n  #-----------------------------------------------------\n  # Custom skill filters. Calls the actor's skills method\n  # and then filters on that\n  #-----------------------------------------------------\n  def skills\n    @actor.skills.select do |skill|\n      # some filter criteria for your skills\n    end\n  end\n\n  #-----------------------------------------------------\n  # All of the other methods you need...\n  #-----------------------------------------------------\nend\n<\/pre>\n<p>Notice a few things with this design:<\/p>\n<ul>\n<li>It holds a reference to a particular actor. It&#8217;s basically\u00a0that actor, except with new\u00a0properties<\/li>\n<li>It calls on the actor&#8217;s own methods. If there are scripts that add custom logic to the actor&#8217;s methods, they would\u00a0be compatible with your script<\/li>\n<\/ul>\n<p>This custom battle actor class would be used specifically for my custom battle system and nowhere else. It doesn&#8217;t alias existing methods, so I don&#8217;t need to worry about other scripts having a problem with new logic I&#8217;m adding. It is effectively a stand-alone\u00a0battler\u00a0class that does not need to know how the underlying actor is implemented.<\/p>\n<p>Another thing that you should notice is that it does not inherit from any of the battler classes, despite being a battle object. Inheritance may be an appropriate choice depending on what you need, and may make things easier for you because it already comes with all of the other\u00a0interface methods that other classes expect. I would recommend experimenting with different approaches to understand the advantages and disadvantages of each approach.<\/p>\n<h2>Is composition any good?<\/h2>\n<p>I&#8217;ve presented a\u00a0scenario where I&#8217;ve found a lot of compatibility issues. This could easily apply to mini-games as well, where you want to use existing actors or parties, but new logic would only be used specifically for those games.<\/p>\n<p>The answer to whether composition would solve the problem or not would require you to actually implement multiple battle systems in this\u00a0way to show that they are indeed compatible, but the theory\u00a0suggests it would work out. Perhaps\u00a0in the future we will see more \u00a0large, complex, but compatible systems being built for RPG Maker.<\/p>\n<h2>Spread the Word<\/h2>\n<p>If you liked the post and feel that others could benefit from it, consider tweeting it or sharing it on whichever social media channels that you use. You can also follow<a href=\"https:\/\/twitter.com\/HimeWorks\" target=\"_blank\">@HimeWorks<\/a>\u00a0on Twitter or like my <a href=\"https:\/\/www.facebook.com\/himeworkscom\" target=\"_blank\">Facebook page<\/a>\u00a0to get the latest updates or suggest topics that you would like to read about.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As a scripter, I write scripts with the\u00a0goal of being\u00a0plugged into any project and suddenly a developer has just solved a problem. In this article I discuss a certain technique that I personally have&#46;&#46;&#46;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"twitterCardType":"","cardImageID":0,"cardImage":"","cardTitle":"","cardDesc":"","cardImageAlt":"","cardPlayer":"","cardPlayerWidth":0,"cardPlayerHeight":0,"cardPlayerStream":"","cardPlayerCodec":""},"categories":[11],"tags":[108],"_links":{"self":[{"href":"https:\/\/himeworks.com\/wp-json\/wp\/v2\/posts\/3373"}],"collection":[{"href":"https:\/\/himeworks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/himeworks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/himeworks.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/himeworks.com\/wp-json\/wp\/v2\/comments?post=3373"}],"version-history":[{"count":0,"href":"https:\/\/himeworks.com\/wp-json\/wp\/v2\/posts\/3373\/revisions"}],"wp:attachment":[{"href":"https:\/\/himeworks.com\/wp-json\/wp\/v2\/media?parent=3373"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/himeworks.com\/wp-json\/wp\/v2\/categories?post=3373"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/himeworks.com\/wp-json\/wp\/v2\/tags?post=3373"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}