Pusheen Screensaver
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!
We start with a look at the Screensaver class, which has the main
method. Immediately, the first line confuses me. System.gc()
?? Why???
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 main
method.
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 if
statements?
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 pos
(since flipped
is 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 1.2
from 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!)