I am satisfied with what I was able to do with HEIST! and I'm happy with how most of the game turned out. However, there was a lot of things I couldn't do or spend more time on due to many reasons, but mostly due to the difficult time constraints I was under. Below, I will discuss what went well with my game, and then I will go over all the features I wanted to add and things I would've liked to change if I had more time.
Here's how it works in the final build of the game:
1. Dash Input
When the player presses the "dash" button (Input.is_action_just_pressed("dash")), if they're on the ground or have an available air dash, the player transitions into the State.DASHING state.
2. During Dash
In process_dash(), horizontal velocity is set sharply (velocity.x = max_dash_speed * direction) with some gradual deceleration (lerp toward 0).
If the player presses "slide" during the dash and is on the ground, it transitions immediately to the slide state (State.SLIDING).
3. Slide State and Setup for Jump
Upon entering State.SLIDING, your character:
Shrinks its hitbox (capsule_shape.height and .radius),
Sets a minimum speed for the slide,
Gets extended coyote time (makes jumping easier at the end of the slide),
Begins a timer (slide_time_remaining) for how long the slide lasts.
4. Perfect DSJ Timing
If the player jumps at the very end of a slide (slide_time_remaining < threshold) and coyote time > 0, a Perfect Dash Slide Jump is triggered:
You boost the jump vertically and add extra horizontal velocity (slide_jump_boost * 200!),
You flag perfect_dsj = true,
You set boosted_jump_active = true to allow more freedom in horizontal speed,
You visually highlight this jump with ghost trails that glow and pulse in bright blue:
highlight_ghosts(perfect_dsj_color * (0.5 + 0.5 * sin(pulse_time)))
5. Ghost Trail VFX
While velocity is high (abs(velocity.x) >= 250), a ghost sprite spawns every 0.05 seconds, creating a cool speed trail.
During a perfect DSJ, the ghost trail glows and pulses, adding polish and feedback to the move.
I'm honestly super happy with how the dash slide jump turned out. The timing window feels just right, it's tight enough to be rewarding, but fair enough that with a bit of practice, you can consistently pull it off. That moment when you jump right at the end of a slide and feel that velocity carry you across a gap, it just clicks. On top of that, chaining DSJs to traverse levels as fast as possible is super satisfying and it feels so rewarding beating your previous high score by perfectly timing the mechanics.
Additionally, the extra boost on a perfect DSJ makes it feel so satisfying, especially when you catch that perfect timing and the ghost trail flares up in bright blue. It's the kind of mechanic that feels almost expressive, like the player is doing something special, not just pressing jump again. It turned out really well and although it isn't quite perfect, I'd say it's pretty close.
Building this felt awesome. Every piece came together logically, the UI updates in real-time and looks polished, saving and loading is smooth and efficient and it’s super modular and easy to expand. It's rewarding to finally have a system that’s not only functional but also something I’m genuinely proud of. I can see this being the backbone for some cool speedrun features, maybe even global leaderboards one day if I decide to continue working on HEIST!. Watching it tick down as I try to beat my last run is weirdly motivating, and I love that feeling. All in all, this timer is simple but powerful, and I’m really happy with how it turned out.
One of the main things I’m really happy is the leaderboard system. It tracks the best run times for both levels, and while it started as a small feature, it quickly became something that added a lot more to the overall experience. It gives players a reason to replay, improve, and challenge themselves beyond just reaching the end of a level.
From the beginning, I knew I wanted to make the game feel good for speedrunners or players who like shaving seconds off their time. That mindset shaped how the leaderboard came together. I didn’t want anything overly complex, no external databases or anything like that, just a lightweight, local system that works well and feels integrated into the game’s world. I knew online global leaderboards was way out of my reach for this project so I am perfectly happy with the local system I created.
The system runs through the speedrun_timer.gd script, which handles everything from tracking time during a run to saving the results. The time is displayed in minutes, seconds, and milliseconds, which gives it that satisfying precision players want when going for a personal best. When the player finishes a run in level 1 or 2, the time is automatically saved, sorted, and stored in a simple text file. Only the top 10 times are kept, which keeps the list meaningful and clean.
I also added functions to load and clear run times easily. This helped a lot during testing. The way it’s all tied into game_manager.gd means the timer knows when to appear or reset depending on the level, so everything feels smooth and responsive.
What really worked was how natural it feels in the flow of gameplay. You don’t have to do anything extra, it just works in the background, keeping track without interrupting the experience. The use of Godot’s built-in file system made the saving and loading simple, but also very stable.
What I’m especially proud of is how the leaderboard changes how players interact with the game. Instead of just completing a level and moving on, now they have a reason to replay and improve. It turns levels into something more competitive, even if it’s just against yourself.
I am very happy with the music I made for HEIST!, particularly the main menu track. When planning I knew I wanted jazz music to be a big part of the game as I am a huge fan of jazz and I love it in games when done properly. However, I am no musician and I seriously underestimated how difficult it would be to create jazz music from scratch. That being said, I think I did a pretty good job with the music for my game. The tutorial/cutscene music fit perfectly as it was subtle and sneaky. I can imagine the crew listening to the song as they planned this all out. The level track whilst being my least favourite of the three, still fit quite well and I am a huge fan of the crazy drum sections I managed to create, it sounds so cool and although it isn't exactly perfect for the game, it still sounds good as it's own track and serves it's purpose nicely as a level track. Lastly, the main menu track is so perfect, it sounds like lift music in the best way possible, it's fun and relaxing whilst sounding fitting for the game; I couldn't be more happy with it.
Considering my lack of music theory knowledge and experience making music outside of this course, I think what I achieved is quite impressive, it's not amazing but it definitely isn't the worst music I've ever heard or made. It fits the game, it doesn't annoy me and all things considered, I think it turned out quite well.
I spent a large amount of time making art for this game. I chose art at GSCE level and managed to get an A, and I used to draw a lot growing up so I felt quite confident going into making art for the game. Animating on the other hand, was quite new to me and definitely posed a real challenge to me. As you could see in my prototype I made a simple black and white guy do the basic animations I wanted my player to have which wasn't too bad and a small minority of testers even preferred that to the final character. This placeholder character was okay and it was helpful to make the final character animations. Looking at the final sprite sheet now, I'm honestly very happy with the result. It's consistent and expressive whilst fitting the simple, rustic pixel art style. Most of the testers agreed it looked great and gave the game a polished, finished feel. I also learned how important it is to break animations down into manageable pieces: walk, jump, fall, attack, crouch, rather than trying to perfect everything at once. That structure helped me not get overwhelmed, especially as someone new to animation.
Beyond being aesthetically pleasing, the art works well to differentiate the player from the rest of the world, I achieved this by giving each level a distinct colour theme so that the player can easily grasp what are world elements and what they're in control of, it seems like such a minute thing but it really was a purposeful decision I made specifically for this reason.
Overall, the experience made me appreciate how much work goes into animated characters, especially in pixel art. It’s one thing to draw a character standing still, and a whole other challenge to bring them to life. Despite the difficulty, I’m really proud of pushing through it. I think the final character gives the game a lot of personality and feels like a real part of the world I built.
The bank heist level would have been packed with decorations like vault doors, piles of gold bars and cash, broken glass, security cameras (some working, some broken), red flashing alarms, and a lot of dynamic lighting effects: strong spotlights, laser glows, and flickering lights to really sell the sense of urgency. The setting was going to feel rich and chaotic, with ornate marble walls and crumbling tiles showing the damage caused during the heist.
Mechanically, this level would’ve introduced new elements like moving vault doors as timed obstacles, laser grids you had to dodge through, pressure plates that triggered traps or opened secret paths, and a final escape sequence, possibly with an auto-scrolling section where the player had to outrun the chaos. Enemies like armed guards and laser drones would’ve added to the pressure, and coins might have been re-skinned as gold bricks or pieces of stolen artwork to fit the theme.
Visually, I was planning a strong colour theme using deep golds, crimson reds, and gunmetal greys. The idea was to create sharp contrast lighting to build tension and make everything feel high-stakes and cinematic.
Even though I didn’t get to build this level, I’m still glad I planned it out because it helped shape the tone and progression of the earlier levels. And who knows, it’s the kind of thing I’d love to revisit in the future, maybe in an expanded version of the game or a sequel if I ever decided to make one. Cutting it was a tough call, but focusing on quality over quantity meant the rest of the game came out more polished and consistent. I think knowing how and when to make calls like these is an incredibly important ability to learn as a game developer especially when you have a deadline. While more content would have helped, the deeper improvement lies in how I would develop. Instead of reactive tweaks, I would adopt A/B testing for movement variables, integrate player telemetry to track fall deaths, and employ qualitative methods like think-aloud protocols during playtests. This represents a shift from intuition-based iteration to structured user research. My aim would be to gather actionable design data early, mirroring the UX-driven workflow seen in many successful indie teams.
I’m still not a huge fan of how the tutorial turned out, even though it technically does its job. It covers all the core movement mechanics - jumping, sliding, dashing, and wall jumping, and for the most part, players pick up those individual actions just fine. But the issue is that it doesn’t go deep enough. One of the most important mechanics in the game is chaining a dash into a slide and then into a jump (the DSJ) - it's something that really defines the flow and momentum of movement later on. The tutorial doesn’t properly teach that, and as a result, a lot of playtesters never discovered it or didn’t realise how important it was to mastering the game. This feedback directly informed my understanding that tutorials should not merely introduce mechanics but progressively guide players through complex chaining and application, preventing the 'difficulty whiplash' observed by testers. This tutorial gap exposed a deeper issue in onboarding design. Effective onboarding doesn’t just teach controls, it guides cognitive mapping and progression scaffolding. The oversight here caused a disconnect between skill introduction and skill expectation. Drawing from learning curve theory and UX heuristics, I would now prototype tutorials as part of the core player loop design, using progressive disclosure and structured rehearsal, ensuring players are prepared not only for what to press - but when and why.
That DSJ mechanic isn’t just a nice trick; it’s critical for navigating the more difficult platforming sections in the first and second level. So when players go from a tutorial that’s very basic and safe straight into a level that expects a much higher level of control, it creates a kind of difficulty whiplash. A lot of people told me they felt out of their depth really quickly, which obviously wasn’t what I was aiming for.
In hindsight, I think the tutorial needed a second half or a challenge section, just something that nudged players to start experimenting and combining moves. Even just one or two more complex obstacles that required chaining dash-slide-jump would have made a big difference. Right now, it’s too gentle and segmented, so it doesn’t prepare players for how demanding the game becomes almost immediately afterward.
I’ve learned that tutorials aren’t just about introducing buttons, they’re about teaching thinking, flow, and confidence. That’s something I’d like to revisit and improve if I ever update the game or work on a follow-up project.
In levels 1 and 2, I placed three coins in each as a subtle way to guide players toward using the dash-slide-jump (DSJ) mechanic properly. The idea was that these coins would be positioned in spots that, at first glance, look unreachable or even like background decoration, but they are reachable if the player has figured out how to chain their movement correctly. It was a way to reward curiosity and skill without forcing anything too directly.
For players who did get it, it worked really well. They’d notice the coin, think “wait, is that even possible?”, and then start experimenting until they figured out the correct technique to reach it. That kind of “aha” moment was exactly what I was hoping to create. But for others, especially those who hadn’t fully grasped the DSJ mechanic due to the tutorial’s limitations, the coins either went unnoticed or were dismissed as unreachable. Some people didn’t realise they were meant to be collectible at all. This direct user feedback highlighted a crucial design principle: optional challenges require immediate and clear feedback loops to be effective and engaging.
I had originally planned to build this out further, maybe have a little UI that showed “0/3 Coins Collected” per level, or maybe even a score or reward system tied to it. But unfortunately, I just ran out of time before I could add those features. The groundwork is there, but without that feedback loop, the coin system ended up being more of a hidden extra than the integrated layer of optional challenge I’d hoped for.
Still, I think it adds something interesting to the levels, even in its limited state. If I had more time, expanding the coin system and giving players clearer motivation and feedback for collecting them would have definitely been a priority.
One thing I definitely didn’t get to finish was the sound design. I only managed to add a sound effect for picking up coins, which does help make those moments feel a bit more satisfying, but beyond that, there’s really nothing. There are no sounds for jumping, sliding, dashing, landing, or even basic UI interactions like clicking buttons or opening the pause menu. Playtesters noted the absence of looping music, and generally, the lack of sound effects contributed to a less immersive experience. This feedback unequivocally demonstrated the critical role of comprehensive audio design in conveying 'game feel' and responsiveness, especially for high-impact actions like dashing and landing.
I had planned to include a whole set of movement sounds to make the player feel more connected to the world, like a little whoosh on the dash, a crunch or skid sound when sliding, and a soft impact sound when landing from a height. All of that would’ve made the movement feel more grounded and reactive. Same goes for UI sounds; even just a subtle click or beep when navigating menus would have made the game feel more polished and responsive.
Unfortunately, I just ran out of time. Between working on the mechanics, fixing bugs, designing levels, and creating the art and animations, the audio side of things ended up getting pushed to the bottom of the list. It’s something I would absolutely want to revisit, because good sound design can really elevate how a game feels - especially in a fast-paced platformer like this one, where feedback is so important.
I encountered a weird bug where if the player died or moved into an area exit collision shape whilst sliding, their collision shape wouldn't be reset until sliding once again, which led to some weird visuals and also made a section of the tutorial not work as intended. This bug, though minor in terms of game progression, compromised visual polish and disrupted player immersion, indicating a need for more rigorous state management post-death/exit. Since the fix was simply sliding again and it didn't really break much, I decided to leave it to the end, so that if I had more time I would fix it. Unfortunately, I ran out of time and this never got fixed, but with more time I could definitely fix this quite easily I imagine.
Myself and many of the testers ran into the same issue with the wall jump, sometimes with flawed input the player would flip their sprite to face away from the wall, and pressing jump would lock them in place and then shortly after they'd fall back down to the ground. I'm not 100% certain what causes this, but I do have some idea. I think it has something to do with the way the wall sliding is handled and detected and it's causing some issues with setting values at the wrong time. This issue highlighted a broader lesson in input buffering and animation state management - specifically, how overlapping inputs and animation transitions can conflict in edge cases. Rather than treating these bugs as isolated technical problems, I now see them as indicators of weak system design. In future projects, I’d take inspiration from games like Celeste and their use of state-safe transitions to create more resilient movement code. I realise now that refining the wall-jump isn’t just about feel, it’s about predictability, player trust, and design architecture. I think if I had more time this would be the first thing I would want to change, it's easily the biggest issue with the gameplay and it's visually jarring and feels horrible. The wall-jump handling has gone through a lot of changes over the course of development and it has gone from absolutely horrific to much better but still not where I want it to be. It feels better than it did but it still needs a lot of refinement and maybe even a complete change in the way it's handled. Maybe that's dramatic but this was easily the most frustrating part of development for me.
I ran into an issue with controls and trying to make the game work for keyboard and mouse, and use of controller. The game is designed with controllers in mind and I decided this very early on in development, however I never quite understood how to make Godot detect input from one or the other and then change the UI based on that detection. This led to me making the game solely around controller use as it felt much better to play using a controller anyway so I wanted that to be the focus rather than some half-baked solution that felt rushed and ugly. That being said, I still made it possible to use keyboard and mouse, it just doesn't look quite right in the menus because grab_focus() always applies to make controllers work with the UI, so multiple buttons can be focused using keyboard and mouse which obviously doesn't look right. This interface problem exposed the importance of input abstraction in multi-platform development. I now recognise that adaptive UI based on active input type (keyboard vs. controller) is a standard expectation, and the lack of it disrupted the polish and accessibility of my menus. If I revisited this, I would create an input manager system inspired by Unity/Godot best practices, using listener-based input mapping to switch icons, prompts, and focus behavior dynamically. This aligns with professional interface standards and player expectations.