Project · 2025
Parachute Panic
A Unity remake of the Game & Watch classic, refactored for code craft, with a persistent JSON highscore system.
Tags
- Unity
- C#
- Gameplay
- Design
Overview
Parachute Panic is my Unity take on Nintendo’s 1981 Game & Watch Parachute, rebuilt from an earlier Processing version. I kept working on it because I still had to retake it, and because it overlapped well with the Git Gud module: the codebase needed improvement in nearly every aspect.
In my version the emphasis lies less on catching parachutists and more on dodging obstacles. The player earns or loses points depending on their actions, which makes for a more active, risk-driven loop that serves the goal of the game: reaching the highest highscore.
My own addition is a highscore system: the ten best scores, with player names, are stored locally and shown in the UI. It has its own breakdown: Highscore System.
This iteration focused on:
- Improving code quality and structure
- Processing peer feedback and playtests
- Extending the old highscore system
Design
Core design choices
To make the gameplay more manageable I adjusted the spawn intervals and capped the maximum number of lives, balancing challenge and playability.
The scoring system was reworked to encourage active play: players are rewarded for interacting and less for playing passively. This stops players from “beating” the game without taking any real risk.
The original only had three positions (left, middle, right). For a modern version I wanted a movement range wide enough for the player sprite to fit across it about five times.
Art & sound
The visual style is inspired by retro arcade games, with pixel art and simple colors for clear readability. I looked up Game & Watch sprite sheets and gave a few sprites a custom outline in Aseprite. The highscore screen draws on old-school arcade leaderboards.
For audio I chose an arcade-inspired style, with sound effects that give clear feedback on positive and negative interactions. The music is deliberately calmer outside of gameplay, for contrast and to prevent overstimulation.
Development
My process was split into three phases, with a “get it working first, clean it up after” mentality.
Phase 1: Functional base
I focused on getting the core gameplay working. My earlier Processing version served as a reference to see what already worked, and for the rest I searched for comparable YouTube tutorials on arcade games, such as “Space Invaders in Unity”.
The first peer review (27 Oct 2025) was still useful, even though I barely had a working game to review. It was about the structure of my project in the editor, and how easy or hard it was to find and change things in the inspector.
The feedback mostly targeted code quality: readability, consistency, and reducing needless complexity. The full review is longer and also covered the player, lives, score and menu scripts.
Peer review, 27 Oct 2025 (translated)
IN EDITOR:
- Unclear which scene to play
- Movement speed is changeable, but unclear what it all changes
- Cluster speed can't be changed?
- Cluster amount isn't clearly indicated, so I assume not
- Cluster interval and obstacle interval can be changed
- Health can be changed
- Attack speed can be changed, but in the bullet, not the player
- Miss punishment doesn't work and physics aren't accurate
- Unclear which ones to catch and which not
- Red doesn't explain enough
IN SCRIPT:
- Easily adjustable: change 1 line in the function
and add some code comments for visibility
- But the points system must be converted:
if you catch the white one, you now lose pointsPhase 2: Improve & extend
With the basics in place, the biggest question was how good or bad my codebase objectively looked. I asked a second-year student to review my code, since I had missed this kind of feedback earlier.
Code review, 9 Feb 2026: Cluster.cs
- Move the bounds into a separate variable instead of using them inline
- Remove unnecessary comments (“basically the function…”)
sealedis the opposite ofabstractand could be considered here- Replace magic numbers with constants or readonly variables, like
randomSpeedRangeorclusterAmount - Let the for-loop use
clusterAmount InitiateCluster()can useRandom.Rangewith variables instead of fixed values
ClusterSpawner.cs
- Hungarian notation isn’t necessarily wrong, but consistency matters
- Naming can be more abstract
- The empty for-loop in
Awake()can go - Replace magic numbers with min/max variables
Phase 3: Cleanup
Over the course of the assignments, the feedback visibly changed. It went from many remarks about the code to “the code is clear, just watch X and Y”. To me that confirmed the code was improving each iteration, as the remaining feedback focused on everything around it: gameplay, user experience, and how bad practices could be handled differently or better.
Conventions
I used a mix of Unity’s conventions and the course guidelines. The ones I stuck to most:
- English as the language of choice
- PascalCase and camelCase, following the engine and language conventions
- Opening curly bracket on the next line
- Local variables at the top of a function, where possible
- Group things that belong together without whitespace, and separate things that don’t with a single blank line
- Declaration order: public / protected / private, member variables before functions, engine hooks (
Start,Update) before custom functions, functions in order of appearance - Always include access modifiers
Git workflow
Looking back, I never did intermediate merges and kept branching further, roughly one branch per assignment:
- Pre Git Gud: main branch
- Code Refactor: develop branch
- First Playable: leaderboard branch
- Second Iteration: leaderboard branch
- Final Assignment: score systems branch
For the retake, the relevant branch is retake.
Everything else is either a failed attempt at a mechanic or version control for the intermediate assignments.
Technical insights
Syntax sugar was an important concept for readability.
Shortening a declaration like the one on the right works just as well, and var helps too, as long as the type stays clear from context.
Generics (<T>) were new to me.
Applying them in the highscore system gave me better insight into how data can be stored flexibly and reusably.
Getters and setters clicked when I split responsibilities between classes: a private setter keeps the data encapsulated.
// before
private List<HighscoreElement> highscoreList = new List<HighscoreElement>();
// after
private List<HighscoreElement> highscoreList = new();Delegates, Actions and UnityEvents.
I deliberately chose not to write custom UnityEvents, because they are less transparent: you have to go to the editor to see what something does.
With Actions and delegates you can read directly which arguments are expected and passed along, and what the intent is, for example from an action named OnDeath.
That made the code more readable and easier to debug.
I used this for the highscore system’s event flow, which is covered in its own breakdown.
Feedback
Based on peer, playtest and teacher feedback I improved the project on both gameplay and code level.
Gameplay & balancing
- Too forgiving, not punishing enough → bomb penalty raised to -10 → mistakes have direct impact, so weighing risk matters more
- Score could be farmed by ignoring objects → parachutes +7, power-ups +3 → active play is rewarded, passive play discouraged
- Too much visual noise → spawn intervals increased → better readability, less cognitive overload
- Unclear which objects to catch → colors, sprites and a title screen explanation improved → faster onboarding
- Physics felt inaccurate → tuned, but deliberately left slightly unstable → more challenge without full control
UI & UX
- Unclear UI flow → restart and menu functionality added
- Duplicate highscore entries → intermediate
EnterName()step → score is saved only after input - Wish to see highscores outside Game Over → highscore button reused in the main menu
Code quality & refactoring
- Magic numbers → replaced by variables → more readable, easier to tune
- Needlessly complex or unreadable code → naming improved, unnecessary comments removed
- Unclear inspector variables → renamed and documented → better usability for designers
- Direct dependencies between systems, like the ScoreManager → deliberately kept, but I gained insight into event-driven alternatives
GameObject.Find()is strongly discouraged → usage minimized, direct references instead
Feedback played a central role in improving the project step by step. Technical feedback in particular, like using events and reducing coupling, gave me a better understanding of scalable software architecture, which is valuable for future projects.
Takeaway
I grew a lot in independence as a developer. Where I used to struggle with basics like loops and leaned heavily on external help, I can now write working, thoughtful code on my own.
The key insight was the difference between code that “works” and code that is also readable, maintainable and future-proof. Refactoring and processing feedback made me think more consciously about structure, naming and responsibility. Trying things myself before reaching for ready-made solutions strengthened my confidence in my own problem solving.
On the design side I learned that visual presentation and feedback play a big role in motivation, for the player and for me as a developer.
If I started over, I would begin with a simple, well-structured base, like a minimal scene, and expand iteratively. I would also think about architecture and system structure earlier, to limit unnecessary refactors.
Final Feedback
J. should revise this when writing the actual page.
Resources
- Reference: Game & Watch Parachute (YouTube)
- Let’s Make An Arcade Game Like Space Invaders! (Night Run Studio)
- Point Counter & High Scores (Velvary)