🐕💙 Animal System & Emotional Memory Implementation

FEATURES:
- Created animals/ folder structure (wild, domestic, infected)
- Implemented proximity-based memory trigger system
- Pulsating heart UI when Kai remembers family dog
- Emotional storytelling without dialogue

NEW FILES:
- src/entities/Animal.js - Animal class with proximity detection
- src/ui/MemoryHeartUI.js - Pulsating heart with Slovenian text
- docs/systems/ANIMAL_MEMORY_SYSTEM.md - Full documentation
- scripts/organize_all_tools.py - Tool organization script

TOOLS ORGANIZATION:
- Moved 84 additional tools to items/tools/
- Final count: 427 tools organized by material tier
  • wood: 36 tools
  • stone: 60 tools
  • iron: 36 tools
  • gold: 36 tools
  • special: 259 tools

GAMESCENE INTEGRATION:
- Added Animal and MemoryHeartUI imports
- Preload heart icon and heartbeat audio
- Update animals each frame for proximity detection
- Example domestic dog spawns at (600, 600)

EMOTIONAL IMPACT:
When Kai approaches a domestic dog, a pulsating heart appears
with text 'Spominjaš se...' (You remember...) - creating a
powerful moment of nostalgia for his lost family pet.
This commit is contained in:
2026-01-20 01:45:03 +01:00
parent e7759433a2
commit 5fb502e7a8
200 changed files with 484 additions and 2 deletions

77
src/entities/Animal.js Normal file
View File

@@ -0,0 +1,77 @@
/**
* 🐕 ANIMAL SYSTEM
* Handles all animal interactions including emotional triggers
*/
class Animal extends Phaser.GameObjects.Sprite {
constructor(scene, x, y, texture, type = 'domestic') {
super(scene, x, y, texture);
this.scene = scene;
this.type = type; // 'wild', 'domestic', 'infected'
// Animal properties
this.animalName = '';
this.isHostile = (type === 'infected' || type === 'wild');
this.triggerMemory = (type === 'domestic'); // Domestic animals trigger memories
// Proximity detection
this.proximityRadius = type === 'domestic' ? 150 : 100;
this.isPlayerNear = false;
// Memory trigger
this.memoryTriggered = false;
// Add to scene
scene.add.existing(this);
scene.physics.add.existing(this);
// Setup physics
this.body.setImmovable(true);
this.body.setCollideWorldBounds(true);
}
update(player) {
if (!player) return;
// Calculate distance to player
const distance = Phaser.Math.Distance.Between(
this.x, this.y,
player.x, player.y
);
const wasNear = this.isPlayerNear;
this.isPlayerNear = distance < this.proximityRadius;
// Trigger memory when player gets close to domestic animal (first time only)
if (this.triggerMemory && this.isPlayerNear && !wasNear && !this.memoryTriggered) {
this.onMemoryTriggered();
}
// Stop memory when player leaves
if (!this.isPlayerNear && wasNear && this.memoryTriggered) {
this.onMemoryEnded();
}
}
onMemoryTriggered() {
console.log(`💙 Kai remembers the family dog...`);
this.memoryTriggered = true;
// Emit event for UI to handle
this.scene.events.emit('animal:memory_triggered', {
animal: this,
type: 'domestic_dog'
});
}
onMemoryEnded() {
console.log(`💔 Memory fades...`);
this.scene.events.emit('animal:memory_ended', {
animal: this
});
}
}
export default Animal;

View File

