Huisdieren Systeem
Huisdieren verzorgen, trainen, en interacties.
Overzicht
┌─────────────────────────────────────────────────────────────┐
│ Pet Systeem │
├─────────────────────────────────────────────────────────────┤
│ │
│ Pet Stats: Acties: │
│ ├── Happiness (0-100) ├── Voeren │
│ ├── Hunger (0-100) ├── Aaien │
│ ├── Energy (0-100) ├── Spelen │
│ └── Bond Level (1-10) ├── Trucs leren │
│ └── Op avontuur │
│ │
│ Beloningen: │
│ • Hoge happiness = bonus items vinden │
│ • Hoge bond = nieuwe trucs unlocked │
│ • Dagelijkse gifts van je huisdier │
│ │
└─────────────────────────────────────────────────────────────┘
Pet Data Model
Pet Resource
# pet_data.gd
class_name PetData extends Resource
@export var pet_id: String = ""
@export var pet_type: String = "" # cat, dog, bunny, etc.
@export var name: String = ""
@export var variant: String = "" # color variant
# Stats (0-100)
@export var happiness: int = 50
@export var hunger: int = 50
@export var energy: int = 100
# Progression
@export var bond_level: int = 1
@export var bond_xp: int = 0
@export var learned_tricks: Array[String] = []
# Timestamps
@export var last_fed_time: int = 0
@export var last_pet_time: int = 0
@export var last_play_time: int = 0
Pet Manager
# pet_manager.gd
extends Node
signal pet_happiness_changed(pet_id: String, new_value: int)
signal pet_hunger_changed(pet_id: String, new_value: int)
signal pet_leveled_up(pet_id: String, new_level: int)
signal trick_learned(pet_id: String, trick_id: String)
var owned_pets: Dictionary = {} # pet_id -> PetData
var active_pet_id: String = ""
func _ready() -> void:
_load_pets_from_server()
_start_stat_decay_timer()
func _start_stat_decay_timer() -> void:
var timer = Timer.new()
timer.wait_time = 60.0 # Check every minute
timer.autostart = true
timer.timeout.connect(_decay_stats)
add_child(timer)
func _decay_stats() -> void:
var current_time = Time.get_unix_time_from_system()
for pet_id in owned_pets:
var pet = owned_pets[pet_id]
# Hunger increases over time
var time_since_fed = current_time - pet.last_fed_time
var hunger_increase = int(time_since_fed / 1800) # +1 every 30 min
pet.hunger = min(100, pet.hunger + hunger_increase)
# Happiness decreases when hungry or lonely
if pet.hunger > 70:
pet.happiness = max(0, pet.happiness - 1)
var time_since_pet = current_time - pet.last_pet_time
if time_since_pet > 7200: # 2 hours
pet.happiness = max(0, pet.happiness - 1)
_sync_pet_to_server(pet_id)
Pet Interacties
Voeren
func feed_pet(pet_id: String, food_item_id: String) -> bool:
if pet_id not in owned_pets:
return false
var pet = owned_pets[pet_id]
var inventory = get_node("/root/InventoryManager")
if not inventory.has_item(food_item_id):
NotificationManager.toast("Je hebt dit voedsel niet!", "warning")
return false
# Get food data
var food_data = PetFoodDatabase.get_food(food_item_id)
if food_data.is_empty():
NotificationManager.toast("Dit is geen huisdiervoedsel", "warning")
return false
# Check if pet likes this food
var pet_type_data = PetTypeDatabase.get_pet_type(pet.pet_type)
var is_favorite = food_item_id in pet_type_data.favorite_foods
# Remove food from inventory
inventory.remove_item(food_item_id, 1)
# Update pet stats
var hunger_reduction = food_data.hunger_restore
var happiness_gain = food_data.happiness_gain
if is_favorite:
hunger_reduction = int(hunger_reduction * 1.5)
happiness_gain = int(happiness_gain * 2)
NotificationManager.toast("%s houdt van dit eten!" % pet.name, "success")
pet.hunger = max(0, pet.hunger - hunger_reduction)
pet.happiness = min(100, pet.happiness + happiness_gain)
pet.last_fed_time = Time.get_unix_time_from_system()
# Bond XP
_add_bond_xp(pet_id, 5)
_sync_pet_to_server(pet_id)
pet_hunger_changed.emit(pet_id, pet.hunger)
pet_happiness_changed.emit(pet_id, pet.happiness)
return true
Aaien
func pet_the_pet(pet_id: String) -> void:
if pet_id not in owned_pets:
return
var pet = owned_pets[pet_id]
var current_time = Time.get_unix_time_from_system()
# Cooldown check
var time_since_last = current_time - pet.last_pet_time
if time_since_last < 300: # 5 minute cooldown
NotificationManager.toast("%s wil even rust" % pet.name, "info")
return
# Increase happiness
pet.happiness = min(100, pet.happiness + 10)
pet.last_pet_time = current_time
# Bond XP
_add_bond_xp(pet_id, 3)
# Play animation
var pet_node = _get_pet_node(pet_id)
if pet_node:
pet_node.play_animation("happy")
_sync_pet_to_server(pet_id)
pet_happiness_changed.emit(pet_id, pet.happiness)
# Random response
var responses = ["Miauw!", "Blij!", "❤️", "Spinnen..."]
NotificationManager.toast(responses.pick_random(), "success")
Spelen
func play_with_pet(pet_id: String, toy_item_id: String = "") -> void:
if pet_id not in owned_pets:
return
var pet = owned_pets[pet_id]
# Check energy
if pet.energy < 20:
NotificationManager.toast("%s is te moe om te spelen" % pet.name, "info")
return
# Play session
pet.energy = max(0, pet.energy - 15)
pet.happiness = min(100, pet.happiness + 15)
pet.hunger = min(100, pet.hunger + 5) # Playing makes hungry
pet.last_play_time = Time.get_unix_time_from_system()
# Bond XP (more with toy)
var bond_gain = 5
if not toy_item_id.is_empty():
bond_gain = 10
_add_bond_xp(pet_id, bond_gain)
# Play mini-game or animation
_start_play_animation(pet_id)
_sync_pet_to_server(pet_id)
Bond Systeem
const BOND_XP_PER_LEVEL = [0, 50, 150, 300, 500, 800, 1200, 1700, 2300, 3000]
func _add_bond_xp(pet_id: String, amount: int) -> void:
var pet = owned_pets[pet_id]
pet.bond_xp += amount
# Check for level up
var next_level = pet.bond_level + 1
if next_level <= 10:
var xp_needed = BOND_XP_PER_LEVEL[next_level]
if pet.bond_xp >= xp_needed:
pet.bond_level = next_level
_on_bond_level_up(pet_id, next_level)
func _on_bond_level_up(pet_id: String, new_level: int) -> void:
var pet = owned_pets[pet_id]
NotificationManager.toast(
"Bond met %s is nu level %d!" % [pet.name, new_level],
"success"
)
# Unlock new tricks at certain levels
var pet_type_data = PetTypeDatabase.get_pet_type(pet.pet_type)
for trick in pet_type_data.tricks:
if trick.unlock_level == new_level:
_unlock_trick(pet_id, trick.id)
pet_leveled_up.emit(pet_id, new_level)
Trucs Systeem
func _unlock_trick(pet_id: String, trick_id: String) -> void:
var pet = owned_pets[pet_id]
if trick_id in pet.learned_tricks:
return
pet.learned_tricks.append(trick_id)
var trick_data = TrickDatabase.get_trick(trick_id)
NotificationManager.toast(
"%s heeft '%s' geleerd!" % [pet.name, trick_data.display_name],
"success"
)
trick_learned.emit(pet_id, trick_id)
func perform_trick(pet_id: String, trick_id: String) -> void:
var pet = owned_pets[pet_id]
if trick_id not in pet.learned_tricks:
return
if pet.energy < 10:
NotificationManager.toast("%s is te moe" % pet.name, "info")
return
pet.energy -= 10
# Play trick animation
var pet_node = _get_pet_node(pet_id)
if pet_node:
await pet_node.play_trick(trick_id)
# Happiness boost
pet.happiness = min(100, pet.happiness + 5)
# Random reward chance
if randf() < 0.2:
_give_trick_reward(pet_id)
_sync_pet_to_server(pet_id)
func _give_trick_reward(pet_id: String) -> void:
var pet = owned_pets[pet_id]
var rewards = ["coin", "acorn", "small_gem"]
var reward = rewards.pick_random()
var inventory = get_node("/root/InventoryManager")
inventory.add_item(reward, 1)
NotificationManager.toast(
"%s heeft iets gevonden!" % pet.name,
"success"
)
Pet UI
Pet Status Panel
┌─────────────────────────────────────────────────────────────┐
│ ┌────────┐ │
│ │ 🐱 │ Whiskers Bond: ⭐⭐⭐⭐☆ │
│ │ │ Siamese Cat │
│ └────────┘ │
├─────────────────────────────────────────────────────────────┤
│ │
│ Happiness: [████████████████░░░░] 80% │
│ Hunger: [██████░░░░░░░░░░░░░░] 30% │
│ Energy: [██████████████░░░░░░] 70% │
│ │
│ [🍖 Voeren] [🤚 Aaien] [🎾 Spelen] [🎪 Trucs] │
│ │
└─────────────────────────────────────────────────────────────┘
Script
# pet_panel.gd
extends Control
@onready var portrait: TextureRect = $Portrait
@onready var name_label: Label = $NameLabel
@onready var type_label: Label = $TypeLabel
@onready var bond_stars: HBoxContainer = $BondStars
@onready var happiness_bar: ProgressBar = $HappinessBar
@onready var hunger_bar: ProgressBar = $HungerBar
@onready var energy_bar: ProgressBar = $EnergyBar
var current_pet_id: String = ""
func show_pet(pet_id: String) -> void:
current_pet_id = pet_id
var pet = PetManager.owned_pets[pet_id]
# Portrait
var pet_type = PetTypeDatabase.get_pet_type(pet.pet_type)
portrait.texture = load(pet_type.portrait_path.replace("{variant}", pet.variant))
# Info
name_label.text = pet.name
type_label.text = pet_type.display_name
# Bond stars
_update_bond_stars(pet.bond_level)
# Stats
happiness_bar.value = pet.happiness
hunger_bar.value = pet.hunger
energy_bar.value = pet.energy
visible = true
func _update_bond_stars(level: int) -> void:
for i in range(5):
var star = bond_stars.get_child(i)
if i < level / 2:
star.texture = preload("res://assets/ui/star_full.png")
elif i == level / 2 and level % 2 == 1:
star.texture = preload("res://assets/ui/star_half.png")
else:
star.texture = preload("res://assets/ui/star_empty.png")
Pet Volgen
# pet_follower.gd
extends Node2D
@export var pet_id: String = ""
@export var follow_distance: float = 80.0
@export var move_speed: float = 100.0
var target: Node2D = null
var pet_data: PetData = null
@onready var sprite: AnimatedSprite2D = $AnimatedSprite2D
func _ready() -> void:
target = get_tree().get_first_node_in_group("player")
pet_data = PetManager.owned_pets.get(pet_id)
_load_pet_sprite()
func _process(delta: float) -> void:
if not target:
return
var distance = global_position.distance_to(target.global_position)
if distance > follow_distance:
var direction = (target.global_position - global_position).normalized()
global_position += direction * move_speed * delta
# Flip sprite
if direction.x > 0:
sprite.flip_h = false
elif direction.x < 0:
sprite.flip_h = true
sprite.play("walk")
else:
sprite.play("idle")
func play_animation(anim_name: String) -> void:
sprite.play(anim_name)
await sprite.animation_finished
sprite.play("idle")
Pet Type Database
const PET_TYPES = {
"cat": {
"display_name": "Kat",
"variants": ["orange", "black", "white", "siamese"],
"favorite_foods": ["fish", "milk"],
"tricks": [
{"id": "sit", "unlock_level": 1},
{"id": "meow", "unlock_level": 2},
{"id": "purr", "unlock_level": 3},
{"id": "hunt", "unlock_level": 5}
],
"portrait_path": "res://assets/pets/cat/{variant}/portrait.png"
},
"dog": {
"display_name": "Hond",
"variants": ["golden", "brown", "spotted", "black"],
"favorite_foods": ["bone", "meat"],
"tricks": [
{"id": "sit", "unlock_level": 1},
{"id": "bark", "unlock_level": 2},
{"id": "fetch", "unlock_level": 3},
{"id": "roll", "unlock_level": 4},
{"id": "guard", "unlock_level": 6}
]
},
"bunny": {
"display_name": "Konijn",
"variants": ["white", "brown", "spotted"],
"favorite_foods": ["carrot", "lettuce"],
"tricks": [
{"id": "hop", "unlock_level": 1},
{"id": "dig", "unlock_level": 3},
{"id": "binky", "unlock_level": 5}
]
}
}