{"id":3062,"date":"2013-12-29T18:02:06","date_gmt":"2013-12-29T17:02:06","guid":{"rendered":"http:\/\/t-machine.org\/?p=3062"},"modified":"2014-01-28T14:03:08","modified_gmt":"2014-01-28T13:03:08","slug":"artemis-entity-system-in-objectivec","status":"publish","type":"post","link":"http:\/\/new.t-machine.org\/index.php\/2013\/12\/29\/artemis-entity-system-in-objectivec\/","title":{"rendered":"Artemis Entity System in ObjectiveC"},"content":{"rendered":"<p>I wanted to try the latest version of Artemis, and I had an old game project that was quickly written in OOP style. So I went looking for an ObjC port&#8230;<\/p>\n<h2>Existing port: outdated<\/h2>\n<p>There was a port linked on the Artemis site that was OK &#8211; but had no documentation or updates, and Artemis has moved on since then.<\/p>\n<p>There were also no unit tests etc &#8211; and the current Artemis getting-started wouldn&#8217;t work with this port (because so much has changed). So I started a new port&#8230;<\/p>\n<h2>New port: ObjC Artemis 100%<\/h2>\n<p>Primary aim:<\/p>\n<ul>\n<li>make it identical to the core Artemis.\n<\/ul>\n<p><!--more--><br \/>\nSecondary aims:<\/p>\n<ul>\n<li>include getting-started, unit-tests, etc, so that even if Artemis changes &#8230; this version will still be usable\n<li>use as many Obj-C features as possible to simplify writing code &#8211; but ALWAYS keep it so that code written in Java-Artemis ports directly to ObjC with zero code changes\n<li>&#8230;except: some of Java-Artemis is literally impossible to port because it uses Java features that don&#8217;t exist in ObjC\n<\/ul>\n<p>Github project: <a href=\"https:\/\/github.com\/adamgit\/ArtemisObjC\">https:\/\/github.com\/adamgit\/ArtemisObjC<\/a><\/p>\n<h2>Features I had to write \/ re-write<\/h2>\n<p>Since launching the iPhone &#8230; Apple has been trying to bring ObjC up to modern standards. They&#8217;re making good progress (e.g. blocks!) &#8211; but they have a long way to go.<\/p>\n<h3>Naming<\/h3>\n<p>ObjC&#8217;s big problem for library writing is its lack of namespace support.<\/p>\n<p>I had to rename every class to have the word &#8220;Artemis&#8221; on the front. Otherwise, names like &#8220;Component&#8221; clash with existing libraries :(.<\/p>\n<h3>Generics<\/h3>\n<p>ObjC has no Templates and no Generics, which makes life hard. Lots of boilerplate code required, lots of errors, etc.<\/p>\n<h3>Missing classes<\/h3>\n<p>Almost every class ported directly (ObjC&#8217;s standard libraries are very similar to Java&#8217;s).<\/p>\n<p>But there were two classes that needed special effort to implement in ObjC:<\/p>\n<ul>\n<li>Bag \/ ArtemisBag &#8212; for ObjC, this needs to be implemented in raw C for performance; I haven&#8217;t done that!\n<li>BitSet \/ ArtemisBitSet &#8212; ObjC has no direct class for Java&#8217;s BitSet, but it has a very similar C library around CFBitSet (methods behave slightly differnetly though!)\n<\/ul>\n<h2>Progress&#8230;<\/h2>\n<h3>Emulating Generics in ObjC<\/h3>\n<p>I&#8217;m hoping someone else will try this: <a href=\"https:\/\/github.com\/tomersh\/Objective-C-Generics\/\">tomersh&#8217;s clever one-file hack that simulates Generics in ObjC<\/a>. It creates @protocol&#8217;s that extend NSSet\/NSArray\/etc to behave like Generics (but only for simple operations) &#8212; and because @protocol uses the same &lt;\/&gt; syntax as Generics, it even reads the same!<\/p>\n<h3>Reducing boilerplate code typing, even without Generics<\/h3>\n<p>Artemis has ComponentMapper&#8217;s. In Java, using Generics, these automatically output the correct type for each object. In ObjC, you have to type some horrors like:<\/p>\n<p>[objc]<br \/>\n\tComponentOrder* order = (ComponentOrder*) [self.mapOrders get:entity];<br \/>\n\tif( ((ComponentOwnedResource*)[self.mapOwnedResource get:[entity.world getEntity:order.sourceCountryEID]]).ownerEID != order.playerEID )<br \/>\n\t{<\/p>\n<p>\t}<br \/>\n[\/objc]<\/p>\n<p>&#8230;because of ObjC&#8217;s lack of Generics, there&#8217;s so much crud there it&#8217;s almost impossible to read WTF the programmer was doing. In OOP it would have been:<\/p>\n<p>[objc]<br \/>\n\tif( order.sourceCountry.ownerEID != order.playerEID )<br \/>\n\t{<\/p>\n<p>\t}<br \/>\n[\/objc]<\/p>\n<p><span style=\"color: red\">This is a disaster! The ES code is literally 3 times as much typing as the OOP code, AND IT HAS NO TYPESAFETY! The worst of all worlds<\/span><\/p>\n<p>So, I added subscripting (a relatively recent ObjC feature) to ArtemisComponentMapper. The new code is:<\/p>\n<p>[objc]<br \/>\n\tComponentOrder* order = (ComponentOrder*) self.mapOrders[entity];<br \/>\n\tif( ((ComponentOwnedResource*)self.mapOwnedResource[ order.sourceCountryEID]).ownerEID != order.playerEID )<br \/>\n\t{<\/p>\n<p>\t}<br \/>\n[\/objc]<\/p>\n<p><strong>Note:<\/strong> &#8220;self.mapOwnedResource&#8221; is an ArtemisComponentMapper. In traditional Artemis, you have to pass it an Entity instance (ObjC: ArtemisEntity*). But in cases where you had only the &#8220;id&#8221; (ObjC: Id), you need to first fetch the Entity.<\/p>\n<p>&#8230;with subscripting, you can have TWO subscripts: one that uses int&#8217;s, one that uses NSObject*&#8217;s. Conveniently, that means you can use EITHER the raw id (which is an int! Very lucky!), or the Entity instance &#8230; and the library now intelligently does the right thing.<\/p>\n<h2>More to come&#8230;<\/h2>\n<p>If you contribute to the project and add fixes\/improvements, let me know and I&#8217;ll add info here&#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wanted to try the latest version of Artemis, and I had an old game project that was quickly written in OOP style. So I went looking for an ObjC port&#8230; Existing port: outdated There was a port linked on the Artemis site that was OK &#8211; but had no documentation or updates, and Artemis [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[60,20],"tags":[],"_links":{"self":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/3062"}],"collection":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/comments?post=3062"}],"version-history":[{"count":8,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/3062\/revisions"}],"predecessor-version":[{"id":3109,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/posts\/3062\/revisions\/3109"}],"wp:attachment":[{"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/media?parent=3062"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/categories?post=3062"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/new.t-machine.org\/index.php\/wp-json\/wp\/v2\/tags?post=3062"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}