Dirty Hacks

Posted by marbs on June 24, 2013, 5:31 p.m.

Sometimes you just have to get code working, regardless of how pretty it is. This is especially true for game developers, since you generally want a playable prototype as fast as possible.

I find this quite difficult sometimes. My progress gets bogged down by planning for the future, by writing clean and modular code, or by finding the optimal solution for everything.

Perhaps my engineering degree created this desire for perfection? I don't think so. Code written by my lecturers was almost always very messy, with sloppy indentation and inconsistent braces. (At least it wasn't as bad those ancient hieroglyphics they call handwriting.)

So do I write perfect code? Definitely not! Looking back at code I wrote months ago, weeks ago, or sometimes even just seconds ago, I spot things I would do differently. Why is this? That answer could take up a whole other blog post.

What I want to show you is this level editor I've been working on:

Above is a cubic bezier curve.

The black shapes can be moved to manipulate the curve. The squares indicate end points (where the terrain begins and ends), while the circles represent control nodes (used to manipulate the shape of the curve.)

It was surprisingly easy to implement, taking only a few hours. Feeling confident, I decided to add circular arcs as well. After all, surely arcs would be super easy in comparison?

Above is a circular arc. It turned out to be terrifically hard to implement, and took, on and off, about three days to get working.

I found it very irritating because, at the outset, it seemed like such a simple thing to do! The user places three points; two squares and one circle; then the arc then just has to pass from one square, through the circle, to the other square. For any three given points there exists a circle that passes through, so it is just a matter of determining this circle, and taking only a section of it - the arc.

The first bit I could do - determining the circle - that was a simple wikipedia job. It was the second part that stumped me.

I managed to isolate the problem down to a couple of things. Part of the it was this: my algorithm incorrectly calculated the angle that passes from one square, through the circle, to the other square.

In the above image, the correct solution is the yellow angle. However, my calculation would always return the shortest angle, so it never worked for a reflex arc. I spent a while trying to find a mathematical solution to this, but hours passed and no progress was made.

Through experimentation, I found that by manually adjusting a couple of boolean parameters of the arc generation code I could always create the correct arc! The parameters controlled a couple of things: whether to flip the arc direction, and whether to subtract its angle from 360 degrees.

And so I arrived at my solution: brute force!

Given that one combination of the aforementioned two boolean parameters always led to the solution, this meant that only 4 possible combinations exist. So I stuck the arc generation code inside a loop which tries all 4 combinations and returns only the correct one. It works flawlessly!

Is this solution sub-optimal and terribly ugly? Yes; but that's not important! What really matters is now I can move on to making it playable, and find out whether the game is fun.

For similar tales, read the Gamasutra article on Dirty Game Development Tricks. My favourite one of those is where the programmer exploits a buffer overflow to patch his own game. Oh, and also the one where they store audio data within a 3D model.

What dirty hacks and programming sins have you committed in order to get things done?

Comments

LAR Games 10 years, 9 months ago

You know, even though I'm probably the worst GML programmer on this site, I can relate to your problem completely.

That's exactly what happens when I'm writing code for my games.

"Hmm. well, I could do it this way, but what If I want to add more of that later. Better rewrite everything to support that.".

Then I run into a wall, and give up. (Until I figure out something new, then the process starts again.)

Quietus 10 years, 9 months ago

math turns me on.

Quote:
Dirty Hacks

(i have nothing to add, i just like generated stuff like this. looks awesome!)

marbs 10 years, 9 months ago

Quote:
"Hmm. well, I could do it this way, but what If I want to add more of that later. Better rewrite everything to support that."
Haha yeah, that's pretty much it. Thinking about it, I felt a similar way about writing until I did NaNoWriMo. It forced me to just get stuff done, and worry about making it good later. I think it is a bit different with programming though, because a bit of appropriate foresight can save a lot of work later on. Getting the balance right can be tricky.

Eva unit-01 10 years, 9 months ago

Love the blog, and that feeling when you finally get something working after so much trial and error and different methods? It's just the best.

As for this–

"What dirty hacks and programming sins have you committed in order to get things done?"

Everything under the sun, since I was never a programmer, though I knew a nice amount of GML. I thought of code more in a 'logical' sense like for example, some old comments on a highscore code I wrote for my last game.

/*

The first place score should always be higher than both 2nd and 3rd place.

The second place score should always be higher than the 3rd place, and always lower than 1st place.

The third place socre should always be lower than both 1st and 2nd place and so on.

This script handles as many places as you want, or as few as you want. Just copy this

and place it under the first score, and etc.

*/

And it gets a lot messier than that haha. Yet it worked flawlessly.

Cesque 10 years, 9 months ago

Quote:
(At least it wasn't as bad those ancient hieroglyphics they call handwriting.)

Hey, that reminds me of the story of a guy who tried a handwritten MySQL Injection when filling out a voting ballot in some Scandinavian country (can't find a reference to it now… I swear, I tried googling it for like 3 seconds to no effect).

Quote:
And so I arrived at my solution: brute force!

Bah. Just call it an "evolutionary algorithm".

Quote:
What dirty hacks and programming sins have you committed in order to get things done?

Okay, brace yourself for this one… I routinely use Regex to read XML.

JuurianChi 10 years, 9 months ago

Quote:
What dirty hacks and programming sins have you committed in order to get things done?

I base a number of my CSS designs on http://www.getskeleton.com/

:<

F1ak3r 10 years, 9 months ago

Quote: Cesque
Okay, brace yourself for this one… I routinely use Regex to read XML.
XML is at this perfect midpoint between computer parsability and human readability where it's terrible for both.

Mega 10 years, 9 months ago

Quote:
What dirty hacks and programming sins have you committed in order to get things done?
Until recently, all of my file IO code relied on the archaic io.h, and used a ridiculous method for getting the size of the file being read.

Also, I can quite honestly say that most of my 'complete' projects are hacks, through and through.

aeron 10 years, 9 months ago

Nice level editing features! How hard is it to alter the resolution of the curves? Also yeah don't be ashamed of having to resort to dirty hacks, sometimes it just isn't worth the time to work out the best way and just go with what works.

marbs 10 years, 9 months ago

Quote: Cesque
I routinely use Regex to read XML.
Blasphemy!

Quote: aeron
How hard is it to alter the resolution of the curves?
Within the editor I made it very easy to change the curve resolution, and it can actually be done dynamically, which is pretty cool to see.

At the top level, the user specifies curve resolution in terms of the segment length (with each straight line in the curve being considered a segment). The underlying algorithm will then attempt to generate a curve with segments as close to the specified length as possible. In this way I can have huge curves and tiny curves both with segments that are almost congruent.

At the bottom level, the curve generator needs to know how many segments to generate. I therefore have algorithms that translate the desired segment length into the desired number of segments, which is done by dividing the curve length by the desired segment length, and rounding the result.

Calculating the exact circular arc length is simple, but calculating the exact cubic bezier curve length is not so simple! So again, applying what could be considered a dirty hack, I just opted to estimate the bezier curve length. This is done by generating a high-ish resolution curve with 100 segments, and adding up the length of all these segments.