I needed to implement a character set evolution system for my mini-home service. Previously, there was absolutely no functionality for character growth or acquiring new appearances. I felt that adding something like this would enrich the user experience.
Attempts and Pitfalls
At first, I thought about simply adding evolution items to the point shop and having the character's appearance change upon use. However, I ran into unexpectedly complex issues when trying to integrate it with the inventory system.
I had to consider the character's current level, owned items, and evolution stage simultaneously, and I was at a loss for how to manage this data and pass it via API. It was particularly difficult to integrate it naturally without affecting the already existing point shop and inventory systems.
The Cause
The biggest problem was the unclear data linkage between each system. The point shop only managed item purchase history, and the inventory only managed the list of owned items. There was a lack of design on where and how to store and retrieve the new state values for character evolution.
The Solution
Ultimately, I implemented a 4-stage character evolution system by linking it with the point shop and inventory systems. I defined the required items and points for each evolution stage and created logic to update the character's appearance and stats accordingly.
# Example of character evolution logic (simplified)
class CharacterEvolutionService:
def __init__(self, user_id):
self.user_id = user_id
self.inventory_service = InventoryService(user_id)
self.point_shop_service = PointShopService(user_id)
self.character_data = self.load_character_data(user_id) # Load current character data
def load_character_data(self, user_id):
# In reality, character data would be retrieved from the DB using the user ID
# Example: {"level": 1, "evolution_stage": 0, "skin_id": "default_skin"}
return {"level": 1, "evolution_stage": 0, "skin_id": "default_skin"}
def can_evolve(self, target_stage):
# Check current evolution stage and required items/points
required_items = self.get_evolution_requirements(target_stage)
if not self.inventory_service.has_items(required_items):
return False
required_points = self.get_evolution_points(target_stage)
if self.point_shop_service.get_current_points() < required_points:
return False
return True
def evolve_character(self, target_stage):
if not self.can_evolve(target_stage):
raise ValueError("Evolution conditions not met.")
# Remove required items
required_items = self.get_evolution_requirements(target_stage)
self.inventory_service.remove_items(required_items)
# Deduct points
required_points = self.get_evolution_points(target_stage)
self.point_shop_service.deduct_points(required_points)
# Update character data
self.character_data["evolution_stage"] = target_stage
self.character_data["skin_id"] = self.get_skin_id_for_stage(target_stage)
self.save_character_data(self.user_id, self.character_data)
return True
def get_evolution_requirements(self, stage):
# In reality, this would be retrieved from a config file or DB
requirements = {
1: {"item_id": "evolution_stone_1", "quantity": 1},
2: {"item_id": "evolution_stone_2", "quantity": 2},
3: {"item_id": "evolution_stone_3", "quantity": 3},
4: {"item_id": "evolution_stone_4", "quantity": 4}
}
return requirements.get(stage, {})
def get_evolution_points(self, stage):
# In reality, this would be retrieved from a config file or DB
points = {1: 100, 2: 200, 3: 300, 4: 400}
return points.get(stage, 0)
def get_skin_id_for_stage(self, stage):
# In reality, this would be retrieved from a config file or DB
skins = {1: "stage1_skin", 2: "stage2_skin", 3: "stage3_skin", 4: "stage4_skin"}
return skins.get(stage, "default_skin")
def save_character_data(self, user_id, data):
# In reality, character data would be saved to the DB using the user ID
print(f"Saving character data: {user_id}, {data}")
# --- Mock Services (In a real environment, actual services would be called) ---
class InventoryService:
def __init__(self, user_id):
self.user_id = user_id
self.items = {"evolution_stone_1": 2, "evolution_stone_2": 1} # Example owned items
def has_items(self, required_items):
if not required_items: return True
item_id = required_items["item_id"]
quantity = required_items["quantity"]
return self.items.get(item_id, 0) >= quantity
def remove_items(self, required_items):
if not required_items: return
item_id = required_items["item_id"]
quantity = required_items["quantity"]
if self.has_items(required_items):
self.items[item_id] -= quantity
print(f"Removed {quantity} of {item_id}. Remaining: {self.items[item_id]}")
else:
raise ValueError("Insufficient items.")
class PointShopService:
def __init__(self, user_id):
self.user_id = user_id
self.current_points = 500 # Example owned points
def get_current_points(self):
return self.current_points
def deduct_points(self, amount):
if self.current_points >= amount:
self.current_points -= amount
print(f"Deducted {amount} points. Remaining: {self.current_points}")
else:
raise ValueError("Insufficient points.")
# --- Example Usage ---
# user_id = "test_user_123"
# evo_service = CharacterEvolutionService(user_id)
# try:
# print(f"Current evolution stage: {evo_service.character_data['evolution_stage']}")
# if evo_service.can_evolve(1):
# print("Stage 1 evolution possible")
# evo_service.evolve_character(1)
# print(f"Stage after evolution: {evo_service.character_data['evolution_stage']}, Skin: {evo_service.character_data['skin_id']}")
# else:
# print("Stage 1 evolution not possible")
# except ValueError as e:
# print(f"Error occurred: {e}")
This code checks the user's inventory and point information, and if the conditions are met, it updates the character's evolution stage and changes its appearance. It's designed to clearly manage the required items, points, and applicable skin IDs for each evolution stage.
Results
- Users can now grow their characters and acquire new appearances in the game.
- Integration with the existing point shop and inventory systems was achieved smoothly.
- Through the structured 4-stage evolution system, we can now provide users with a more in-depth gameplay experience.
Takeaways — To Avoid the Same Pitfalls
- [ ] When implementing new features, clearly design the data linkage with existing systems in advance.
- [ ] Carefully decide on the data structure for storing and managing character state values (evolution stage, appearance, etc.).
- [ ] Accurately define all necessary parameters and return values for API calls.
- [ ] Consider a structure that minimizes dependencies between systems and allows for flexible expansion.
💬 This is part of *Riel** — a full AI product I'm building solo, in public (failures and all). Read more build logs → · See the product →*
Top comments (0)