A playable vertical slice and cutting a bad mechanic
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)