{"id":14162,"date":"2015-03-01T04:06:57","date_gmt":"2015-03-01T04:06:57","guid":{"rendered":"http:\/\/rafaelfajardo.com\/portfolio\/connected-tiles-using-bitflags\/"},"modified":"2024-09-26T11:19:57","modified_gmt":"2024-09-26T17:19:57","slug":"connected-tiles-using-bitflags","status":"publish","type":"post","link":"https:\/\/rafaelfajardo.com\/portfolio\/connected-tiles-using-bitflags\/","title":{"rendered":"Connected Tiles using Bitflags"},"content":{"rendered":"<p><a href=\"http:\/\/mflux.tumblr.com\/post\/112376004890\/connected-tiles-using-bitflags\" class=\"tumblr_blog\">mflux<\/a>:<\/p>\n<blockquote>\n<p>So lately I\u2019ve been working on a city-simulator. I\u2019ve tackled a lot of interesting problems and have been posting some progress shots on <a href=\"http:\/\/twitter.com\/mflux\">Twitter<\/a>.<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/46b1a481257cdaa1b7b5c34689c142d8\/tumblr_inline_nkic272qAT1qg01ej.png\" alt=\"image\" \/><\/figure>\n<p>Sometimes I get requests for a writeup on my process, this is generally a good thing, people are interested in what I\u2019m making, and I get to spew out my thought process on the internets.<\/p>\n<p>My aversion to this is because I prefer to save writeups like these for post-mortem. There\u2019s a lot more interesting things to tackle that I have yet to tackle, like socio-economics simulation, or culture generators. The technical stuff, that stuff comes pretty easily, to me it\u2019s not as worth that much talking about.<\/p>\n<p>On top of this, I really hate doing \u201cmarketing\u201d for a project before it\u2019s ready (blog posts are marketing now, apparently). I\u2019m not a fan of this \u201crelease early release often\u201d marketing approach for indies. Yes, there are benefits of doing this, however the surprise factor, the freshness factor in the eyes of people worth seeing it will be diminished. I find the lack of surprise in a transparent development process to be quite the hinderance later on.<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/b9ecce7fd9f0ecd7eb6986bfb071edc2\/tumblr_inline_nkic9sRwv01qg01ej.png\" alt=\"image\" \/><\/figure>\n<p><\/p>\n<p>During my daily trawls through twitter, I found this curious post about procedurally generating Millennium Falcon style texture maps. I mean, this is really great stuff, I\u2019ve always wondered about doing something like this \u2014 how one might actually approach this problem. I can see baking the AO, what about generating the greeble? What about connecting lines across multiple surfaces so they all line up? Defining what parts of the mesh is an exhaust port and giving that the appropriate color? That stuff is fascinating to me.<\/p>\n<p>As an impatient person it also really frustrated me that Howard Day (what a name) didn\u2019t also include a process-post. The nerve! Showing cool shit off on twitter without talking about how it\u2019s made.. that is so annoying.<\/p>\n<p>Wait a minute. That\u2019s exactly what I do. Shit.<\/p>\n<p>So I\u2019ve managed to guilt myself into doing a writeup. This is good, at least it\u2019ll be written down somewhere. The most recently asked topic was about road tiles, so let\u2019s start there.<\/p>\n<hr>\n<h2>Where we\u2019re going we actually need roads<\/h2>\n<p>This is going to be an awkward writeup since I\u2019ve tackled this exact problem at least three separate times (that I can count) and came up with different approaches each time. There are also numerous inter-connected problems that have to do with game design. I\u2019ll just focus on the direct problem and the solution I ended up at, skipping some seriously circuitous problem solving that will only take you down some nasty rabbit holes.<\/p>\n<p>The premise:<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/58de2f290f52f5f9be4b8a11a7ce0c5b\/tumblr_inline_nkicnjUfMx1qg01ej.jpg\" alt=\"image\" \/><\/figure>\n<p>The game is a city simulator, so one has to think about road planning, the veins and skeleton of a city. Making a few gameplay assumptions, this generally means allowing the player to directly draw roads, place them on some surface, connect roads with each other, etc.<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/dfde325d4df0f2c720c1f5eebc022a9c\/tumblr_inline_nkictiu1FT1qg01ej.jpg\" alt=\"image\" \/><\/figure>\n<p>The original Sim City by Will Wright was created because he had more fun designing the maps for Raid on Bungeling Bay. The tech at the time only really allowed for tile-based map visualization, it was great because you can get excellent variety with a ton of re-useable assets.<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/f6f38eba11487406c412012619e0f79f\/tumblr_inline_nkicv5XSeC1qg01ej.gif\" alt=\"image\" \/><\/figure>\n<p>The roads ended up being on a grid, which has some inherent limitations. Diagonal roads are harder to make, and we\u2019ll see why when we break this problem down.<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/00aa8f74f87a522dca1f6220867be84e\/tumblr_inline_nkid96OB081qg01ej.jpg\" alt=\"image\" \/><\/figure>\n<p>Here the road tiles are represented by R, perhaps a number in our data map. Zones, parks, police stations, they all occupy some space on this map, so they also get separate id numbers as well.<\/p>\n<p>This is not good enough. Just because the data looks like this, road tiles aren\u2019t a uniform graphic that you can just clone stamp across the rendered map. Roads have directionality, the tile that gets drawn needs to care about what tiles they\u2019re connected to.<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/a2e746540f3a3fd9236e9e7cd90cdd52\/tumblr_inline_nkidpzhyYN1qg01ej.jpg\" alt=\"image\" \/><\/figure>\n<p>The simplest variations are pretty straightforward. You have roads that go up and down, so you have these road tiles going from north to south, center divider is vertical. Ditto with horizontal. When these orthogonal directions intersect, you have an intersection, so perhaps this tile connects to all 4 corners, with stop lights. There are more variations, such as a T junction (4 variations).<\/p>\n<p>To know what graphic should be drawn at a particular tile, you have to know its neighboring tiles.<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/e177e53891fcbdda2ad2ddf3821c6436\/tumblr_inline_nkiffx9FIy1qg01ej.png\" alt=\"image\" \/><\/figure>\n<p>This is a pretty well established gamedev problem. Essentially, an artist draws every possible permutation of connected roads (or whatever, it could even be connected cliffs \/ ground tiles used for side-scrolling games for example). Then the map designer simply picks the right puzzle piece to use for that particular section of the map.<\/p>\n<p>There are several\u00a0<i>(annoying)<\/i> problems with doing this.<\/p>\n<p>Making the assets would be a <i>combinatorial nightmare<\/i>. Imagine having to create the above just for one version of this tileset. If I wanted to have wider roads, or highways, I have to do the above all over again. Even in the above example image, there would be no way of creating arbitrary turns or intersections on terrain that goes up or down unless I also want to author that! Let\u2019s not forget what if we wanted diagonal roads?<\/p>\n<p><\/p>\n<hr>\n<p><i>As an aside\u2026<\/i><\/p>\n<p>At some point you\u2019ve probably asked yourself why I even bothered to stick with tiles and not just do arbitrary straight-line roads. I guess that\u2019s an article for another day, however I did do that experiment and ended up with some OK results (with a slew of other kinds of problems).<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/e57374190a86afa0172672a6b19b861b\/tumblr_inline_nkig0n26WX1qg01ej.png\" alt=\"image\" \/><\/figure>\n<hr>\n<p>So now we\u2019ve identified the problems:<\/p>\n<ul>\n<li>We need a fast way to generate all possibilities of road connections before the heat death of the universe.<\/li>\n<li>We need a good layout engine that can seek neighbors and pick the right tile to use.<\/li>\n<\/ul>\n<p>Let\u2019s talk about the layout engine first since we need a plan for this.<\/p>\n<p>The most naive implementation of a world map looks something like this:<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/c8234c4a794b56f27d79f02907420c93\/tumblr_inline_nkih4aNqku1qg01ej.png\" alt=\"image\" \/><\/figure>\n<p>Here, 1 represents a road tile, and 0 represent nothing, empty space.<\/p>\n<p>The layout engine that picks the tile would go through the map grid in a 3&#215;3 pattern and examine each tile and its neighbors.\u00a0<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/a2e746540f3a3fd9236e9e7cd90cdd52\/tumblr_inline_nkih7bYcWd1qg01ej.jpg\" alt=\"image\" \/><\/figure>\n<p>What happens when we only examine orthogonal directions, ignoring diagonal tiles completely?<\/p>\n<p>So for example in the above illustration it would look like.<\/p>\n<p>Top left (tile by itself)<\/p>\n<p><b>\u00a00<br \/>010<br \/>\u00a00<\/b><\/p>\n<p>Top right (tile going north)<\/p>\n<p><b>\u00a01\u00a0<br \/>010<br \/>\u00a00\u00a0<\/b><\/p>\n<p>Bottom left (L shape, north and east)<\/p>\n<p><b>\u00a01\u00a0<br \/>011<br \/>\u00a00<\/b><\/p>\n<p>Bottom right (intersection)<\/p>\n<p><b>\u00a01<br \/>111<br \/>\u00a01<\/b><\/p>\n<p>This method is alright so far. In fact, we can then compact this information into a lookup table, so it looks like a binary<\/p>\n<p>Top left (tile by itself)<\/p>\n<p><b>00100<\/b><\/p>\n<p>Top right (tile going north)<\/p>\n<p><b>10100<\/b><\/p>\n<p>Bottom left (L shape, north and east)<\/p>\n<p><b>10110<\/b><\/p>\n<p>Bottom right (intersection)<\/p>\n<p><b>11111<\/b><\/p>\n<p>If we continue this, we can then create a lookup table that contains all combinations of road tile connections and their associated graphic tile.<\/p>\n<p>This is good enough if we only care about orthogonal road maps, however that makes for some boring road layouts. Diagonal roads would make this way more interesting, for instance Sim City 4:<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/d8855e8dc314a41f62c1c9c95ed49f3c\/tumblr_inline_nkihn7OzNw1qg01ej.jpg\" alt=\"image\" \/><\/figure>\n<p>Okay, this should be easy right? We were only examining the orthogonal tiles, we should extend this to the diagonal tiles if we want this feature. Let\u2019s take a look at what happens:<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/4a4f382854f50b7c2379041c31aeb5e6\/tumblr_inline_nkihyeBY2b1qg01ej.jpg\" alt=\"image\" \/><\/figure>\n<p>From left to right\u2026<\/p>\n<p>Top left diagonal (going to north-west)<\/p>\n<p><b>100<br \/>010<br \/>000<\/b><\/p>\n<p>Going north AND north-west (?)<\/p>\n<p><b>110<br \/>010<br \/>000<\/b><\/p>\n<p>Going north AND west AND north-west (???)<\/p>\n<p><b>110<br \/>110<br \/>000<\/b><\/p>\n<p><b>Uh oh.<\/b><\/p>\n<p>What\u2019s happening is that the tiles don\u2019t care at all about <i>connectivity<\/i>, since this whole system relies entirely on a binary switch of their neighbors. When diagonals are connected alongside their orthogonal brethren, you end up in this situation where it\u2019s totally ambiguous how the roads should be formed.<\/p>\n<p><b>111<br \/>111<br \/>111<\/b><\/p>\n<p>What happens now? Should this be a star intersection? Or a just a big parking lot?<\/p>\n<p>Not to mention, we wouldn\u2019t be able to have roads that run alongside each other.<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/9c94d5637e8869d350722846e4c2b7ba\/tumblr_inline_nkiifv1B0w1qg01ej.jpg\" alt=\"image\" \/><\/figure>\n<hr>\n<h2>Check yo bit flags<\/h2>\n<p>What we really want is a system that says, <i>road tile, you are<\/i> <i>connected to<\/i>\u00a0north, south, and north west, and that is all. We can represent this information as such:<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/3b89348aa8849962569149719032bdfa\/tumblr_inline_nkiiom4eZt1qg01ej.png\" alt=\"image\" \/><\/figure>\n<p>So when we touch the map, we have to be aware of what is being connected to what. Each tile needs to connect <i>back to each other<\/i>\u00a0in order for this to work.<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/8d0c698c584bb91f8943217c354d5425\/tumblr_inline_nkiiwpEZlf1qg01ej.jpg\" alt=\"image\" \/><\/figure>\n<p>Now I were really lazy I would just leave it as is and call it a day. Good job Michael.<\/p>\n<p>However, we can improve this code <i>so much more.<\/i><\/p>\n<p>For instance, the tile really should have no place carrying 8 pieces of information. It sucks to have to check each boolean here, on top of that it\u2019s a huge waste of memory and manipulating this information would be quite annoying.<\/p>\n<p>Instead, each tile should just carry one unique number to represent any of the possible connections, diagonal or otherwise, just like we had before. To do this we need to use bitflags.<\/p>\n<p>A somewhat <a href=\"http:\/\/wakeupandcode.com\/storing-and-retrieving-multiple-flags-in-an-integer\/\">decent introduction to bitflags can be found here<\/a>. Essentially, we can pack a lot of information into a single integer if we represent a number as a series of bits.<\/p>\n<p>This allows us to create \u2018flags\u2019, booleans that can be added to and checked against in a number.<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/0a2bcc1fcd09776ecd74778e356f2f7a\/tumblr_inline_nkikt8sYGs1qg01ej.png\" alt=\"image\" \/><\/figure>\n<p>So to continue this, we can build a definition of directions<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/52527d310df34ddc53ef6cab0c299d11\/tumblr_inline_nkijmpMOof1qg01ej.png\" alt=\"image\" \/><\/figure>\n<p>And now each tile has some notion of what neighboring tile it\u2019s connected to!<\/p>\n<p>This has some pretty staggering ramification, not the least path-finding will be quite different. Some of the issues I talked about earlier are now solved quite handedly:<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/0c7dacf5634a2a012f0f0f46aaf8bf2c\/tumblr_inline_nkijraba2b1qg01ej.png\" alt=\"image\" \/><\/figure>\n<p>It is now no longer ambiguous which tile is connected to which, since we know for certain that the orange highlighted tile is connected to northwest, west, and east, and nothing else.<\/p>\n<p>We can then do stupid stuff like having that angle tile connect back to its orthogonal neighbor:<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/1c9c7d73be5f35601b1e666472b32629\/tumblr_inline_nkijt50WQd1qg01ej.png\" alt=\"image\" \/><\/figure>\n<p>Build a neighboring road network that don\u2019t touch the existing ones:<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/c81785b73ae555ecced6215ec4b3191f\/tumblr_inline_nkijvefTpl1qg01ej.png\" alt=\"image\" \/><\/figure>\n<p>And all manners of weird edge-cases:<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/d6bca39260d24cfe1cd8a4e958c8e971\/tumblr_inline_nkijyye8aY1qg01ej.png\" alt=\"image\" \/><\/figure>\n<p>What gamedev tumblr post would be complete without an animated gif?<\/p>\n<figure><img decoding=\"async\" src=\"https:\/\/66.media.tumblr.com\/c170e5431450102a641bc01b9dd0451b\/tumblr_inline_nkik3do0eU1qg01ej.gif\" alt=\"image\" \/><\/figure>\n<hr>\n<p>I haven\u2019t even touched the geometry generation aspect of this project yet so perhaps I\u2019ll head there in my next post since there are a lot of issues in the above that I haven\u2019t even mentioned.<\/p>\n<p>If you enjoyed this, please RT me @<a href=\"http:\/\/twitter.com\/mflux\"><\/a><a href=\"http:\/\/tmblr.co\/mfCwJHX75W_2lQdpuZzVirg\">mflux<\/a>\u00a0feel free to ask me questions or give me suggestions and comments. You can also find me lurking as a moderator on <a href=\"http:\/\/reddit.com\/r\/gamedev\">reddit.com\/r\/gamedev<\/a>, a great community of game developers on reddit.\u00a0<\/p>\n<p>Finally if you\u2019re curious what tech I\u2019m using, this is all Javascript, using THREE.js running WebGL.<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>mflux: So lately I\u2019ve been working on a city-simulator. I\u2019ve tackled a lot of interesting problems and have been posting some progress shots on Twitter. Sometimes I get requests for a writeup on my process, this is generally a good thing, people are interested in what I\u2019m making, and I get to spew out my [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[10],"tags":[],"class_list":["post-14162","post","type-post","status-publish","format-standard","hentry","category-words"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p6PWot-3Gq","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/rafaelfajardo.com\/portfolio\/wp-json\/wp\/v2\/posts\/14162","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rafaelfajardo.com\/portfolio\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rafaelfajardo.com\/portfolio\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rafaelfajardo.com\/portfolio\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rafaelfajardo.com\/portfolio\/wp-json\/wp\/v2\/comments?post=14162"}],"version-history":[{"count":1,"href":"https:\/\/rafaelfajardo.com\/portfolio\/wp-json\/wp\/v2\/posts\/14162\/revisions"}],"predecessor-version":[{"id":56671,"href":"https:\/\/rafaelfajardo.com\/portfolio\/wp-json\/wp\/v2\/posts\/14162\/revisions\/56671"}],"wp:attachment":[{"href":"https:\/\/rafaelfajardo.com\/portfolio\/wp-json\/wp\/v2\/media?parent=14162"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rafaelfajardo.com\/portfolio\/wp-json\/wp\/v2\/categories?post=14162"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rafaelfajardo.com\/portfolio\/wp-json\/wp\/v2\/tags?post=14162"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}