duck.place

volume control - 03 May 2022

volume control

This has been a long time coming: you can now control the volume. Eventually I’ll add music and then there will be one control for sound and another for music.

jetpack powered by coins - 02 May 2022

Jetpack

There’s now a jetpack in the game. But to use it you need to have some cash on hand. Each time you press enter you can propel yourself upwards, as long as you have coins.

I plan to introduce more coin-based mechanics. Current ideas include doors that require x amount of coins to open and perhaps enemies that grow stronger with each coin they collect. We’ll see.

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

I lied - 23 Mar 2022

Two days ago I said the following in my devlog:

“if you save a level now it should be forward compatible with new versions for some time”

Well, I just broke that format. Sort of. I’ve added compression to the level files. So while the underlying format that the game uses to serialize a level is the same, before it is saved it gets compressed which changes the actual bytes. When the game loads a level it now expects a compressed level which means that old saves are now broken.

I didn’t expect compression to be necessary. When saving using the file icon the level is encoded as an image. Considering how many pictures of megabyte proportions are saved casually, a few kb is probably not a concern for anyone.

The pressure to keep level size down comes from the link sharing. Since levels are assumed to be authored by humans I had a rough idea of how big most levels would be. I estimated that levels more than about 50kb when encoded as b64 url strings would be rare. The server which stores shortened links for 24 hours is technically capable of megabyte long expanded urls. Furthermore, modern browsers can also handle quite big urls. The common rule of thumb seems to be to keep urls under 2000 characters but this is to ensure compatibility with any possible client. However, most browsers are not so picky. Firefox states a 65kb character limit for query urls. Safari says 80kb. Chrome is fine with 2mb.

Though I failed to consider one part of the equation. When the short links get expanded this happens through a redirect. My current solution expects destination urls to be max 16kb. 16kb levels are much more common. So I decided that compression was needed ASAP.

The current compression solution uses Godot’s built in compression with zstd as the backend. The compression ratio varies of course but seems to be high enough to be useful. I tried creating a level that exceeded the 16kb limit and had to spam a lot of items to the point that performance became a much bigger issue (I will eventually optimize performance as well) than level size.

It is of course still possible to go over the 16kb limit, no compression can stop that. Though I doubt most levels will. There is a work-around if this happens. Saving through the file icon has no limit as the level is encoded as an image.

As for the future: It would be nice not to be limited by 16kb for shared links. At some point I may consider a dedicated server for storing levels. A fast and reliable server, capable of storing levels indefinitely, can be costly. Now is not really the time. But who knows what the future holds.

new minor version - 21 Mar 2022

I’ve incremented the minor version of the game from v0.1 to v0.2. The increment is sort of arbitrary but the main motivation is that the file format was just updated to something that I think is a bit more permanent. The idea is that future changes to the file format will not break old levels. I can’t promise that this will hold for all future but if you save a level now it should be forward compatible with new versions for some time.

Other recent additions include trees:

Tree

Visual feedback when trying to put stuff in a crate:

Tree

And support for movement with arrow keys.

link sharing - 05 Mar 2022

Levels can now be shared with links. The purpose is to make it easy to share the levels you create with friends. Using link sharing is quite simple:

First click the link icon to the right of the screen.

Link icon

Then simply click “get link” followed by “copy link” to copy the link to your clipboard. You can now paste it wherever you want.

Link sharing

Note that this link expires within 24 hours, so make sure your friend opens it before then. Fortunately, once it is opened the link expands to its full size. This larger link will not expire. However, these can get quite long so it is a bit cumbersome to pass these expanded links around.

Expanded link

If you’re interested why this is, I can briefly explain how link sharing works on the technical side. When you request a link by pressing “get link”, the game saves your level, similar to when you press the regular save icon. Once the game has collected this save data, it encodes it to a base 64 string. Base 64 is a way of storing binary data as characters. This means that they can be passed along into your browsers address bar. This base 64 string can be used to construct a url with the level data as a parameter, which looks something like this: “https​://duck.place/?d=AQAAAA…..”. However, since this url has to be long enough to store the entire level it can be unpractical to share this link directly.

To solve this, the game takes this long link and sends it to a server which gives it a short name, which might look like “https​://share.duck.place/abcdefg”. This server then remembers that whenever someone asks for this short link, they really want the long, expanded url that contains the entire level. Since the server must remember all expanded links, it consumes memory. There is a limit on 24 hours, as well as an upper bound on the total amount of links, to prevent it from taking up too much memory. If these limits become an issue I will expand them.

An interesting issue is that browsers have a limit for how large a url can be, effectively putting a limit on how large your level can be before it can no longer be shared. It depends on what browser you have. There is also a size limit on the server side. How big your levels can be I cannot say at the moment. It depends on the current level encoding scheme I have. This is unfortunate, as the player should really be given heads up if their level is about to grow to large. Giving players feedback on their level size so they know if it can be saved as a link or not is part of my backlog. So it will eventually be added.

