I made a rail shooter for Kenney Jam 2025 | Maximum Voltage
Projects:
Categories:
Practice. Practice. Practice.
Since Scream Jam 2024, I’ve been creating tons of small prototype projects in Godot to better learn the engine’s features. Since I wanted to focus on the coding, I’ve been using Kenney assets exclusively for these projects so I was really excited when I learned that Kenney has a yearly game jam!
Preparation
After not doing so well in my last 7 day jam, I was extremely nervous to try a 48 hour jam but decided to make the best of my time by reviewing Adam Younis’ jam devlogs for tips before the jam. I took away two points from his devlogs: make a schedule and prioritize tasks. To that end, I put together my own general purpose schedule for a 48 hour jam based on my best guess at how long each task would take. The exact time spent on each task isn’t that important but the order I work on them was carefully chosen to get the game playable as early as possible.
Expand schedule
Day Time Goal Actions Friday 11:00 AM Ideation Brainstorming - Concept Design Friday 12:00 PM Systems Mechanics - Core Loop Friday 01:00 PM " Friday 02:00 PM " Friday 03:00 PM " Friday 04:00 PM Game Playable Friday 05:00 PM World Design Friday 06:00 PM Core Animations Friday 07:00 PM Game Loop Bookends Score - Win Condition - Loose Condition Friday 08:00 PM Level Design Friday 09:00 PM " Friday 10:00 PM " Friday 11:00 PM " Saturday 12:00 AM " Saturday 01:00 AM UI Design Saturday 02:00 AM " Saturday 03:00 AM Game Complete-able Saturday 04:00 AM Juice Saturday 05:00 AM " Saturday 06:00 AM " Saturday 07:00 AM Story Saturday 08:00 AM SFX Saturday 09:00 AM " Saturday 10:00 AM Music Saturday 11:00 AM " Saturday 12:00 PM Beta Test Saturday 01:00 PM Collectables/Extras Saturday 02:00 PM " Saturday 03:00 PM " Saturday 04:00 PM Title Screen Saturday 05:00 PM Settings Menu Saturday 06:00 PM Credits Saturday 07:00 PM Cutscenes Saturday 08:00 PM " Saturday 09:00 PM " Saturday 10:00 PM Create itch Page Saturday 11:00 PM " Sunday 12:00 AM Testing Test Game in itch Sunday 01:00 AM Create thumbnail Sunday 02:00 AM Screenshots Sunday 03:00 AM Submit Sunday 04:00 AM Sunday 05:00 AM Sunday 06:00 AM Sunday 07:00 AM Sunday 08:00 AM Sunday 09:00 AM Sunday 10:00 AM Sunday 11:00 AM DEADLINE
After building the schedule, I finished my prep for the jam by downloading every Kenney and Kay asset pack and importing them into a file manager called Eagle. Eagle is a program I learned about last year from a YouTube video on tag-based filesystems and I’ve been using it ever since to help organize my game assets (not sponsored, I just really like it). The nice thing about Eagle is that it lets you assign tags to your assets and search for them much easier than through Windows Explorer. I figured having the files indexed would help me find what I need during the jam quicker.

Searching for Kenney and Kay assets in Eagle
Ideation
Before the jam started, I had been on a rail-shooter kick playing games like Starfox 64 and Galaga: Destination Earth. Having seen the ships in the Kenney Space pack before, I really wanted to try making a game like these and was thankful when power was announced to be the theme. Immediately, I decided that I would build a 2-3 minute rail shooter where the player fires electrical bolts and can charge their ship to either unleash a more powerful attack or dodge. I figured this idea was perfect for a short jam since player and enemy movement could be done entirely with Path3D
nodes.
Being inspired by retro rail shooters, I also decided the game would run in an extremely low resolution (256x224) and adhere to the simple geometry and colors of a SNES SuperFX game.
Development
Component architecture
I’ve been working to embrace component architecture more in my recent games so I started by defining a whole set of reusable components for every game function I could need: health, hitboxes, hurtboxes, scoring, item pickups, damage/hit effects, etc. These components are so generalized that almost every object in my game was built from the same components.

Charge ring components

Enemy components

Player components

Projectile components
Most components are also written in such a way that they can take references to other components to chain behavior without needing any code. This is done by having the components self-subscribe to the linked component’s signals on ready. For example, the pickup component will kill a linked health component when obtained and the death component will destroy an object when its linked health component is killed.

Example death component

Example flash component

Example hit-box component

Example hurt-box component

Example score component
Player controllers
Both the player and enemy inherit from a custom PathFollow3D
node called RailFollower
which adds extra logic to follow a path at a set speed.

Rail follower

Enemy code
The player ship doesn’t directly follow the path but rather is constrained to a 3D plane following the path; unfortunately, it gets a bit more complicated still. I learned that to look correct, the ship actually needs to pitch and yaw away from the camera as it reaches the extents of the screen. That caused problems for the aiming since I implemented the crosshairs as literal 3D objects attached to the front of the ship. Having the ship pitch/yaw as it moves caused the crosshairs to go off screen and required a lot of manual tuning to fix.

Player scene showing the crosshairs in front

