I Really Move On - Post Mortem


Wait, itch.io has a devlog? 🤯

Okay, let’s give it a try! This is my first Post Mortem on this platform. I welcome feedback :-)

Since the formatting options are limited here, I’m going to abuse bold for headlines.

Sorry for the lack of semantics :-/

My Post Mortems tend to become longform content. I hope you’ve got some snacks at hand.

I like to outline my thought process as I go along my commit history. Feel free to jump to the very end.

Prequel

Why participating? Because Andrzej. I came to enjoy his competitions.

Since I’m a web developer by trade, I don’t have many options to explore game mechanics. It’s an interesting exercise to me. I normally tend to explore new technologies, since so many contestants are too good, so I won’t have a chance for winning anyway.

Day 1

First things first. The topic for this Jam was „Mirror”. Since I was announced SVG review topic owner I need to learn more about this technology.

I already had some exposure and enjoy the math-y bits of it.

Since a few weeks, I’m also member of the viewBox club which inspires me to do more.

But I disgress …

Okay, I have my boilerplate code I apply anyway.

  • Pick a license*? GPL v3+ ☑️

  • Add gitignore ☑️

  • Pick a new technology*? esbuild and fastify - Unlike js13kgames I may want to offer multiplayer mode, which requires me to have a server side part ☑️

  • Add renovate* ☑️

  • Update README* - I put a line of what the repo is about and state the license ☑️

I configured my run-scripts in such a way, that I could bundle Client-side JavaScript (for testing, a console.log only) and serve a HTML file by the server.

Day 2

Now, what will the game be about?

Mirror … mirror … on the wall!

What if light was reflected from walls made out of mirrors?

Looks like I’ve got a game idea really fast :-D

Let’s spring into action to get the basics done.

The boilerplate HTML was put in place already. So I could add a SVG element and draw a M.

In fact, I droodled some art already. Here, I wanted to form the word MIRROR as a single path element where one character flows into the next.

My SVGs have normally a viewBox of 100×100, because that makes it easier to calculate. Of course, I could use a tool link Inkscape, but where’s the fun in it? I enjoy handcrafting SVGs :-)

Day 3

I had a problem. Um … challenge. I could serve HTML from fastify but not the JavaScript. Bundling introduced a hash as part of the file system. So I decided to move everything into the client directory and defer the copy operation to esbuild. That introduced a hash into the HTML file, too 🙄

So fastify learned to look into the target directory for any HTML file.

Can someone explain me, why I need a plugin for simple tasks like serving static files? 😮‍💨

Anyway, let’s add some animation!

The level was hardcoded into the SVG at this point, but I was sure, that the user-controlled input (the light beam) had to be dynamic.

To improve the UX, I wanted the path to be animated.

For this, I referred to an article by good ol’ Jake.

During my last js13kgames development, I came up with a pattern on how to create SVG elements. So I ported my helper function (which accepts a string for the element to be created, a list of strings which become classes and an object to map out the attributes - all in 13 lines!).

Okay, now I could draw a path with hardcoded points using JavaScript and animate it!

Day 4

I faced another problem. The current setup would allow me for only one level. But I planned to have several. So I ripped out the level path from the HTML and moved it into JavaScript, thereby reusing code I used to draw the light beam.

This had the downside to use absolute coordinates, but it liberated me from the characters used in a SVG path definition. I could easily tweak the points as a list of list of x and y numbers.

One iteration further, the level definition as JSON. This way, I could utilise IPFS if times permit. However, since I haven’t used that before, I put it on the backburner and declared it a stretchgoal, that would allow me to participate in an additional category.

Last thing I did was to break up the code into smaller ES modules, since I like small files and esbuild did not produce bloat like WebPack would 💖

Day5

I have a tendency to OCD I think. At least, the M is now perfectly mirrored.

Also, this day I only broke out functions into more files to keep them focussed. This meant to move code around.

Since there is math in this game, I created a directory with helper functions for linear algebra and geometry. Namely functions to compute the intercept with y axis and the slope of a line.

A line would be a pair of intercept and slope going forward. The other primitive were points - a list of x and y coordinate.

