The Unbeatable Squirrel Girl #20
Click Start, then use the arrow keys on your keyboard to move Squirrel Girl around the pyramid! ~CLICK SEE INSIDE TO REMIX THE GAME~
Squirrel Girl is secretly also computer science student Doreen Green, shh, don't tell!
Inspired by the cover of The Unbeatable Squirrel Girl #20, by Ryan North, Erica Henderson, Rico Renzi. (And of course by classic arcade game Q*Bert, by Warren Davis and Jeff Lee.)
Scroll down for more notes and credits, or see http://www.techknight.com/ for my other projects
-- Artwork --
Using Erica's amazing art as a starting point, I isolated each element in Photoshop and painted over top with a flattened colour palette. This was necessary because digital comics have some JPEG artifacts, which make them tough to simply cut & paste into sprites. (Which is fair! That use-case is not normally considered when tuning compression vs file size.)
Creating the sprite for Squirrel Girl, she was too tall so I had to remove her shins (sorry Doreen!) and make kind of a chibi version that also brought the tail in a bit.
For her jump, I preserved the blockiness by rotating one leg 90 degrees, and sliding sections of the other in progressively wider chunks.
-- Sound --
All of the sounds come from Q*Bert, and were sourced partly from Twisty's MAME Samples Collection, and partly from Basement Arcade Classics.
-- Game Design --
Scratch and Squirrel Girl comics are both new user-friendly, so I tried to keep that kind of accessibility in mind in terms of both playing and modifying. Players should be able to add new enemies, levels, and rules with minimal effort.
1. Q*Bert is not as well-known as other classic games of the era, so there is extra difficulty in communicating its unconventional controls to players.
2. Scratch's system for in-line commenting is clunky, so the source code has to be fairly readable as-is to be effective
3. Q*Bert originally played in a vertical orientation, on a 7-row pyramid. Fitting everything into 6 rows in Scratch keeping Erica's rad art readable is tough.
-- Technical Decisions --
I prefer using two arrow keys for diagonal movement, but that's confusing to the largest number of players. So the default controls pretend to rotate the arrow keys and take only one keypress to move. They can be changed to my face method by setting DoControls to 2 instead of 1.
The cubes of the pyramid are identical except for their CubeNum ID number (with a slight exception for Cube1), but exist as individual sprites instead of as clones. There are ways to give unique IDs to clones through a generation process, but it felt like it would make the project more complex to modify. There is also (afaik) no way to programmatically manage the deletion of clones, which can complicate their life cycles when restarting a game.
To create the pyramid layout, I made note of the pixel width and height, and created a rough layout in Excel. One pyramid of cells to indicate the cube ID number, and another pyramid of cells below to record the corresponding x/y starting points.
Those x/y starting points are contained in the CubeStartX and CubeStartY lists, and are referenced by way of CubeNum.
The player has a PlayerCubeNum to indicate which cube she is standing on, and the position of the player is derived by accessing the corresponding cube coordinates and just adding a Y offset to the player sprite Y position, to make her stand on top of the cubes.
To find the next cube that a player is moving to, I created four lists: UL, UR, DL, DR. If you take the player's current position PlayerCube, you can use that to look up which cube number they would be moving to in a specific direction. So, for example, if the player is on cube number 1, and the keys they press indicate that they are trying to move down-left, we look up DL(PlayerCube) and receive cube 3 as a result. If the player was moving up-right, we'd look up PlayerCube in list UR, and receive -1, which indicates that the player should fall off the pyramid.
In moving the player from one cube to the next, I tried to recreate the feel of jumping in Q*Bert as simply as possible in two glide motions. (And a slight change when jumping up vs down.)
Just like my decision with the cubes, using clones for the rats didn't quite gel with how I had things in mind. I experimented with a cloning system that added new variables for RatStartingPosition etc, but it just made the whole thing more complex than I wanted. In the end, I set the rats as two individual sprites with some local variables. Rat2 is twice as fast as Rat1.
Collision checking could be tightened up a bit… But it would mean having to make the code more complicated, at the expense of ease-of-modding. I kind of wish that I'd based Doreen's win dance animation on the large sprite from the Ouch event so that it looked cooler. The layer stuff isn't perfect: there are some cases where jumping enemies and Doreen crossing up/down between heights could be in the wrong Z-order. I started working on a solution but it would've hurt readability too much.