I’m making some solid progress on my new game now, and I find myself getting distracted as I start tweaking the content. This is a good thing; it means that I’m getting a lot closer to a vertical slice that I can put in front of people and ask for their opinions. Some major changes from last week:

  • Added preliminary device management, which [redacted, but you can probably figure it out from the video]
  • Added damage and effect visual effects (color reflects type, animates and removes itself)
  • Added the card recycling user interface (mechanic used to be backend only)
  • Added card disabling when you run out of energy
  • Toolbar is completely real (except Options)
  • Cleaned up the effect data type and improved initialization abstraction (easier to extend)
  • Solidified state management issues and improved the task queueing system (supports parallel and sequential now)

I also experimented with GDSam which worked, but I wasn’t sure if it was a good fit because of the harshness, the retro feel when I haven’t solidified on a specific style, and the low quality pronunciations. My kids hated it, so it’s out. What I did learn was that I’ll need separate sounds for when you win or lose a conflict.

I’ve put some effort into a clean collision-based card dragging system and it all works. Good for me! But… why? Why did I do that? It made sense on some level, but looking at other games, that’s not at all how they do it. I don’t think it’s going to enrich the gameplay, it’s a technical distraction, and I need to make this controller first. You’ll still be able to click on things, but I need to take a step back and make this right. This is a natural part of iterative development and constant validation is better than dogmatically continuing in the same direction regardless of the feedback.

I didn’t end up adding any content (cards, opponents, [redacted]) this week, but I think the base mechanics were more important. In my queue:

  • Remove mouse dragging and replace with first-class controller experience
  • Opponent intent (it’s known but not shown)
  • Granular [redacted] beyond just turning them on and off
  • Visual indicator when [redacted] are damaged or disabled
  • Loadout - show and sort all possible cards
  • Delays when playing a card and each opponent effect (don’t just instantly resolve)
  • Visual indication of persistent effects (shield, melt)
  • Add another [redacted] and associated cards for variety
  • Add a second opponent to the conflict with dynamic layout
  • Subtle floating for all combatants
  • Shrink cards a little (too big)
  • Abstraction pass (buttons, labelsettings, themes, etc.)
  • Remove unused fonts
  • Simple dialog system (start of encounter, midway)

While I don’t think it’s a mistake, I’m glad that I’m validating the decisions that I’m making and doing the root check - is the mechanic fun?


I’ve been enjoying a couple other games recently, including Winnie’s Hole - it’s from the makers of Ring of Pain, and features a wonderful soundtrack by Belinda Coombs. It’s sort of a deckbuilder, but with multiple mechanics, great art and music, and an evolving story. I hit my first Early Access snag, but I like that they incorporated it into the dialog options!

I also played a demo of another roguelike deckbuilder game and took some notes that I’ll incorporate into my own development. I also shared some feedback directly with the developers.

  • Ensure cards have clear differentiators from each other mechanically; think of Matt Groening’s approach to character design where you can recognize them from their outlines alone
  • Avoid too many effects too early in a run; it got chaotic and it was hard to create a consistent strategy
  • Minimize animations on dialog, prevent repetitive unskippable discussions

Here’s a little helper for setting the name of a movie to avoid repeatedly overwriting the same one until you remember to rename it. Just right-click, “Run” before recording the movie.

@tool
extends EditorScript

func _run() -> void:
	var base_path := "res://movies/"
	var time_str := Time.get_datetime_string_from_system().replace(":", "_")
	var movie_path := base_path + "REPLACE-" + time_str + ".avi"

	# Set the movie path
	ProjectSettings.set_setting("editor/movie_writer/movie_file", movie_path)
	ProjectSettings.save()
	print("Movie path set to: ", movie_path)