shrani
This commit is contained in:
444
docs/design/ADVANCED_CAMERA_PLAN.md
Normal file
444
docs/design/ADVANCED_CAMERA_PLAN.md
Normal file
@@ -0,0 +1,444 @@
|
||||
# 🎬 ADVANCED CAMERA FEATURES - IMPLEMENTATION PLAN
|
||||
|
||||
**Datum:** 12. December 2025
|
||||
**Prioriteta:** MEDIUM
|
||||
**Estimated Time:** 2-3 ure
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **CILJI:**
|
||||
|
||||
Razširitev Camera System z naprednimi funkcionalnostmi za profesionalne trailerje:
|
||||
- Smooth camera movement (Bezier curves)
|
||||
- Recording Mode (UI hide, slow-mo)
|
||||
- Cinematic Sequences (pre-made cutscenes)
|
||||
- Demo Recording (60s gameplay loops)
|
||||
|
||||
---
|
||||
|
||||
## 📋 **FAZA 1: SMOOTH CAMERA MOVEMENT** (45 min)
|
||||
|
||||
### **1.1 Bezier Curve Paths**
|
||||
**Dodaj v CameraSystem.js:**
|
||||
|
||||
```javascript
|
||||
// Bezier curve camera path
|
||||
createBezierPath(points, duration = 5000) {
|
||||
// points = [{ x, y, zoom }, { x, y, zoom }, ...]
|
||||
|
||||
const path = new Phaser.Curves.Spline(points.map(p => [p.x, p.y]));
|
||||
|
||||
let progress = 0;
|
||||
const tween = this.scene.tweens.add({
|
||||
targets: { t: 0 },
|
||||
t: 1,
|
||||
duration: duration,
|
||||
ease: 'Sine.easeInOut',
|
||||
onUpdate: (tween) => {
|
||||
const t = tween.getValue();
|
||||
const point = path.getPoint(t);
|
||||
|
||||
// Interpolate zoom
|
||||
const zoomIndex = Math.floor(t * (points.length - 1));
|
||||
const zoomT = (t * (points.length - 1)) - zoomIndex;
|
||||
const zoom = Phaser.Math.Linear(
|
||||
points[zoomIndex].zoom,
|
||||
points[Math.min(zoomIndex + 1, points.length - 1)].zoom,
|
||||
zoomT
|
||||
);
|
||||
|
||||
this.camera.scrollX = point.x - this.camera.width / 2;
|
||||
this.camera.scrollY = point.y - this.camera.height / 2;
|
||||
this.camera.setZoom(zoom);
|
||||
}
|
||||
});
|
||||
|
||||
return tween;
|
||||
}
|
||||
|
||||
// Example usage:
|
||||
// cameraSystem.createBezierPath([
|
||||
// { x: 100, y: 100, zoom: 1.0 },
|
||||
// { x: 200, y: 150, zoom: 1.5 },
|
||||
// { x: 300, y: 100, zoom: 1.0 }
|
||||
// ], 5000);
|
||||
```
|
||||
|
||||
### **1.2 Cinematic Zoom Controls**
|
||||
```javascript
|
||||
cinematicZoom(targetZoom, duration = 2000, ease = 'Sine.easeInOut') {
|
||||
return this.scene.tweens.add({
|
||||
targets: this.camera,
|
||||
zoom: targetZoom,
|
||||
duration: duration,
|
||||
ease: ease
|
||||
});
|
||||
}
|
||||
|
||||
// Zoom presets
|
||||
zoomPresets = {
|
||||
'extreme_closeup': 2.5,
|
||||
'closeup': 1.8,
|
||||
'medium': 1.2,
|
||||
'wide': 0.8,
|
||||
'extreme_wide': 0.4
|
||||
};
|
||||
|
||||
applyZoomPreset(preset) {
|
||||
const zoom = this.zoomPresets[preset];
|
||||
if (zoom) {
|
||||
this.cinematicZoom(zoom);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### **1.3 Camera Shake Intensity Controls**
|
||||
```javascript
|
||||
cinematicShake(intensity = 'medium', duration = 500) {
|
||||
const intensities = {
|
||||
'subtle': 0.002,
|
||||
'medium': 0.005,
|
||||
'strong': 0.01,
|
||||
'extreme': 0.02
|
||||
};
|
||||
|
||||
const value = intensities[intensity] || intensities.medium;
|
||||
this.camera.shake(duration, value);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 **FAZA 2: RECORDING MODE** (30 min)
|
||||
|
||||
### **2.1 Hide UI Toggle (F4)**
|
||||
**Že implementirano kot F7!** ✅
|
||||
|
||||
### **2.2 Free Camera Mode (noclip)**
|
||||
**Že implementirano kot F6!** ✅
|
||||
|
||||
### **2.3 Time Slow-Mo**
|
||||
```javascript
|
||||
setTimeScale(scale) {
|
||||
// scale: 1.0 = normal, 0.5 = half speed, 0.25 = quarter speed
|
||||
this.scene.time.timeScale = scale;
|
||||
|
||||
// Also affect physics
|
||||
if (this.scene.physics && this.scene.physics.world) {
|
||||
this.scene.physics.world.timeScale = scale;
|
||||
}
|
||||
|
||||
console.log(`⏱️ Time scale: ${scale}x`);
|
||||
}
|
||||
|
||||
// Keyboard shortcuts
|
||||
// F11 - Slow-mo 0.5x
|
||||
// F12 - Slow-mo 0.25x
|
||||
// Shift+F12 - Normal speed
|
||||
```
|
||||
|
||||
### **2.4 Screenshot Mode (High-Res)**
|
||||
```javascript
|
||||
captureHighResScreenshot(scale = 2) {
|
||||
// Temporarily increase resolution
|
||||
const originalZoom = this.camera.zoom;
|
||||
this.camera.setZoom(originalZoom * scale);
|
||||
|
||||
// Capture after next frame
|
||||
this.scene.time.delayedCall(100, () => {
|
||||
this.scene.game.renderer.snapshot((image) => {
|
||||
// Download image
|
||||
const link = document.createElement('a');
|
||||
link.download = `novafarma_${Date.now()}.png`;
|
||||
link.href = image.src;
|
||||
link.click();
|
||||
|
||||
console.log('📸 High-res screenshot captured!');
|
||||
});
|
||||
|
||||
// Restore zoom
|
||||
this.camera.setZoom(originalZoom);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 **FAZA 3: CINEMATIC SEQUENCES** (60 min)
|
||||
|
||||
### **3.1 Intro Cutscene (Farm Arrival)**
|
||||
```javascript
|
||||
playIntroCutscene() {
|
||||
console.log('🎬 Playing intro cutscene...');
|
||||
|
||||
// Hide UI
|
||||
this.toggleScreenshotMode();
|
||||
|
||||
// Sequence
|
||||
const sequence = [
|
||||
// 1. Fade in from black
|
||||
() => this.fadeIn(2000),
|
||||
|
||||
// 2. Wide shot of farm (3 seconds)
|
||||
() => {
|
||||
this.panTo(400, 400, 2000);
|
||||
this.zoomTo(0.5, 2000);
|
||||
},
|
||||
|
||||
// 3. Zoom to player (2 seconds)
|
||||
() => {
|
||||
this.panTo(this.scene.player.sprite.x, this.scene.player.sprite.y, 2000);
|
||||
this.zoomTo(1.2, 2000);
|
||||
},
|
||||
|
||||
// 4. Follow player
|
||||
() => {
|
||||
this.mode = 'follow';
|
||||
this.camera.startFollow(this.scene.player.sprite);
|
||||
this.toggleScreenshotMode(); // Restore UI
|
||||
}
|
||||
];
|
||||
|
||||
this.playSequence(sequence, [0, 3000, 5000, 7000]);
|
||||
}
|
||||
|
||||
playSequence(actions, timings) {
|
||||
actions.forEach((action, i) => {
|
||||
this.scene.time.delayedCall(timings[i], action);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### **3.2 Boss Encounter Intro**
|
||||
```javascript
|
||||
playBossIntroCutscene(bossX, bossY) {
|
||||
const sequence = [
|
||||
// Dramatic zoom out
|
||||
() => this.zoomTo(0.3, 1000),
|
||||
|
||||
// Pan to boss
|
||||
() => this.panTo(bossX, bossY, 2000),
|
||||
|
||||
// Zoom to boss face
|
||||
() => this.zoomTo(1.5, 1500),
|
||||
|
||||
// Shake
|
||||
() => this.cinematicShake('strong', 500),
|
||||
|
||||
// Flash red
|
||||
() => this.flash(0xff0000, 300),
|
||||
|
||||
// Return to player
|
||||
() => {
|
||||
this.panTo(this.scene.player.sprite.x, this.scene.player.sprite.y, 1500);
|
||||
this.zoomTo(1.0, 1500);
|
||||
}
|
||||
];
|
||||
|
||||
this.playSequence(sequence, [0, 1000, 3000, 4500, 5000, 5500]);
|
||||
}
|
||||
```
|
||||
|
||||
### **3.3 Day/Night Transition Showcase**
|
||||
```javascript
|
||||
playDayNightShowcase() {
|
||||
// Speed up time temporarily
|
||||
const originalTimeScale = this.scene.timeSystem.timeScale;
|
||||
this.scene.timeSystem.timeScale = 10.0; // 10x speed
|
||||
|
||||
// Wide shot
|
||||
this.zoomTo(0.6, 2000);
|
||||
|
||||
// Wait for full day/night cycle
|
||||
this.scene.time.delayedCall(12000, () => {
|
||||
// Restore time
|
||||
this.scene.timeSystem.timeScale = originalTimeScale;
|
||||
this.zoomTo(1.0, 2000);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### **3.4 Season Change Sequence**
|
||||
```javascript
|
||||
playSeasonShowcase() {
|
||||
// Cycle through seasons
|
||||
const seasons = ['spring', 'summer', 'autumn', 'winter'];
|
||||
|
||||
seasons.forEach((season, i) => {
|
||||
this.scene.time.delayedCall(i * 3000, () => {
|
||||
if (this.scene.weatherSystem) {
|
||||
this.scene.weatherSystem.setSeason(season);
|
||||
}
|
||||
|
||||
// Flash transition
|
||||
this.flash(0xffffff, 500);
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 **FAZA 4: DEMO RECORDING** (45 min)
|
||||
|
||||
### **4.1 60-Second Gameplay Loop**
|
||||
```javascript
|
||||
recordGameplayLoop() {
|
||||
console.log('🎥 Recording 60-second gameplay loop...');
|
||||
|
||||
const script = [
|
||||
// 0-10s: Farming
|
||||
{ time: 0, action: () => this.showcaseFarming() },
|
||||
|
||||
// 10-20s: Building
|
||||
{ time: 10000, action: () => this.showcaseBuilding() },
|
||||
|
||||
// 20-30s: Combat
|
||||
{ time: 20000, action: () => this.showcaseCombat() },
|
||||
|
||||
// 30-40s: Crafting
|
||||
{ time: 30000, action: () => this.showcaseCrafting() },
|
||||
|
||||
// 40-50s: NPCs
|
||||
{ time: 40000, action: () => this.showcaseNPCs() },
|
||||
|
||||
// 50-60s: Day/Night
|
||||
{ time: 50000, action: () => this.playDayNightShowcase() }
|
||||
];
|
||||
|
||||
script.forEach(({ time, action }) => {
|
||||
this.scene.time.delayedCall(time, action);
|
||||
});
|
||||
}
|
||||
|
||||
showcaseFarming() {
|
||||
// Pan to farm area
|
||||
this.panTo(400, 400, 2000);
|
||||
this.zoomTo(1.2, 2000);
|
||||
|
||||
// Simulate farming actions
|
||||
// (Player would do this manually or via AI)
|
||||
}
|
||||
|
||||
showcaseBuilding() {
|
||||
// Show building mode
|
||||
if (this.scene.buildSystem) {
|
||||
this.scene.buildSystem.toggleBuildMode();
|
||||
}
|
||||
}
|
||||
|
||||
showcaseCombat() {
|
||||
// Spawn enemy for demo
|
||||
// Show combat
|
||||
}
|
||||
|
||||
showcaseCrafting() {
|
||||
// Open crafting menu
|
||||
const uiScene = this.scene.scene.get('UIScene');
|
||||
if (uiScene) {
|
||||
uiScene.toggleCraftingMenu();
|
||||
}
|
||||
}
|
||||
|
||||
showcaseNPCs() {
|
||||
// Pan to NPCs
|
||||
if (this.scene.npcs && this.scene.npcs.length > 0) {
|
||||
const npc = this.scene.npcs[0];
|
||||
this.panTo(npc.sprite.x, npc.sprite.y, 2000);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 **KEYBOARD SHORTCUTS:**
|
||||
|
||||
```
|
||||
F6 - Free Camera Mode
|
||||
F7 - Screenshot Mode (Hide UI)
|
||||
F8 - Save Camera Position
|
||||
F10 - Cinematic Mode
|
||||
F11 - Slow-mo 0.5x
|
||||
F12 - Slow-mo 0.25x
|
||||
Shift+F12 - Normal speed
|
||||
Ctrl+S - High-res screenshot
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 **INTEGRATION:**
|
||||
|
||||
**GameScene.js:**
|
||||
```javascript
|
||||
// In create():
|
||||
this.cameraSystem = new CameraSystem(this);
|
||||
|
||||
// In update():
|
||||
if (this.cameraSystem) {
|
||||
this.cameraSystem.update(delta);
|
||||
}
|
||||
|
||||
// Keyboard shortcuts:
|
||||
this.input.keyboard.on('keydown-F11', () => {
|
||||
this.cameraSystem.setTimeScale(0.5);
|
||||
});
|
||||
|
||||
this.input.keyboard.on('keydown-F12', () => {
|
||||
this.cameraSystem.setTimeScale(0.25);
|
||||
});
|
||||
|
||||
this.input.keyboard.on('keydown', (event) => {
|
||||
if (event.shiftKey && event.key === 'F12') {
|
||||
this.cameraSystem.setTimeScale(1.0);
|
||||
}
|
||||
if (event.ctrlKey && event.key === 's') {
|
||||
event.preventDefault();
|
||||
this.cameraSystem.captureHighResScreenshot();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 **IMPLEMENTATION STEPS:**
|
||||
|
||||
1. **Razširi CameraSystem.js** (45 min)
|
||||
- Bezier curves
|
||||
- Cinematic zoom
|
||||
- Shake controls
|
||||
|
||||
2. **Dodaj Recording Mode** (30 min)
|
||||
- Time slow-mo
|
||||
- High-res screenshots
|
||||
|
||||
3. **Ustvari Cinematic Sequences** (60 min)
|
||||
- Intro cutscene
|
||||
- Boss intro
|
||||
- Day/night showcase
|
||||
- Season showcase
|
||||
|
||||
4. **Implementiraj Demo Recording** (45 min)
|
||||
- 60s gameplay loop
|
||||
- Feature showcases
|
||||
|
||||
5. **Integration \u0026 Testing** (30 min)
|
||||
|
||||
**Total:** 3h 30min
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **PRIORITETA:**
|
||||
|
||||
**MEDIUM** - Pomembno za marketing, ampak ne kritično za gameplay.
|
||||
|
||||
**Priporočam:** Implementacija po dokončanju core funkcionalnosti.
|
||||
|
||||
---
|
||||
|
||||
**Status:** ⏳ **PLAN PRIPRAVLJEN**
|
||||
|
||||
**CameraSystem.js že obstaja** - samo razširitev potrebna!
|
||||
|
||||
**Estimated time:** 3h 30min
|
||||
|
||||
Želite implementacijo zdaj ali kasneje? 🎬
|
||||
Reference in New Issue
Block a user