12 KiB
🎬 VFX & INTERACTIVE EFFECTS SYSTEM
Project: Mrtva Dolina
Purpose: Visual feedback, emotional storytelling, player satisfaction
Style: ADHD-friendly, instant feedback, satisfying
✨ 1. AMNESIA EFFECT (Kai's Memory System)
Concept:
When Kai finds family heirlooms or Ana's belongings, trigger a blur-to-clear memory flashback with audio cues.
Visual Effect:
Stage 1: Discovery
// Player finds item (photo, Ana's necklace, family object)
onItemFound(familyItem) {
// Show blurred image overlay
showImage({
src: familyItem.memoryImage,
blur: 20, // Heavy gaussian blur
opacity: 0.8,
fadeIn: 500ms
});
// Play mysterious sound
playSound('memory_echo.mp3', volume: 0.5);
// Show prompt: "E - Remember" (simple text)
showPrompt("Pritisni E za spomin");
}
Stage 2: Memory Restoration
// Player presses E to "remember"
onRememberPressed() {
// Blur clears gradually (2 seconds)
animateBlur({
from: 20,
to: 0,
duration: 2000ms,
easing: 'easeOut'
});
// Play Ana's voice (short clip)
playVoice('ana_flashback_01.mp3');
// Example: "Kai, pomnš tisti dan...?" (short, 2-3 sec)
// OR play emotional music sting
playMusic('flashback_theme.mp3', fadeIn: 500ms);
// Show caption (simple text)
showCaption({
text: "Spomin odklenjn...", // ADHD-friendly: simple, typo intentional for domestic feel
duration: 3000ms,
color: '#FFD700' // Gold
});
// Update quest log
questLog.add('family_memory_' + itemID);
}
Stage 3: Reward
// After memory clears:
- Unlock new location on map (e.g., Capital City)
- Add clue to Ana's trail counter (X/50)
- Small stat boost (Hope +5%)
- Journal entry auto-saved
Audio Assets Needed:
memory_echo.mp3- Mysterious hum/echoflashback_theme.mp3- Short emotional music (10-15 sec)ana_voice_01-10.mp3- 10 short voice clips from Ana
Visual Assets Needed:
- Family photo (blurred + clear versions)
- Ana's necklace (blurred + clear)
- Old diary page (blurred + clear)
- Kai's childhood toy (blurred + clear)
🌾 2. HARVESTING VFX (Stardew Valley Style)
Concept:
When player harvests crops, items bounce up with sparkles and fly into inventory. Instant satisfaction feedback.
Animation Sequence:
Step 1: Harvest Action
onCropHarvested(cropTile) {
// 1. Crop disappears from tile
cropTile.sprite.fadeOut(200ms);
// 2. Item sprite bounces UP
let itemSprite = createSprite(crop.harvestedItem);
itemSprite.position = cropTile.position;
// Bounce animation (arc trajectory)
itemSprite.animate({
y: cropTile.y - 40, // Jump up 40px
duration: 300ms,
easing: 'easeOutQuad'
});
// 3. Sparkle particles
emitParticles({
position: cropTile.position,
count: 8,
sprite: 'sparkle_star.png',
color: '#FFD700', // Gold sparkles
velocity: random(-50, 50),
lifetime: 800ms,
fadeOut: true
});
// 4. Sound effect
playSound('harvest_pop.mp3', volume: 0.7);
// Happy "pop" or "ding" sound
// 5. Fly to inventory (UI corner)
itemSprite.animate({
x: inventoryIcon.x,
y: inventoryIcon.y,
duration: 600ms,
easing: 'easeInQuad',
onComplete: () => {
// Add to inventory
inventory.add(crop.harvestedItem);
itemSprite.destroy();
// Inventory icon pulse
inventoryIcon.pulse();
}
});
}
Optional: Quality Tier Effects
Different sparkle colors for quality:
qualityColors = {
basic: '#FFFFFF', // White sparkles
silver: '#C0C0C0', // Silver sparkles
gold: '#FFD700', // Gold sparkles
iridium: '#9D00FF' // Purple sparkles (legendary)
}
Audio Assets Needed:
harvest_pop.mp3- Satisfying "pop" soundsparkle_ting.mp3- Optional twinkle sound
Visual Assets Needed:
sparkle_star.png- 8x8px star particleglow_particle.png- 4x4px glow dot
🐟 3. WATER LIFE (Fish Jump Animation)
Concept:
Fish occasionally jump out of water with splash effect. Visual hint for good fishing spots.
Animation Sequence:
Random Fish Jump:
// Every 5-15 seconds at fishing spots
setInterval(() => {
if (Math.random() < 0.3) { // 30% chance
spawnFishJump();
}
}, randomRange(5000, 15000));
function spawnFishJump() {
let waterTile = getRandomWaterTile();
// 1. Fish sprite jumps out
let fish = createSprite('fish_jump.png', waterTile.position);
fish.animate({
// Arc jump animation
keyframes: [
{ y: waterTile.y, time: 0 },
{ y: waterTile.y - 32, time: 300 }, // Peak of jump
{ y: waterTile.y, time: 600 } // Back to water
],
rotation: [0, 180, 360], // Flip in air
easing: 'easeInOutQuad'
});
// 2. Splash effect (start + end)
createSplash(waterTile.position, scale: 1.0);
setTimeout(() => {
createSplash(waterTile.position, scale: 1.2); // Bigger splash on landing
fish.destroy();
}, 600);
// 3. Sound effect
playSound('water_splash.mp3', volume: 0.6);
// 4. Ripple effect
createRipple(waterTile.position, {
radius: [0, 48],
duration: 1000ms,
opacity: [0.8, 0]
});
}
Splash Particle Effect:
function createSplash(position, scale) {
emitParticles({
position: position,
count: 12,
sprite: 'water_drop.png',
color: '#4DB8FF', // Water blue
velocity: randomRange(-80, 80),
gravity: 200, // Drops fall down
lifetime: 500ms,
scale: scale,
rotation: random(0, 360)
});
}
Gameplay Integration:
- Fish jump frequency indicates fish abundance
- More jumps = better fishing spot
- Rare fish have unique jump animations (golden sparkle)
Audio Assets Needed:
water_splash.mp3- Splash soundfish_jump.mp3- Optional fish "plop"
Visual Assets Needed:
fish_jump.png- 16x16px fish mid-jump (Style 32)water_drop.png- 4x4px water droplet particleripple.png- 32x32px circular ripple ring
🎥 4. DYNAMIC VISUALS (Cutscenes & Story Moments)
Cross-Fade Transitions:
// Scene transitions (smooth, cinematic)
function transitionScene(fromScene, toScene) {
// Fade out current scene
fromScene.fadeOut({
duration: 1000ms,
color: '#000000' // Fade to black
});
// Wait for fade
setTimeout(() => {
// Switch scenes
game.scene.stop(fromScene);
game.scene.start(toScene);
// Fade in new scene
toScene.fadeIn({
duration: 1000ms
});
}, 1000);
}
Vignette Effect (Important Moments):
// Adds dark edge vignette for dramatic moments
function applyVignette(intensity = 0.5) {
let vignetteShader = {
type: 'radialGradient',
center: [screenWidth/2, screenHeight/2],
radius: screenWidth * 0.6,
colors: [
{ offset: 0, color: 'rgba(0,0,0,0)' },
{ offset: 1, color: `rgba(0,0,0,${intensity})` }
]
};
camera.applyPostFXShader(vignetteShader);
}
// Use during:
- Intro sequence (heavy vignette)
- Ana clue discoveries (medium vignette)
- Boss fights (light vignette)
- Emotional cutscenes (heavy vignette)
Blur Effect (Dream/Memory Sequences):
// Full-screen blur for dream states
function applyDreamBlur() {
camera.applyPostFXShader({
type: 'gaussianBlur',
strength: 8,
quality: 'medium'
});
// Desaturate colors slightly
camera.applyColorMatrix({
saturation: 0.5, // 50% saturation
brightness: 1.1 // Slightly brighter
});
}
Slow-Motion Effect (Epic Moments):
// Slow-motion for dramatic moments
function applySlowMotion(duration = 2000, speed = 0.3) {
game.time.timeScale = speed; // 30% speed
setTimeout(() => {
// Return to normal speed
tweenValue(game.time.timeScale, 1.0, {
duration: 500ms,
easing: 'easeOut'
});
}, duration);
// Optional: Add motion blur
camera.applyMotionBlur(strength: 0.5);
}
// Use during:
- Boss defeated moment
- Ana rescue cutscene
- Major discovery moments
🎨 PARTICLE SYSTEM LIBRARY
Reusable Particle Effects:
particlePresets = {
// Sparkle (harvest, treasure)
sparkle: {
sprite: 'sparkle_star.png',
count: 8,
color: '#FFD700',
velocity: random(-50, 50),
lifetime: 800ms,
fadeOut: true
},
// Smoke (campfire, forge)
smoke: {
sprite: 'smoke_puff.png',
count: 3,
color: '#888888',
velocity: { x: random(-10, 10), y: -30 },
lifetime: 2000ms,
fadeOut: true,
scaleUp: true
},
// Magic (enchanting, portals)
magic: {
sprite: 'glow_particle.png',
count: 20,
color: '#9D00FF', // Purple
velocity: spiral(radius: 40, speed: 2),
lifetime: 1500ms,
fadeOut: true,
glow: true
},
// Blood (combat - optional, can be green "zombie goo")
blood: {
sprite: 'blood_splat.png',
count: 6,
color: '#00FF00', // Green (zombie blood)
velocity: random(-60, 60),
gravity: 150,
lifetime: 800ms,
fadeOut: true
},
// Coins (quest rewards, sales)
coins: {
sprite: 'coin_spin.png',
count: 10,
color: '#FFD700',
velocity: { x: random(-40, 40), y: -80 },
gravity: 200,
lifetime: 1200ms,
rotation: true,
bounce: true
}
}
📊 VFX IMPLEMENTATION PRIORITY
| Effect | Priority | Complexity | Impact |
|---|---|---|---|
| Harvest Sparkles | ⭐⭐⭐⭐⭐ | Low | High satisfaction |
| Amnesia Blur | ⭐⭐⭐⭐⭐ | Medium | Emotional storytelling |
| Fish Jump | ⭐⭐⭐⭐ | Low | World feels alive |
| Cross-Fade | ⭐⭐⭐⭐ | Low | Professional polish |
| Vignette | ⭐⭐⭐ | Low | Dramatic moments |
| Slow-Motion | ⭐⭐ | Medium | Epic boss moments |
🎯 PHASER 3 IMPLEMENTATION NOTES
Particle Manager:
// src/systems/ParticleManager.js
class ParticleManager {
constructor(scene) {
this.scene = scene;
this.emitters = {};
}
emit(preset, position, customParams = {}) {
let params = { ...particlePresets[preset], ...customParams };
let emitter = this.scene.add.particles(position.x, position.y, params.sprite, params);
return emitter;
}
sparkle(position) {
return this.emit('sparkle', position);
}
smoke(position) {
return this.emit('smoke', position);
}
magic(position) {
return this.emit('magic', position);
}
}
Post-FX Pipeline:
// Phaser 3 built-in post-processing
scene.cameras.main.setPostPipeline('BlurPostFX');
scene.cameras.main.setPostPipeline('VignettePostFX');
🎬 CUTSCENE SYSTEM
Simple Dialogue + VFX:
// src/systems/CutsceneManager.js
class CutsceneManager {
playMemoryFlashback(memoryData) {
// 1. Freeze player
player.freeze();
// 2. Apply vignette
applyVignette(0.7);
// 3. Show blurred image
showBlurredImage(memoryData.image);
// 4. Play Ana's voice
playVoice(memoryData.audioClip);
// 5. Clear blur after 2 seconds
setTimeout(() => {
clearBlur(duration: 2000ms);
}, 2000);
// 6. Show dialogue
setTimeout(() => {
showDialogue({
text: memoryData.caption,
speaker: "Ana",
duration: 4000ms
});
}, 4000);
// 7. Resume game
setTimeout(() => {
removeVignette();
player.unfreeze();
}, 8000);
}
}
🚀 ASSETS TO GENERATE
Particle Sprites:
sparkle_star.png- 8x8px gold starglow_particle.png- 4x4px white glowsmoke_puff.png- 16x16px gray smokewater_drop.png- 4x4px blue dropletblood_splat.png- 8x8px green splat (zombie blood)coin_spin.png- 8x8px gold coin
VFX Animations:
fish_jump.png- 16x16px fish spriteripple.png- 32x32px water ripple ring
Audio:
memory_echo.mp3flashback_theme.mp3ana_voice_01.mp3throughana_voice_10.mp3harvest_pop.mp3sparkle_ting.mp3water_splash.mp3
Status: 🟢 READY FOR IMPLEMENTATION
Estimated Time: 6-8 hours coding + 2 hours audio/visual assets
Emotional Impact: 🚀 MASSIVE - Game feels alive and responsive!