Balatro + Path Building?
In December 2024 I joined the FediJam 2 game jam on a bit of a whim. On Mastodon, the organizers had been running a poll to decide the theme of the jam and I was pretty sure ‘On Rails’ was going to win. Sometime during the period the poll was going on (and probably while I was playing Balatro) I decided to join and would try to make a path-building game with cards and scoring elements similar to Balatro.
Trails, Roads, and Rails is the result, and I won the Jam!! I’m very happy with how the game turned out. It’s fun to play and it demonstrates a lot of the potential a game like it would have. Here’s how the game turned out, and how it was made!
But first, please consider subscribing to my newsletter, either with the substack link below or with the RSS feed for this blog. I’m excited to share my game development journey with you.
Trails, Roads, and Rails
Trails, Roads, and Rails is a deck-building path-building game. The goal is to lay down a path to connect two flags by placing tiles from your hand. You can choose to discard remaining cards and draw new ones at any time. Tiles connecting the flags will score points (NICE!) and a multiplier (EXCITING!). Score enough points to advance to the next level, where you can add or remove cards from your deck. Feature cards can be placed on the path for bonus points.
Not only are the different path types worth different numbers of points, but stringing together multiple of the same type will grant a combo multiplier! Trails get a special bonus when running through a forest and are the only type that can go through the mountains while rails get double the combo bonus.
Development Log
I really did not plan to spend a full month on this prototype, but in the end it was scoped well for the timeframe and I had a really fun time working on it.
I developed this in the Godot Engine, a free and open source game engine that I’ve had a lot of fun learning the past couple years.
The source code for this project is available here: https://github.com/nuzcraft/trails-roads-rails
Tilemap Editing
I started by trying to understand how to do the basic mechanic of just placing a tile down on a map. I created a basic tilemap with some sprites from kenney and started working through some things. I created a basic card object that held a picture of whatever tile I was looking to place and then hooked up the some mouse actions to clicking and releasing the card. When the mouse button is released (indicating the player has dropped the card) a signal is sent out from the card. The main game scene uses the mouse position and the ‘atlas position of the image on the card’ to update the tilemap with the new tile. The atlas position bit is important for this prototype because by aligning the atlas image used in the card with the atlas image used in the tileset, I didn’t have to create a bunch of extra logic when creating new card types. I only had to set the image of the card and dropping them on the map would work without issue.
In this example, you can see when the card is dropped, the map is updated and the card disappears. There is logic so that right-clicking instead of releasing the button will send the card back to the hand.
Looking back, it’s kinda amazing how little the vision for the game changed from that very first day or two.
Pathfinding
Pathfinding was going to be a big element of the game, so the next step was to so it was important to get it figured out early in the process. Each card would have a ‘connection array’ property containing some combination of N, S, E, W to indicate which directions could path through it. The ‘vertical road’ card has a ['N', 'S']
array to indicate that we only want to path through it vertically.
Pathfinding itself is done via the AStar2D
class in Godot. By keeping track of all the cards we drop on the board, we can make sure we only connect the tiles in AStar if adjacent tiles have the corresponding connection arrays to allow the path to move through in the correct direction.
Once again, I tried to make this system robust enough to handle lots of different path configurations, including T and X intersections. I didn’t end up adding any of those to the game, but the opportunity was there right from the start.
In this example, there’s a big ‘not connected’ label in the top left. When we drop an unconnected road piece off to the side, the pathfinding checks for a path and updates the label with ‘not a path’. When we drop a vertical road tile in the empty space, the label updates to ‘you win’ indicating a successful path was created between the two flags.
Deck Mechanics
From pathfinding, I was able to quickly make some new card types (horizontal and turn roads) and started building out the UI and data structures for having a ‘hand’ and ‘deck’ of cards. At its most boring, the hand and deck are just arrays of card objects, but it was suprisingly complex to get everything interacting propely and consistently.
Mostly my issues had to do with parenting. There are instances of the cards saved in the deck, but they aren’t added to the scene until they come into the hand. There’s a semi-complex tree of UI controls to display the hand correctly, and the card becomes the child of one of those controls. After the card is played, it needs to be decoupled from UI and either cleared from memory or stored in a discard object somewhere. Getting all that orchestrating well is something I adjusted all throughout development.
Here we can see a deck on the right indicating a total of 16 cards. 8 were drawn to the hand, so 8 remain in the deck. Cards from the hand are played until the flags are connected. As cards are played, we see the cards shift to the left, shrinking the hand.
Scoring!
If you’ve played Balatro, you know that each card is worth blue chips, then your hand and jokers provide additional chips and mult to help you rack up the points. I tried to implement a similar scoring system with the rudimentary idea of building a NICE path with EXCITING as a multiplier. In this first iteration, the only way to get mult was to path through a forest (or put a tree in the road) for a little excitement. The pathing would increment it’s way through and tally up the points, ideally giving a little bit of mystery.
‘How many points did I really get?’
Somewhat obviously, the goal was to give players a method to calculate their score ahead of time, but also a bit of a suspense factor as they watched the score tally up (this would end up being the subject of a minor bug later on).
In this example, we place down a path with one road going through a forest. After the path is complete, popups show how much score is coming through plus the score on the right starts ticking up. Eventually we get up to a total of 20 points. 10 NICE x 2 EXCITING
Adding some juice
Deck and hand mechanics continued to get fleshed out, and I began adding some little things to make the game feel better to play. Outlines + a little size increase when hovering over a card, a little wiggle when a card is clicked, when canceling a card, you see it move back to the hand. Finally, when discarding cards, you can see them move towards the deck and disappear.
The discarding bit comes from a brand new button, the Discard & Draw button! Click it to get rid of all the remaining cards in hand and draw some brand new ones!
I also added a Goal for the number of points the player should be trying to get for this particular path.
In this example, we see cards getting moused over, clicked and picked up. Some cards are placed on the map, some are canceled and move back into the hand. We see some cards get discarded and a fresh hand is drawn before the path is finished.
In this next example, we see multiple turn get taken to make a large path. Points are tallied through the whole path with the multiplier incrementing whenever it goes through a forest.
The next bit of juice I tried to add was screenshake, and as you can see from this next gif, I overdid it a bit at the start…
Finally getting to new path types…
For the next update, I did I focused on finishing out the features I needed to make the game interesting to play. I implemented a level system so the ‘Goal’ points would increment and a new level could start. The leveling system isn’t very complex, but it did a good job forcing me to partition out my code such that I could create new levels on the fly and start them easily.
I added a combo multiplieer so that any part of the path where 3 or more of the same path type gets a bonus multiplier.
I also started implementing new path types. The ‘trail’ type is a lower scoring type that gets extra bonuses from going through forests. In the first iteration I simply recolored the road sprite since the tileset I used didn’t have an appropriate ‘trail’ sprite.
I flexed my art skills and created custom trail and rail sprites that turned out really well! The rail doesn’t get as much bonus from forests, but gets extra multiplier for combos. I hoped with some of the differentiation in the path types, players could start strategizing ways to get high scores.
There were a few othere additions to finish up development.
- if you create a path without enough points, a little labels comes up to tell you
- there’s a pause menu where the game can be restarted or quit
- there are tooltips when you hover over a card in your hand
- the popups speed up when the path is big enough
Complete?
The game was done! 10 days ahead of the deadline, I uploaded the game to itch.io and submitted it to the jam as a pre-release. I also took a little detour to set up automated deployments, which is always a fun adventure.
https://nuzcraft.itch.io/trails-roads-and-rails/devlog/854812/trails-roads-and-rails-pre-release
Bonus updates
One of the first comments I got on the pre-release said ‘it needs sounds!’ and I facepalmed because sounds had completely slipped my mind. To be fair, sounds were on my to-do list, but somehow I had completely discounted them for the pre-release when they really should have been involved in the first place.
Anyway, the first bonus update to the game was adding sounds and music.
https://nuzcraft.itch.io/trails-roads-and-rails/devlog/856395/sound-and-music-update-
The second and final update added some stretch features that I think really show what the game is capable of…
- deck editing
- new card types
In between each level, players get the option to add or remove cards to the deck. This stage would be more impactful with a few other tweaks, but I’m really happy with how it changed the flow of the game.
I added 4 new cards in a new card type, the feature type
- forest
- hills
- mountains
- flower field
The ‘feature’ cards can be placed on top of paths just like the pre-existing forests and they are meant to be powerful bonuses to ramp up points.
https://nuzcraft.itch.io/trails-roads-and-rails/devlog/859527/new-tilesdeck-editing
Conclusion
I had a really great time in this jam. It was really nice to have a vision at the start and execute on it relatively well. The project ended up being scoped really well and I was able to hit a lot of the goals I set for myself.
Thank you so much for reading! Please subscribe if you enjoyed!
nuzcraft