slopes are cursed - 21 Apr 2022

slopes example 1

It’s been almost a month since my last post and there’s a good reason for it. I’ve been hard at work implementing slopes. It’s been a wild ride full of annoying edge cases. Mario Maker 1 famously did not include slopes and instead deferred it to its sequel and I can understand why.

Generating slopes in a grid based sandbox game where the user should be able to generate any angle is a challenge in and of itself. Making it look decent while working within the confines of pixel art makes it even harder. I’ve created a system that looks alright in common cases but there are plenty of cases where the generated slope looks a bit off. I’ve decided to upload what I have so far and leave perfection for later. With that out of the way, let’s break down the implementation:

First off, I decided on using a click and drag approach for the input method. Once a user has started dragging the mouse we generate a line based on the position that was first clicked and the current mouse position. There are a lot of nuances to this part, which I’ll spare you the details of. We use this line to generate polygons that fit in each of the intersected grid cells.

slopes example 2

We add a “top” texture to each of these polygon, applying correct texture rotation and offset.

slopes example 3

We also create another polygon for the background based on the top polygon.

slopes example 3 and quarter

Presumably because of precision errors the background polygon is poking up from behind the top polygon, as indicated by the arrows. So we have to use some heuristics to offset a few of the vertices in the polygon.

slopes example 3 and helf

That’s better! The current scheme is alright for this case but when we add regular blocks we get very noticable seams between the slope and the blocks.

slopes example 4

So we replace Godot’s autotiling routine with our own solution. This looks much better.

slopes example 5

But this can only get us so far. The top texture is only present on slopes so in certain cases we get these ugly gaps in the slope top.

slopes example 6

So we generate polygonal patches to fix this issue.

slopes example 7

Add a texture to these patches and things are looking decent. It is up to our autotiling solution to figure out when these patches should be visible.

slopes example 8

And that’s basically the current scheme. It’s far from perfect. Some ill-behaved cases can be seen in the image below.

slopes example 9

I’ll leave slopes alone for a little while before I lose my mind. I have an idea for a more robust solution in the future. It would involve grouping a contiguous group of blocks/slopes of the same kind and figuring out the signed distance to the nearest edge of this contiguous group for each pixel. A custom fragment shader could then sample from a suitable texture corresponding to either a top, left/right, bottom, or internal part of the block. Haven’t thought the details through but my instincts tell me that something like that is possible.

For now, try to enjoy the slopes even if they can look a bit odd at times. You can activate them by toggling the golden icon when selecting tiles.

slopes example 10