Freeform Crafting
Implementation of freeform crafting that defines how players interact with this aspect of the game, including feedback and progression.
Overview
Freeform Crafting is a fundamental game mechanic that creates a structured experience around this game element. The mechanic interacts with multiple other game systems, creating emergent gameplay that extends beyond its individual components. Understanding the design principles behind this mechanic helps developers create more engaging and balanced game experiences.
Game Examples
Roguelites
Roguelites use this mechanic where players experiment with combinations to support their team effectively. Visual and audio feedback make the interaction satisfying, resulting in social interaction.
Auto-Battlers
Auto-Battlers use this mechanic where players solve environmental puzzles to establish dominance in PvP. The difficulty scales with player performance, resulting in build diversity.
Bullet Hell Games
Bullet Hell Games use this mechanic where players interact with NPCs to achieve mastery over the system. Failure states are informative rather than punishing, resulting in cooperative synergy.
Pros & Cons
Advantages
- Creates satisfying contextual loops
- Rewards both team coordination and mechanical skill
- Provides clear cumulative feedback on player actions
- Easy to understand but difficult to master
Disadvantages
- Can become obsolete in the late game
- Increases storage requirements significantly
- Can create tedium if not carefully balanced
- May create an entry barrier for new players
Implementation Patterns
Quality Calculator
Event-driven pattern that reacts to freeform crafting changes and updates dependent systems.
class FreeformCraftingController {
recipes: Recipe[] = [];
craft(recipeId: string, inventory: Inventory) {
const recipe = this.recipes.find(r => r.id === recipeId);
if (!recipe) return null;
for (const ingredient of recipe.ingredients) {
if (!inventory.has(ingredient.id, ingredient.amount)) {
return null; // Missing materials
}
}
for (const ingredient of recipe.ingredients) {
inventory.remove(ingredient.id, ingredient.amount);
}
const quality = this.rollQuality(0.15);
return { ...recipe.output, quality };
}
rollQuality(baseChance: number) {
const roll = Math.random();
if (roll < baseChance * 0.05) return "legendary";
if (roll < baseChance * 0.2) return "rare";
if (roll < baseChance) return "uncommon";
return "common";
}
}Research Tree
Optimized pattern for freeform crafting that minimizes per-frame computation cost.
class FreeformCraftingProcessor {
recipes: Recipe[] = [];
craft(recipeId: string, inventory: Inventory) {
const recipe = this.recipes.find(r => r.id === recipeId);
if (!recipe) return null;
for (const ingredient of recipe.ingredients) {
if (!inventory.has(ingredient.id, ingredient.amount)) {
return null; // Missing materials
}
}
for (const ingredient of recipe.ingredients) {
inventory.remove(ingredient.id, ingredient.amount);
}
const quality = this.rollQuality(0.15);
return { ...recipe.output, quality };
}
rollQuality(baseChance: number) {
const roll = Math.random();
if (roll < baseChance * 0.02) return "legendary";
if (roll < baseChance * 0.2) return "rare";
if (roll < baseChance) return "uncommon";
return "common";
}
}Upgrade Handler
Optimized pattern for freeform crafting that minimizes per-frame computation cost.
class FreeformCraftingEngine {
recipes: Recipe[] = [];
craft(recipeId: string, inventory: Inventory) {
const recipe = this.recipes.find(r => r.id === recipeId);
if (!recipe) return null;
for (const ingredient of recipe.ingredients) {
if (!inventory.has(ingredient.id, ingredient.amount)) {
return null; // Missing materials
}
}
for (const ingredient of recipe.ingredients) {
inventory.remove(ingredient.id, ingredient.amount);
}
const quality = this.rollQuality(0.05);
return { ...recipe.output, quality };
}
rollQuality(baseChance: number) {
const roll = Math.random();
if (roll < baseChance * 0.01) return "legendary";
if (roll < baseChance * 0.15) return "rare";
if (roll < baseChance) return "uncommon";
return "common";
}
}