Game development has been a hobby of mine for a long time. I especially enjoy creating interesting things from simple parts. My game programming page has links to articles I wrote and articles I found useful. This blog has my writings about game design, game development, and game reviews.
While writing my guide to hexagonal grids I ran into some html+css+js issues that I need to spend more time learning about. Here are a few things that are on my mind.
Responsive layout
I got a little frustrated with the layout options I had in HTML+CSS. I want to write HTML one way, then use CSS media queries to reformat the layout to work with wide desktop, narrow desktop, and mobile widths.
For some of my previous articles, I used floats. It works nicely in the simple case.
However, for this article I often found that the best layout for narrow would be to put diagram B in the middle of the text A+C:
But now the diagram is aligned with C; I want it to be aligned with A. I don’t know the best way to do this. I ended up using three different patterns.
- When A and C were taller than B, I used absolute positioning to take B out of the flow and line it up with A:
narrow
ABCwide
ACB - When A and C were shorter than B, I didn’t have a good solution, so I moved C’s content into A’s and used floats. This hurt the layout on narrow devices, where it ended up in the wrong order:
narrow
ACBwide
ACB - Occasionally I just wanted things to be side by side but not floating, so that I could get this:
narrow
ABCwide
ABC
In the end I wasn't happy with the different CSS rules that I used, but they seem to work. I could have reformatted with Javascript but kept hoping CSS alone would do the trick. Flex boxes don't seem to help here (unless I'm missing something). It's possible CSS Regions would do what I need; it's not widely supported yet. I'm a novice with floats; it's quite possible with some cleverness I could've gotten what I wanted.
Browser compatibility
Some things that bit me:
In WebKit I can use SVG’s baseline alignment to vertically center text. This becomes very handy when I want to write generic code that places text no matter what size the hexagons or what size the text. However in Gecko, I can’t use this. Instead I need to adjust the text position downwards, which depends on the size of the text. But I don’t know the size of the text in the generic code because it’s set later by the CSS on the page. So I fudged it. Also see Nelson Minar’s post on this topic.
In WebKit I can use the DOM node’s
.clientWidthand.clientHeightto get the size of the SVG. I then use that to center the diagram in the SVG frame. In Gecko these were returning 0, so I ended up reading thewidth=andheight=attributes of the SVG instead.
Performance
I wrote the animations in a straightforward way but there are way too many animations running at once. I have a single toggle for the orientation (pointy top vs flat top) of all the diagrams on the page. When you change the orientation it rebuilds all of the diagrams. This is slow.
I guess I was hoping requestAnimationFrame would magically solve everything. But it doesn’t. It doesn’t know where the output will be on screen, and therefore whether the code needs to be called. So I need to do that. I need to look at each diagram, figure out whether it’s on screen, and decide whether to change it immediately or to delay it. But if I delay it, and you toggle it back, then I have stacked timer handlers to deal with. So I haven’t finished implementing this.
A simpler approach would be for me to not link the orientations together, so you’d separately toggle it for each section of the page.
Touch screens
Although I did a little bit of testing on touch screens, I didn’t spend enough time getting the interactions to work well with touch events. Instead I’m (mostly) relying on the emulation of mouse clicks. There’s a ~300ms delay for this emulation though, so it doesn’t feel smooth. There’s a library to fix this but I haven’t tried it. It’d also be nice on touch screens to tap and drag to select multiple hexagons, but I didn't implement click and drag either so I'm consistent in my not supporting the nicer UI.
Labels: writing
A few weeks before Game Developers Conference, I thought to myself, what article can I write that’ll just take 2 weeks? I decided hexagonal grids, as a subset of my bigger article on all grids, would be a reasonable choice. I already have all the material; I've collected it for nearly 20 years on my site.
I was wrong.
I was wrong about how long it would take. It took me roughly 8 weeks. I was also wrong that I already had all the material. The more I dug into hexagonal grid algorithms, the more cool patterns I found — things I hadn't seen elsewhere. And I wanted to not only write about them but implement them and create interactive diagrams. I printed out sheets of hex grid paper (from here), played with the algorithms, tested things out, and discovered new things. I implemented the data structures in Haxe and visualizations in d3.js.
And there are still so many things I wanted to do but didn’t!
For example, I wanted to generate code on the fly for each the grid types. I thought, if I represent the core algorithms in an abstract syntax tree format, I can compose parts together, write an expression optimizer, and generate new code. For example, the neighbor algorithm is written in hex cube coordinates. To use a different coordinate system, like odd-R offset, you’d use convert_cube_to_odd_r( neighbor( convert_odd_r_to_cube(hex) ) ). If you compose these functions, inline, and optimize, you could get a neighbor algorithm custom designed for the odd-R coordinate system. I could generate that, on the fly, in Javascript, and display it to you. I could then give you a menu asking you which of the 74 grid types you use, and then I could generate a hex algorithm library for you, based on your needs. And maybe even in the programming language of your choice.
Is that feasible? I think it is.
There are lots of other things that I would like to do but decided to cut. I would’ve liked to clean up the code to produce a reusable library for others to use. I’ve made a list on Trello with all of the things I could've done, but didn’t.
Instead of doing all those things, I decided it’s better to finish and publish (ship!) than to delay it to do the more ambitious things. I can leave them for version 2. It's like shipping a game. You have to cut things. It's better to ship something good enough than to never ship the perfect game.
Take a look at my new guide to hexagonal grids. Let me know what mistakes I made. Let me know what questions you have. Let me know what you’d like to see in a future version. Quick fixes I’ll make soon; bigger changes will wait for version 2. Thanks!
I love city building and transportation games, and ever since I worked on one, I’ve had a side interest in how to represent and draw roads and railroad tracks. After playing lots of Cities XL, I started to wonder how I’d represent curved roads.
The roads in Cities XL aren’t curves. They’re approximations to curves, using short line segments. I noticed in screenshots and videos of SimCity 5 that it also uses short line segments. Is there a way to represent curved roads without turning them into line segments? I wanted to avoid seeing roads like this:
“You see those roads in Hammerfell? They’ve got curved roads. Curved. Roads.”
So I wrote up my notes on circular arcs.
It took much longer than I had planned to write it. I started in October and was hoping to finish in December, but here it is two months later. Why did it take so long?
- I got distracted for several weeks learning about Geometric Algebra. This is a fascinating topic, and potentially useful for a future project, but I couldn’t figure out how to use it for this project.
- I’m quite rusty with math, and there’s some geometry and algebra involved here. The math for biarcs in particular took some time to figure out, with different approaches given in different papers, and none of them giving me everything I needed to know.
- Over the holidays I lost motivation, and ended up spending a month relaxing, hiking, and birdwatching.
Some things that could’ve gone better:
- The way arcs are defined in SVG seems really strange to me. The core definition is ambiguous so they include two extra flags to disambiguate. The way arcs are drawn in Canvas seems more intuitive but I’m guessing SVG’s approach must have some advantages.
- Arc radius goes to infinity for straight roads, which are common. I’m ignoring this to some extent but a real game will have to handle them. An alternative might be using curvature instead of radius, but I didn’t try this.
- IE9 doesn’t like
d3.hsl()so I instead am usingd3.hsl().toString(). This would’ve been easier to debug if IE had a nicer inspector. - Android stock browser requires SVG clip paths to be defined inside
<defs>; I’m not sure if that’s part of the standard but it was annoying to debug. Android’s Chrome and Firefox browsers are more forgiving. - On iOS, large SVG arcs take a really long time to draw, and freeze up the phone. I have not put in a workaround.
- I’ve attempted to automatically adjust the layout for wide vs. narrow browsers, as well as mobile and tablet, but I’m unsatisfied with the results. It’ll have to do for now; I’ll take another look at this later.
It was lots of fun to play with this. However, I think that I may stick to grids for the next game.
Here’s the article about curved roads.
Labels: math