I also started to think how I would compute the point where the light hit a level wall. This topic would keep me busy for way too long :-(

Day 6

I realised, that the current approach got me stuck in a dead end.

It was too much to keep in working memory. So I needed tests to help me out.

I tried Jest first. But that didn’t play well with ES modules somehow. At least without Babel, which would again blow up things.

So I switched to Ava and tested all my math helpers.

I also was able to curry a function to allow for evaluation of a line once I passed in its slope and intercept. That’s actually cool as I now only have to recompute the new pair for a bounced light beam and could then quickly evaluate the crossing points.

Turning my project into ES modules meant, I had to rename the server files to make them being interpreted as CommonJS modules.

Computing crosspoints and reflections meant handling lots of edge cases. Here, I was happy to write tests! That would have been a mess.

I mean, conceptually it’s easy. Incoming angle = outgoing angle. But I would have to transform my coordinate system all the time … In the end I utilised a geometric motivation as shortcut after crunching about this the whole weekend … (that’s perfectly normal behaviour, right?!)

Day 7

Okay, having a M level is all good. But it was a bit too challenging. Let’s go with something easier. An I!

That was quickly described and introduced.

I also updated the game title to something more custom. This also meant updating the README, since now I had a clearer picture of what I was aiming for.

Over the weekend I thought about how to allow the player to interact with the game. Namely having a slider to drag and a button to commit the change. Something like Pocket Tanks. Should be intuitive enough.

Because it’s possible, the favicon updates on every move, too. (We can SVG there!) If time permits, I wanted to offer a way to download the current level with the beam as PNG.

Since I was still bundling HTML with esbuild, I had to clean up my dist directory before I generated a new game locally.

Day 8

My previous experience made me realise, that sharing on Twitter can drive up engagement rate. 🤷 So to get that out of the way, I implemented a function to dynamically create a share link using the Twitter Intent API.

Since my game was more about Research&Development, pointing to GitHub repo made sense also.

The slider also became able to influence the angle on which the beam was emitted. To keep testing effort low, I limited the number of options.

Also, I had to do some conversions of coordinate systems (Cartesian to Polar). That made me think of allowing the game to use the Web Audio API to orient in the game.

Inspired by VoiceOver’s Audiograms and Steve Saylor’s video (Go watch this!). I could use gain and pitch here.

Day 9

My workday kept me busy, so I was only able to reorganise my level description files. Basically, instead of having one file per level, I kept everything in one JSON. This would also allow me to define the starting position. Having attended his talk, I looked into iPuzzler, but the iPuz format was still not what I could imagine right away.

Instead of bundling the HTML file, I merely copy it now.

Day 10

No update 😿

Day 11

Since I was having multiple levels, I needed a way to allow for switching between them. Be it only for demo purposes (instead of transitioning from one to the other).

So I put a navigation bar at the top - and realised that my GitHub label collided with it on mobile. So I pushed that into the bottom corner.

Speaking of mobile, I noticed, that I forgot to add the viewport meta element (as always …). The share button should also only appear once a level was complete, so I removed the hardcoded href and hid the element until it was assigned something.

It’s so helpful to test on multiple devices!

Day 12

Enough bikeshedding!

Okay … perhaps a tiny bit on optimising the Twitter share function.

From last year’s edition, I also knew that I would have to upload a ZIP archive, so I copied the command for that over.

Since I had two levels, I finally moved the start position into the level description file. As constraint, it always points upwards. It also received a field for its name and end position (a bar).

New levels O and R got added. The start position became a triangle. I felt equilateral looks best, but feedback will make me change that into an isosceles one.

I also minified the HTML and added a normalize stylesheet.

Testing it out made me realise the favicon is hard to see, so the level became a solid background (I forgot to assign the whole document one 🤦)

Having only one line is boring. But computing the bounced angle turned out to be … difficult. It kept me busy for the rest of the day!

Day 13

I got it! I realised, where I had a bug in my logic. But I ran out of time.

Basically, I compute the crosspoints of the current line with all walls and pick the smallest one that is different from 0 (after rounding). That … introduced another bug, since the light now jumps walls if the gap is smaller than the next wall I meant to hit 🤦

But it was submission day, so I had to run with that. I decided to add it to the game description page and call it a day.

What went well

My game was playable (hey, that is a progress!).

I managed to cut features early on to not get overwhelmed.

I was able to develop a small bit on almost every day.

What could have been better

I always try to get my game out as fast as possible. Because making it playable is the most crucial thing.

I also normally spent way too much time to think on ideas, so I lack the implementation time. Thus, I went with the first idea that came to my mind.

I might pivot the game more towards generative art. That resonated with certain people.

Also, the level description files should have some way to allow for more path options than line-to-line.

Conclusion

See you next year! (Or earlier, if you’re taking part at js13kgames).

If you made it this far, thank you for reading.

Comments

Log in with itch.io to leave a comment.

Very interesting read, though it's a bit more technical than my puny brain can comprehend! :) Good luck in the future!