VFX SYSTEM + QUEST MANIFEST - Amnesia blur, Harvest sparkles, Water life, Cinematic transitions - 7 Main quests with ADHD dialogue - ROADMAP updated with VFX and Quest tracking
This commit is contained in:
539
docs/VFX_EFFECTS_SYSTEM.md
Normal file
539
docs/VFX_EFFECTS_SYSTEM.md
Normal file
@@ -0,0 +1,539 @@
|
||||
# 🎬 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**
|
||||
```javascript
|
||||
// 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**
|
||||
```javascript
|
||||
// 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**
|
||||
```javascript
|
||||
// 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/echo
|
||||
- `flashback_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**
|
||||
```javascript
|
||||
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:
|
||||
```javascript
|
||||
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" sound
|
||||
- `sparkle_ting.mp3` - Optional twinkle sound
|
||||
|
||||
### **Visual Assets Needed:**
|
||||
- `sparkle_star.png` - 8x8px star particle
|
||||
- `glow_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:**
|
||||
```javascript
|
||||
// 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:**
|
||||
```javascript
|
||||
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 sound
|
||||
- `fish_jump.mp3` - Optional fish "plop"
|
||||
|
||||
### **Visual Assets Needed:**
|
||||
- `fish_jump.png` - 16x16px fish mid-jump (Style 32)
|
||||
- `water_drop.png` - 4x4px water droplet particle
|
||||
- `ripple.png` - 32x32px circular ripple ring
|
||||
|
||||
---
|
||||
|
||||
## 🎥 **4. DYNAMIC VISUALS (Cutscenes & Story Moments)**
|
||||
|
||||
### **Cross-Fade Transitions:**
|
||||
|
||||
```javascript
|
||||
// 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):**
|
||||
|
||||
```javascript
|
||||
// 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):**
|
||||
|
||||
```javascript
|
||||
// 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):**
|
||||
|
||||
```javascript
|
||||
// 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:**
|
||||
|
||||
```javascript
|
||||
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:**
|
||||
```javascript
|
||||
// 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:**
|
||||
```javascript
|
||||
// Phaser 3 built-in post-processing
|
||||
scene.cameras.main.setPostPipeline('BlurPostFX');
|
||||
scene.cameras.main.setPostPipeline('VignettePostFX');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎬 **CUTSCENE SYSTEM**
|
||||
|
||||
### **Simple Dialogue + VFX:**
|
||||
```javascript
|
||||
// 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 star
|
||||
- `glow_particle.png` - 4x4px white glow
|
||||
- `smoke_puff.png` - 16x16px gray smoke
|
||||
- `water_drop.png` - 4x4px blue droplet
|
||||
- `blood_splat.png` - 8x8px green splat (zombie blood)
|
||||
- `coin_spin.png` - 8x8px gold coin
|
||||
|
||||
### **VFX Animations:**
|
||||
- `fish_jump.png` - 16x16px fish sprite
|
||||
- `ripple.png` - 32x32px water ripple ring
|
||||
|
||||
### **Audio:**
|
||||
- `memory_echo.mp3`
|
||||
- `flashback_theme.mp3`
|
||||
- `ana_voice_01.mp3` through `ana_voice_10.mp3`
|
||||
- `harvest_pop.mp3`
|
||||
- `sparkle_ting.mp3`
|
||||
- `water_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!
|
||||
Reference in New Issue
Block a user