@@ -1,6 +1,9 @@
// 🎮 GAME SCENE - MEADOW AWAKENING VERSION (Hytale Style)
// "3x Blink to Wake Up + Virus Fog + Hytale UI"
// Updated: January 19, 2026
// "3x Blink to Wake Up + Virus Fog + Hytale UI + Emotional Memories"
// Updated: January 20, 2026
import Animal from '../entities/Animal.js';
import MemoryHeartUI from '../ui/MemoryHeartUI.js';
class GameScene extends Phaser.Scene {
constructor() {
@@ -16,6 +19,18 @@ class GameScene extends Phaser.Scene {
this.blinkCount = 0;
this.isFullyAwake = false;
this.virusFog = null;
// Animal System
this.animals = [];
this.memoryHeartUI = null;
}
preload() {
// Load heart icon for memory UI
this.load.image('heart_icon', 'assets/slike/items/ui/MOJE_SLIKE_KONCNA_ostalo_vmesnik_ikone_heart_icon_style32.png');
// Optional: Load heartbeat sound
this.load.audio('heartbeat', 'assets/audio/_NEW/369017__patobottos__heartbeats-61.wav');
}
create(data) {
@@ -63,6 +78,24 @@ class GameScene extends Phaser.Scene {
// 7. DECORATIONS (Trees, Grass)
this.addStarterCampDecoration(centerX, centerY);
// 8. ANIMAL SYSTEM & MEMORY UI
this.initializeAnimalSystem();
}
initializeAnimalSystem() {
console.log('🐕 Initializing animal system...');
// Create memory heart UI
this.memoryHeartUI = new MemoryHeartUI(this);
// Example: Add a domestic dog near player
// (Replace with actual dog sprite when available)
const dog = new Animal(this, 600, 600, 'kai_idle', 'domestic');
dog.animalName = 'Rex (family dog)';
this.animals.push(dog);
console.log(`✅ Added ${this.animals.length} animals to scene`);
}
update(time, delta) {
@@ -77,6 +110,11 @@ class GameScene extends Phaser.Scene {
// NORMAL MOVEMENT LOGIC
this.handlePlayerMovement();
// UPDATE ANIMALS (proximity detection)
if (this.player && this.animals) {
this.animals.forEach(animal => animal.update(this.player));
}
}
startAmnesiaMode(music) {

156
src/ui/MemoryHeartUI.js Normal file
View File

@@ -0,0 +1,156 @@
/**
* 💙 MEMORY HEART UI
* Displays pulsating heart when Kai remembers family pet
*/
class MemoryHeartUI {
constructor(scene) {
this.scene = scene;
this.container = null;
this.heartIcon = null;
this.isActive = false;
this.createUI();
this.setupEventListeners();
}
createUI() {
const { width, height } = this.scene.cameras.main;
// Container positioned in top-left (near health/stats)
this.container = this.scene.add.container(80, 80);
this.container.setScrollFactor(0);
this.container.setDepth(9000);
this.container.setAlpha(0); // Start invisible
// Heart icon
this.heartIcon = this.scene.add.image(0, 0, 'heart_icon');
this.heartIcon.setScale(0.6);
// Optional: Memory text
this.memoryText = this.scene.add.text(40, 0, '', {
fontFamily: 'Verdana',
fontSize: '16px',
color: '#ff6b9d',
fontStyle: 'italic'
}).setOrigin(0, 0.5);
this.container.add([this.heartIcon, this.memoryText]);
}
setupEventListeners() {
// Listen for memory triggers
this.scene.events.on('animal:memory_triggered', this.show, this);
this.scene.events.on('animal:memory_ended', this.hide, this);
}
show(data) {
if (this.isActive) return;
this.isActive = true;
// Set memory text based on animal
if (data.type === 'domestic_dog') {
this.memoryText.setText('Spominjaš se...');
}
// Fade in container
this.scene.tweens.add({
targets: this.container,
alpha: 1,
duration: 500,
ease: 'Sine.easeIn'
});
// Start pulsating animation
this.startPulsating();
// Optional: Play heartbeat sound
if (this.scene.sound.get('heartbeat')) {
this.scene.sound.play('heartbeat', { volume: 0.3, loop: true });
}
}
hide() {
if (!this.isActive) return;
this.isActive = false;
// Stop pulsating
this.stopPulsating();
// Fade out container
this.scene.tweens.add({
targets: this.container,
alpha: 0,
duration: 800,
ease: 'Sine.easeOut'
});
// Stop heartbeat sound
if (this.scene.sound.get('heartbeat')) {
const heartbeat = this.scene.sound.get('heartbeat');
this.scene.tweens.add({
targets: heartbeat,
volume: 0,
duration: 500,
onComplete: () => {
heartbeat.stop();
}
});
}
}
startPulsating() {
// Gentle pulsating scale animation
this.pulseTween = this.scene.tweens.add({
targets: this.heartIcon,
scale: 0.7,
duration: 800,
yoyo: true,
repeat: -1,
ease: 'Sine.easeInOut'
});
// Subtle glow effect (tint)
this.glowTween = this.scene.tweens.add({
targets: this.heartIcon,
alpha: { from: 0.8, to: 1 },
duration: 600,
yoyo: true,
repeat: -1,
ease: 'Sine.easeInOut'
});
}
stopPulsating() {
if (this.pulseTween) {
this.pulseTween.stop();
this.pulseTween = null;
}
if (this.glowTween) {
this.glowTween.stop();
this.glowTween = null;
}
// Reset to default
this.scene.tweens.add({
targets: this.heartIcon,
scale: 0.6,
alpha: 1,
duration: 300
});
}
destroy() {
this.scene.events.off('animal:memory_triggered', this.show, this);
this.scene.events.off('animal:memory_ended', this.hide, this);
if (this.container) {
this.container.destroy();
}
}
}
export default MemoryHeartUI;