Player and enemy paths
Rendering
Several people in the jam comments assumed I was using a shader to pixelate my game but the reality is much simpler. I just set the project’s window resolution to 256x224, enabled viewport scaling, and switched it to integer upscaling. The game is natively rendering in 256x224 and the pixel size just gets multiplied for larger windows.
This has the downside of causing the game to be very small by default; however, I used Itch.io’s canvas size option in the game settings to force the canvas to a larger initial size.
Time allocation
To help with my planning for future jams, I recorded my time throughout the jam:
Expand devlog
- Friday
- 11:00: Project setup
- 11:15: Ideation
- 12:15: Rendering
- 12:22: Rail follower / camera
- 13:20: Player movement
- 13:38: Targeting reticule
- 14:32: Bug fix
- 16:00: Hit box / health components
- 17:00: Laser components / spawn manager
- 18:40: Break
- 19:40: Basic enemy
- 20:20: Gameplay tweaks
- 23:20: Break
- Saturday
- 00:03: Scoring system
- 01:19: Power system
- 02:44: Break
- 03:16: Add turbo laser
- 04:30: Add boost
- 04:45: Enemy spawner
- 05:00: Trigger volumes
- 05:30: Fixing shader stutter
- 05:51: Game balance
- 06:00: Bookends
- 07:00: Break
- 07:40: Jam page
- 08:05: Break
- 12:38: Bookends
- 16:23: Beta testing
- 17:53: Transitions
- 18:35: Bug fixes
- 18:39: Game over screen
- 21:55: Level design
- Sunday
- 00:55: Break
- 01:39: SFX
- 02:55: Visual design
- 03:56: Break
- 04:20: HUD
- 05:49: Splash screens
- 06:43: Credits
- 08:17: Store page
- 10:00: Submission
- 10:14: Fix sound bug
- 10:17: Done
Expand time summary
Task Details Minutes Planning Ideation 60 Planning Total 60 Project Setup Godot setup 15 Project Setup Total 15 Core Code Rendering code 7 Core Code Shader preloader 21 Core Code Total 28 Mechanics Movement code 18 Mechanics Camera 58 Mechanics Crosshair 54 Mechanics Projectile system 100 Mechanics Hit box / health components 60 Mechanics Drone enemy 40 Mechanics Power system components 85 Mechanics Dodge 15 Mechanics Turbo laser 74 Mechanics Scoring system 79 Mechanics Enemy spawner 15 Mechanics Trigger volume component 30 Mechanics Total 628 Game Loop Bookends Level reset code 60 Game Loop Bookends Menu code 225 Game Loop Bookends Game over code 196 Game Loop Bookends Total 481 Level Design Level design 180 Level Design Total 180 Beta Testing Beta testing 93 Beta Testing Total 93 Bug Fixes Bug fixes 95 Bug Fixes Total 95 Balance Gameplay tweaks 180 Balance Score balancing 9 Balance Total 189 Audio SFX 76 Audio Total 76 Polish Scene transitions 42 Polish Visual polish 61 Polish HUD redesign 89 Polish Splash screens 54 Polish Credits screen 94 Polish Total 340 Jam Submission Itch page 128 Jam Submission Submission 14 Jam Submission Total 142 Break Break 514 Break Total 514 Total 2841 Dev Total 2327 (81% of allotted time)
I’ve heard from multiple devs that a short highly polished game will do better in jams than a longer less polished game so I spent most of my time working on polish rather than the game’s level. This unfortunately meant the final level was only 30 seconds long but I think it worked to prove out the concept.
Post-mortem
Results
Of the 717 final entries, I received 22 comments and won best itch.io page.
Given the jam isn’t ranked, I wasn’t expecting to win anything with over 700 other entrants so I was blown away that I won best itch.io page.
The most common feedback I received was that the visuals, polish, enjoyment, and genre choice were great but that the game was too short, hard to determine depth, and the ctrl keybinding was conflicting with browser shortcuts.
You can play Maximum Voltage on itch.io or check out one of my favorite submission to the jam:
Pros and cons
Pros
- Components made it easy to build levels and add new behaviors
- Kenney assets look great in low-resolution
- Focusing on core gameplay first was the right move
- High-score focus makes the game more enjoyable to replay
- My strength is cinematic events so a rail shooter really highlighted that
- Including hit% in the score screen made it more fun to replay
- Rapid fire is so satisfying
- Early web testing helped identify several critical performance, audio, and sprite issues
Cons
- Spent too much time working on the menus and didn’t have enough left to finish the first level
- Difficult to tell in editor what the bounds of the player’s movement are which made level design more trial and error
- There’s no reason in the final game to use the dodge so it just feels like a waste of power and by extension the single power pickups
- Developed the game with my speakers on low so I didn’t notice until after submission the master volume was way too high
- Should have made my game manager a general purpose scene transitioner as that would have reduced code in the main menu scene
- Ctrl was a bad key mapping - it’s hard to press and I learned from a reviewer that pressing Ctrl+W closes the entire browser
- No volume slider
- Several people had issues with depth perception
- Name didn’t quite match the game
- Should have used pictures instead of headers for the jam page, shouldn’t have repeated the title in the page text after the banner
- The aim-centering is bugged and re-centers the aim on the ship not the screen making it so your ship blocks the view when shooting anything straight ahead
What’s next
Due to popular demand, I started working on several updates to the game during the judging period. While I’d like to make a full rail shooter at some point, I don’t think Maximum Voltage has enough of an identity of its own for that but I am working to complete the first level of the game as I envisioned. This means adding enemies that shoot back and more cinematic encounters.
I have a lot of jams scheduled back-to-back this year so I won’t make any promises for the release date but know that it is in the works.