That’s all for now. Hope you get some fun out of link sharing!

PS: I really need to organize the devlog better. There should both be a pages and an overview, so that it is easier to browse.

graphical changes - 16 Feb 2022

Coins

I’ve tried to improve the quality of the graphics by updating some of the blocks. The grass, rock, and stone tiles should hopefully be a bit nicer to look at.

I’ve also added coins, a staple of the platforming genre. Right now they don’t do very much. You can collect them, that’s it. Still, they can be used as a visual cue to guide players through your level. In the future I will add more concrete mechanics to the coins.

Coins

There is now also a new type of cannon. This one doesn’t hurt you, but it does knock you back.

That’s all for this time.

added various stuff - 10 Feb 2022

I’ve added somes stuff. I will now list them:

New blocks

Two new blocks. First one is stone brick. The other one I call “space foam”. Seen above.

Red moving platform Rising platform

I’ve added two new types of moving platforms. Try them out to see what they do.

Cannons

There are now cannons. You can change both the frequency at which they fire and their phase. By phase, I mean the ability to offset the timing so that, for example, two cannons can fire at the same rate but at different times.

Moon

Finally, I’ve made the map go higher. Space is now more vast. If you go up far enough you get to see the moon.

Hope you enjoy these new additions.

added multiplayer - 29 Jan 2022

Multiplayer example

The foundations for multiplayer are now up. First off, it is VERY unstable. Chrome and safari work better than firefox. Though whatever browser is used, multiplayer will still be a buggy mess. Even though multiplayer is far from “ready”, I decided to put up anyway. I figured it could be fun to play around with. Not everything needs to be perfect from the start.

Also, many of the issues are only apparent when I run the game online, as opposed to running local builds. Pushing multiplayer to the website allows me to debug in the intended execution context. While I could set up a test server specifically for this purpose, I see no harm in letting everyone see how janky everything is at the moment.

Issues that I know about so far include the following:


I’m using webrtc, which means that agreeing on what is the proper state of the game is a bit tricky. Because of latency, drift, and so on, peers will disagree on the exact positions of, whether or not an enemy has been killed, etc. With a classic client/server setup, clients rely on the server to decide on what is the “true” state of the game. Here, I’ve decided to let the host peer to be the source of truth for most things. There are exceptions, mainly that every peer gets to be the authority on their own player.

I also have concerns regarding user friendliness. For example, every player can switch the game mode which is kept in sync. So if someone decides to go back into the editor, the game gets reset for everyone. This can be incredibly frustrating. For things like these I need to come up with a good strategy. Perhaps only the host can change the game mode. Perhaps everyone has to agree to a mode change. Or perhaps everyone can be in different modes and when desired sync their state and play together. The last one seems hairy to implement though.

Anyway, I hope some fun can be had with the super-janky multiplayer. Expect it to become more stable over time. If you want to try it out just open the game and click the button with the three ducks, shown in the image below.

Multiplayer button

added moving platforms - 08 Jan 2022

Moving platform in action

I’ve finally added some moving platforms to the game. Right now, the platforms only support linear motion. You place a platform, then set its destination as well as its speed.

Moving platform in the editor

In the future I want to add more intricate movement patterns. For example, it would be nice if you could define a path made out of an arbitrary number of points.

Moving platform with many destination points

And perhaps instead of linearly interpolating between these points you could do a cubic spline or bezier.

Moving platform with smooth path

Also, I can think of many situations where it would be nice to move the platform in a perfect circle.

Moving platform with circular path

There are many possibilities but I decided not to get carried away yet. We’ll see what happens once I return to moving platforms.

updated site, added a devlog - 02 Jan 2022

Let me start off by saying welcome! On this site you can find my “make-your-own-level” 2D platformer game. Rather than being a game that tells you what to do, you will be in charge of the experience!

The site now contains a devlog and an about page. Before it was just one page containing the game. Since this is the first post of the devlog I thought I could describe what I’ve done so far.

I started development on this game, which does not really have a name, during the summer of 2021. It’s basically mario maker with a duck. I’m using the godot engine. Using an out-of-the-box engine simplifies a lot of things though the ability to easily export to HTML5 and wasm is the main selling point for me. I choose godot over other available engines because it is easier to use, gives more control and is less bloated than the alternatives. Since it is open source it is comforting to know that if I run into some engine quirks that hinders me from achieving what I want I can always fix it in any way I’d like.

In future posts I might ellaborate more on development details but since I’ve worked on this game for ~6 months it’s a bit hard to summarize all of that in one post. I will just give an approximate list of what’s in it so far:


What I have so far is the basic foundation of the game. As more items and stuff are added there will be a superlinear increase of possibilities. I believe there is a critical mass of functionality which once reached will give the player a near endless amount of things to do. Right now I’d say were definitely below that limit. When I’m playing around with the current game I have fun for a little while until I feel limited which kills the creativity. So the current plan is to just add more stuff until that is no longer an issue. Simple enough, right?