Part two of a series in which I got back and examine old github projects. Today’s victim is PusheenScreensaver.
PusheenScreensaver was a class project for my 2D Graphics class. It features our furry friend, Pusheen, strolling back and forth along the bottom of the screen. Every once in a while she will take some action, or change direction. If she bumps into the side of the screen, she turns around. I was so proud of it I gave it as a gift to my girlfriend at the time. For a while we both used it, but after we broke up I got rid of it :/
The code, however, remains!
I remove it. The code continues to run.
I find my choice of breaking out the framing to a separate class strange. I could have moved the
main method into
Pusheen.java and it wouldn’t have changed anything.
I do so. The code continues to run. We are down to two classes. I rewrite the readme.
I’m also not sure why I made
c a global static variable. I move it into the
I, at one point, apparently ran into a windows bug where I had to keep track of every mouse movement in some global variable.
Why didn’t I use brackets around
Did I think I was cool or something?
Dear god, why??
I hope my readers can forgive me.
My ex actually found an interesting bug in the code after years of usage. Pusheen can obviously only move across the screen a fixed number of pixels at a time, but when I tested it I felt like moving one pixel at a time was too slow, and two pixels at a time was too fast. What I ended up doing was making
speed a double, and setting it to
1.2. I also made
pos (the position) a float, and when I rendered Pusheen to the screen I would just cast the
pos double to an int. This meant that in practice, Pusheen moved forward one pixel at a time, but every 5 frames moved forward two pixels, making her appear to have a speed of 1.2 pixels pre frame.
Now here’s where it starts getting tricky.
pos is a double, but when I render Pusheen I cast it to an int. So, I reasoned, when I check if Pusheen is about to go out of bounds, I should cast it to an int. This means that if, for example, the width of the screen is 100,
speed = 1.2 as previously discussed, and
pos = 99.7, I will check that
(int)(pos + speed) > width, which will be false, since
(int)(99.7 + 1.2) > 100 => (int)(100.9) > 100 => 100 > 100 => False. So I will allow the update to happen, and now
pos becomes 100.9 . We render the scene and everything is fine. Now jump through the
updateVars method again. This time, it just so happens that while Pusheen is out here at the edge of her world, the
flipChance random double happens to be generated below the
flipThreshold, and the global
flipped variable is set to
true, meaning that Pusheen is now going to be traversing back across the screen. But! But we continue into the ‘off the screen’ check.
(int)(100.9 + 1.2) > 100 => True, so we negate the
flipped variable again. And because I, when I coded this, assumed that
flipped would always be in the correct state, I didn’t have any checks to make sure that
flipped was becoming
true, I just set
flipped = !flipped; Now we once again add 1.2 to
false) and now
pos = 102.1. Go through
updateVars again, the ‘off the screen’ branch is triggered,
flipped gets set to
true, but it’s too late! We subtract
pos to get
100.9, we render Pusheen facing the opposite direction, and on the next
updateVars we negate
flipped, add 1.2 to
pos, and render Pusheen flipped again. Pusheen now gets stuck flipping back and forth at the very edge of the screen.
This bug has a very low chance of happening. The flip threshold is
.008, so only one of about every hundred frames does Pusheen flip. Pusheen needs to flip while she happens to have a
pos that is greater than the width of the screen, but less than the width of the screen plus one. This bug is so rare I never once encountered it, but my ex used it for long enough that she happened to run into it.
It was still poorly written code though. I was thinking about how if I did this again I wouldn’t use any mutable state - I’d try and do it in a very functional way. I don’t think it would be all that hard to recreate this in elm (but then it wouldn’t be a screensaver!)