{"id":1047,"date":"2014-03-03T08:50:04","date_gmt":"2014-03-03T01:50:04","guid":{"rendered":"http:\/\/blog.bebensiganteng.com\/?p=1047"},"modified":"2016-03-14T08:21:16","modified_gmt":"2016-03-14T08:21:16","slug":"game-development-journal-part-1","status":"publish","type":"post","link":"https:\/\/rahmat-hidayat.com\/?p=1047","title":{"rendered":"Game Development &#8211; part 1"},"content":{"rendered":"<p>Starting on my own game, although brilliant idea is immensely dependent on how the stars are aligned (metaphorical speaking obviously) still I can&#8217;t disclose the exact concept since the indie game scenery is <a title=\"http:\/\/iwantaclone.tumblr.com\/\" href=\"http:\/\/iwantaclone.tumblr.com\/\" target=\"_blank\">notoriously brutal<\/a>, but in a glimpse the basic premise is a maze with a few added twists.<br \/>\n\u3058\u3083\u3042\u3001\u3044\u304d\u307e\u3057\u3087\u3046\u30fc\uff01 <\/p>\n<h5>Choosing the Framework<\/h5>\n<p>There were candidates, which were<\/p>\n<ol>\n<li><a title=\"http:\/\/www.openframeworks.cc\/\" href=\"http:\/\/www.openframeworks.cc\/\" target=\"_blank\">oF<\/a>, because of <a title=\"http:\/\/www.reddit.com\/r\/IAmA\/comments\/1ah6mg\/were_the_creators_of_ridiculous_fishing_ask_us\/c8xd4cf \" href=\"http:\/\/www.reddit.com\/r\/IAmA\/comments\/1ah6mg\/were_the_creators_of_ridiculous_fishing_ask_us\/c8xd4cf \" target=\"_blank\">Ridiculous Fishing<\/a>.<\/li>\n<li><a title=\"http:\/\/www.cocos2d-iphone.org\/\" href=\"http:\/\/www.cocos2d-iphone.org\/\" target=\"_blank\">cocos2D<\/a>, because of <a title=\"Badland\" href=\"http:\/\/www.cocos2d-iphone.org\/badland-a-cocos2d-iphone-game\/\" target=\"_blank\">Badland<\/a><\/li>\n<li>Native, because of <a title=\"iOS7\" href=\"https:\/\/developer.apple.com\/library\/ios\/releasenotes\/General\/WhatsNewIniOS\/Articles\/iOS7.html \" target=\"_blank\">iOS7<\/a><\/li>\n<li>and lastly <a title=\"http:\/\/www.cocos2d-x.org\/\" href=\"http:\/\/www.cocos2d-x.org\/\" target=\"_blank\">cocos2d-x<\/a>, because its porting capabilities<\/li>\n<\/ol>\n<p>At the end I have chosen cocos2d-x because mobile != iOS, although hindsight native was perhaps a better choice since cocos2d-x is inferior in comparison with iOS 7, its laden with flaws such as the documentation, slow update, and mainly performance, on dormant the CPU usage hovers around 16%<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Screenshot\" src=\"http:\/\/i.imgur.com\/gk0KZtg.png\" width=\"244\" height=\"85\" \/><br \/>\nas native, it can go as low as 5%.<\/p>\n<p>Although this is just my opinion, a diehard cocos2d-x user might argue <em>au contraire<\/em>.<\/p>\n<h5>Development<\/h5>\n<p>First phase is building the maze-generator, there a lot of <a title=\"http:\/\/en.wikipedia.org\/wiki\/Maze_solving_algorithm\" href=\"http:\/\/en.wikipedia.org\/wiki\/Maze_solving_algorithm\" target=\"_blank\">maze algorithm<\/a> out there and some uses fancy algorithm such as <a title=\"http:\/\/en.wikipedia.org\/wiki\/Gabriel_graph\" href=\"http:\/\/en.wikipedia.org\/wiki\/Gabriel_graph\" target=\"_blank\">Gabriel Graph<\/a>, <a title=\"http:\/\/en.wikipedia.org\/wiki\/Relative_neighborhood_graph\" href=\"http:\/\/en.wikipedia.org\/wiki\/Relative_neighborhood_graph\" target=\"_blank\">Relative neighborhood graph<\/a>, or <a title=\"https:\/\/en.wikipedia.org\/wiki\/Normal_distribution\" href=\"https:\/\/en.wikipedia.org\/wiki\/Normal_distribution\" target=\"_blank\">Normal distribution<\/a> but I chose<a title=\"http:\/\/en.wikipedia.org\/wiki\/Depth-first_search\" href=\"http:\/\/en.wikipedia.org\/wiki\/Depth-first_search\" target=\"_blank\"> Depth-first search<\/a> since the game has to be simple and fast.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\/**\r\n\r\nBuild an empty maze\r\n\r\n*\/\r\nvoid MazeGenerator::addInit() {\r\n    \r\n    int i;\r\n    \r\n    for (i = 0; i &lt; _total; i++) {\r\n        \r\n        \/\/ _w is width of the tiles\r\n        int flag = EMPTY, nh = i\/_w;\r\n        \r\n        if (i &lt; _w || i &gt; _total-_w-1 || i%_w == 0 || i%(_w*(nh+1)-1) == 0 || (i%2 != 0 &amp;&amp; nh%2 != 0)) {\r\n            flag = WALL;\r\n        }\r\n        \r\n        if (_start &lt; 0 &amp;&amp; flag == EMPTY) {\r\n            _start = i;\r\n            \r\n            \/\/ TODO randomize start position\r\n            flag = START;\r\n        }\r\n        \r\n        if (flag != EMPTY) _empty--;\r\n        \r\n        _stage-&gt;addObject(CCInteger::create(flag));\r\n        \r\n    }\r\n}\r\n\r\n\/**\r\n\r\nAdd the Depth-first search\r\n\r\n*\/\r\nvoid MazeGenerator::addDepthSearch() {\r\n    \r\n    CCArray* stack = CCArray::create();\r\n    CCInteger* p;\r\n    CCInteger* q;\r\n    \r\n    int s = _start;\r\n    \r\n    while (_path &lt; _empty) {\r\n        \r\n        \/\/ Check for any surrounding empty tiles\r\n        CCArray* r = checkSurrounding(_stage, s, EMPTY);\r\n        \r\n        \/\/ If exists\r\n        if (r-&gt;count() &gt; 0) {\r\n            \r\n            p = dynamic_cast&lt;CCInteger *&gt;(r-&gt;objectAtIndex(rand()%r-&gt;count()));\r\n            \r\n            _stage-&gt;replaceObjectAtIndex(p-&gt;getValue(), CCInteger::create( PATH ));\r\n            s = p-&gt;getValue();\r\n            \r\n            \/\/ TODO randomize end position\r\n            if (_end &lt; s) _end = s;\r\n            \r\n            stack-&gt;addObject(p);\r\n            \r\n            _deadend = 1;\r\n            \r\n            _path++;\r\n            \r\n        } else {\r\n            \r\n            \/\/ Add a cul-de-sac\r\n            if (_deadend &gt; 0) {\r\n                \r\n                q = dynamic_cast&lt;CCInteger *&gt;( stack-&gt;lastObject());\r\n                \r\n                _stage-&gt;replaceObjectAtIndex(q-&gt;getValue(), CCInteger::create( WALL ));\r\n                \r\n                _deadend = -1;\r\n            }\r\n            \r\n            \/\/ if cul-de-sac reached, step back \r\n            stack-&gt;removeLastObject();\r\n            p = dynamic_cast&lt;CCInteger *&gt;( stack-&gt;lastObject());\r\n            \r\n            s = p-&gt;getValue();\r\n        }\r\n        \r\n    }\r\n    \r\n}\r\n<\/pre>\n<p>And here&#8217;s the result<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\r\n\/\/ 11x11 tiles\r\n\/\/ 7 = Starting point\r\n\/\/ 8 = Ending point\r\n\/\/ 0 = Wall\r\n\/\/ 6 = Path\r\n\r\n0,0,0,0,0,0,0,0,0,0,0,\r\n0,7,0,0,0,0,0,0,0,0,0,\r\n0,6,0,6,6,6,6,6,6,6,0,\r\n0,6,0,0,0,0,0,0,0,6,0,\r\n0,6,6,6,0,6,6,6,6,6,0,\r\n0,0,0,6,0,6,0,0,0,6,0,\r\n0,6,0,6,0,6,0,6,0,6,0,\r\n0,6,0,6,0,6,0,6,0,6,0,\r\n0,6,6,6,6,6,0,6,6,6,0,\r\n0,0,0,6,0,0,0,0,0,8,0,\r\n0,0,0,0,0,0,0,0,0,0,0,\r\n<\/pre>\n<p>And another thing is path finding, the first choice is of course <a href=\"http:\/\/en.wikipedia.org\/wiki\/A*_search_algorithm\" title=\"http:\/\/en.wikipedia.org\/wiki\/A*_search_algorithm\" target=\"_blank\">A*<\/a>, but I removed\/modified several things;<\/p>\n<ol>\n<li>The <em>past path-cost function<\/em>, as is not required<\/li>\n<li>The open and close list, since I thought duplicating the <em>scene<\/em> array and tagging it with a different number would be faster, there&#8217;s no need for additional iterations nor added processing to deconstruct the extra arrays.<\/li>\n<li>And as for the <em>future path-cost function<\/em> I employed the Manhattan Method, which goes something like this.<\/li>\n<\/ol>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">H = 10*(abs(currentX-targetX) + abs(currentY-targetY))[\/cc]\r\n\r\nSimple enough, note the coefficient 10 is not necessary unless you're dealing with decimal, I used it just for the sake of it \u51f8(\uff400\u00b4)\u51f8\r\n\r\n\r\nvoid MazeGenerator::addPathfinding() {\r\n    \r\n    \/\/ Duplicate the stage\r\n    _pfind = CCArray::create();\r\n    _pfind-&gt;addObjectsFromArray(_stage);\r\n    \r\n    CCArray* stack = CCArray::create();\r\n    CCArray* r;\r\n    CCInteger* p;\r\n    \r\n    int s = _start, pos = 0;\r\n    \r\n    while (_path &gt; 0) {\r\n        \r\n        \/\/ Check surrounding for Path\r\n        r = checkSurrounding(_pfind, s, PATH);\r\n        \r\n        \/\/ If path exists\r\n        if (r-&gt;count() &gt; 0) {\r\n            \r\n            int temp = 0;\r\n            \r\n            for (int i = 0; i &lt; r-&gt;count(); i++) {\r\n                \r\n                p = dynamic_cast&lt;CCInteger *&gt;(r-&gt;objectAtIndex(i));\r\n                \r\n                temp = getCost(p-&gt;getValue());\r\n                \r\n                \/\/ to filter smallest cost\r\n                if(temp &lt; pos) pos = temp;\r\n                \r\n            }\r\n            \r\n            \/\/ Mark the path with 1\r\n            _pfind-&gt;replaceObjectAtIndex(pos, CCInteger::create( 1 ));\r\n            stack-&gt;addObject(CCInteger::create( pos ));\r\n            \r\n            \/\/ break if end reached\r\n            CC_BREAK_IF(_end == pos);\r\n            \r\n            _path--;\r\n            \r\n        } else {\r\n            \r\n            if cul-de-sac, step back\r\n            stack-&gt;removeLastObject();\r\n            p = dynamic_cast&lt;CCInteger *&gt;( stack-&gt;lastObject());\r\n            \r\n            s = p-&gt;getValue();\r\n        }\r\n \r\n    }\r\n    \r\n}\r\n\r\n\/**\r\n\r\nThe Manhattan Method\r\n\r\n*\/\r\nint MazeGenerator::getCost(int p) {\r\n    \r\n    int x0 = _end%_w,\r\n        y0 = _end\/_w,\r\n        x1 = p%_w,\r\n        y1 = p\/_w;\r\n    \r\n    return 10*(abs(x1-x0)+abs(y1-y0));\r\n    \r\n}\r\n<\/pre>\n<p>And the results is pretty good.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\r\n\/\/ 1 = Routes\r\n\r\n0,0,0,0,0,0,0,0,0,0,0,\r\n0,7,0,0,0,0,0,0,0,0,0,\r\n0,1,0,6,6,6,6,6,6,6,0,\r\n0,1,0,0,0,0,0,0,0,6,0,\r\n0,1,1,1,0,1,1,1,1,1,0,\r\n0,0,0,1,0,1,0,0,0,1,0,\r\n0,6,0,1,0,1,0,6,0,1,0,\r\n0,6,0,1,0,1,0,6,0,1,0,\r\n0,6,6,1,1,1,0,6,6,1,0,\r\n0,0,0,1,0,0,0,0,0,1,0,\r\n0,0,0,0,0,0,0,0,0,0,0,\r\n<\/pre>\n<p>Until next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Starting on my own game, although brilliant idea is immensely dependent on how the stars are aligned (metaphorical speaking obviously) still I can&#8217;t disclose the exact concept since the indie game scenery is notoriously brutal, but in a glimpse the basic premise is a maze with a few added twists. \u3058\u3083\u3042\u3001\u3044\u304d\u307e\u3057\u3087\u3046\u30fc\uff01 Choosing the Framework There [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2,7,16,18,19,23,24,33,34,41],"tags":[119],"_links":{"self":[{"href":"https:\/\/rahmat-hidayat.com\/index.php?rest_route=\/wp\/v2\/posts\/1047"}],"collection":[{"href":"https:\/\/rahmat-hidayat.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rahmat-hidayat.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rahmat-hidayat.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rahmat-hidayat.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1047"}],"version-history":[{"count":1,"href":"https:\/\/rahmat-hidayat.com\/index.php?rest_route=\/wp\/v2\/posts\/1047\/revisions"}],"predecessor-version":[{"id":1635,"href":"https:\/\/rahmat-hidayat.com\/index.php?rest_route=\/wp\/v2\/posts\/1047\/revisions\/1635"}],"wp:attachment":[{"href":"https:\/\/rahmat-hidayat.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1047"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rahmat-hidayat.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1047"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rahmat-hidayat.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1047"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}