Tails

Overview

This game was my submission to Mini Jam 176: Foxes, a 72-hour game jam. This jam was fox themed with the limitation requiring that you flip a coin as a mechanic. After brainstorming a couple of ideas, I settled on a puzzle platformer where the player flips a coin when they jump to see if they will jump or not. The result of the coin flip also influences the behavior of platforms and obstacles, transitioning them between binary states. I implemented two platform transition types: one that alternates between two positions and one that fades in and out of existence.

What I Learned

Player Movement Controller

In 2D platforming games, a well-made movement controller is one of the most important elements. With that in mind, I researched what elements were important when creating a movement controller so I could implement them in my game. I began with the lateral movement building on top of Unity’s dynamic rigidbody physics simulation. The controller applies a force to the character that is influenced by whether the player is accelerating or decelerating and the difference between the current speed and the target speed. The end result is a responsive feeling controller with good directional control but still a slight “slippery” feel to match the icy environment. For the jump, the controller adds an upward impulse force to the character and increases gravity at the peak of the jump to add a “snappy” feel. A small Coyote Time and Jump Buffer window were also added to reduce player frustration.

Pixel-Perfect Camera

I have created pixel art games in the past and noticed some strange artifacts when using a normal camera on a low pixel count. In order to fix that this time around, I used Unity’s pixel-perfect camera. This locks the camera to a predetermined pixel resolution (640x360 in this case) and limits camera movement increments to a pixel width. The new camera prevented blurry sprites and other artifacts, but does appear somewhat choppy when sprites are moving slowly since they are “jumping” from one pixel to the next. In the end I decided this tradeoff was acceptable for a game jam, but in the future I would look into other potential solutions such as upscaling.

Events

The Observer Pattern is a development practice used to reduce coupling that I was familiar with in theory but hadn’t had much practice implementing. This game provided a great opportunity to practice it since I had platforms (observers) that needed to execute behavior when the coin (subject) changed states. I utilized C# events in an EventManager script that invokes the event when the coin state changes. I then created a parent class called FlipActor that subscribes/unsubscribes on enable/disable and defines a virtual function FlipAction that its children must implement. Now, I could create classes like MovingPlatform or DisappearingPlatform without worrying about subscribing/unsubscribing and just override FlipAction.

Reflection

Once the jam voting concluded, I did some reflecting on the game concept and implementation. I placed 30th, and the feedback I received the most was that the game was pretty difficult, making it less enjoyable for most players. I failed to notice the increased difficulty because of my familiarity and practice with 2D platformers as a whole, along with my familiarity with the movement in the jam game from testing my implementation. The game concept itself has a fundamental flaw: you need to get lucky to progress. I was aware of this issue pretty early in development and my primary solution was adding jump pads and one-way platforms. I hoped this would alleviate frustration by guaranteeing jumps at certain locations and allow for level design that makes jumping a one-way path to a higher platform you can not get down from, adding some strategic depth. Unfortunately, I was unable to implement these features within the jam timeframe. While these solutions might reduce frustration, they are essentially removing the need to use the jump chance mechanic instead of fixing it. Ultimately I concluded that the jump mechanic was too essential to constrain to a random coin-flip. There are still potential fixes, such as making the coin flip skill-based instead of random, but as-is, the concept isn’t worth pursuing further.