321 lines
8.7 KiB
JavaScript
321 lines
8.7 KiB
JavaScript
class CameraSystem {
|
|
constructor(scene) {
|
|
this.scene = scene;
|
|
this.camera = scene.cameras.main;
|
|
|
|
// Camera modes
|
|
this.mode = 'follow'; // 'follow', 'free', 'cinematic', 'screenshot'
|
|
|
|
// Free camera controls
|
|
this.freeCamSpeed = 5;
|
|
this.freeCamZoom = 1.0;
|
|
|
|
// Cinematic mode
|
|
this.cinematicPath = [];
|
|
this.cinematicIndex = 0;
|
|
this.cinematicPlaying = false;
|
|
|
|
// Screenshot mode
|
|
this.screenshotMode = false;
|
|
this.uiHidden = false;
|
|
|
|
// Saved camera positions
|
|
this.savedPositions = [];
|
|
|
|
this.setupControls();
|
|
|
|
console.log('📷 CameraSystem: Initialized');
|
|
}
|
|
|
|
setupControls() {
|
|
// F6 - Free Camera Mode
|
|
this.scene.input.keyboard.on('keydown-F6', () => {
|
|
this.toggleFreeCamera();
|
|
});
|
|
|
|
// F7 - Screenshot Mode (hide UI)
|
|
this.scene.input.keyboard.on('keydown-F7', () => {
|
|
this.toggleScreenshotMode();
|
|
});
|
|
|
|
// F8 - Save Camera Position
|
|
this.scene.input.keyboard.on('keydown-F8', () => {
|
|
this.saveCameraPosition();
|
|
});
|
|
|
|
// F9 - Cinematic Mode
|
|
this.scene.input.keyboard.on('keydown-F10', () => {
|
|
this.toggleCinematicMode();
|
|
});
|
|
|
|
// Arrow keys for free camera
|
|
this.cursors = this.scene.input.keyboard.createCursorKeys();
|
|
|
|
// Page Up/Down for zoom
|
|
this.scene.input.keyboard.on('keydown-PAGEUP', () => {
|
|
this.adjustZoom(0.1);
|
|
});
|
|
|
|
this.scene.input.keyboard.on('keydown-PAGEDOWN', () => {
|
|
this.adjustZoom(-0.1);
|
|
});
|
|
}
|
|
|
|
// FREE CAMERA MODE
|
|
toggleFreeCamera() {
|
|
if (this.mode === 'free') {
|
|
this.mode = 'follow';
|
|
this.camera.startFollow(this.scene.player.sprite);
|
|
console.log('📷 Camera: Follow mode');
|
|
} else {
|
|
this.mode = 'free';
|
|
this.camera.stopFollow();
|
|
console.log('📷 Camera: Free mode (Arrow keys to move, PgUp/PgDn to zoom)');
|
|
}
|
|
}
|
|
|
|
updateFreeCamera(delta) {
|
|
if (this.mode !== 'free') return;
|
|
|
|
const speed = this.freeCamSpeed * (delta / 16);
|
|
|
|
if (this.cursors.left.isDown) {
|
|
this.camera.scrollX -= speed;
|
|
}
|
|
if (this.cursors.right.isDown) {
|
|
this.camera.scrollX += speed;
|
|
}
|
|
if (this.cursors.up.isDown) {
|
|
this.camera.scrollY -= speed;
|
|
}
|
|
if (this.cursors.down.isDown) {
|
|
this.camera.scrollY += speed;
|
|
}
|
|
}
|
|
|
|
adjustZoom(delta) {
|
|
this.freeCamZoom = Phaser.Math.Clamp(this.freeCamZoom + delta, 0.3, 3.0);
|
|
this.camera.setZoom(this.freeCamZoom);
|
|
console.log(`📷 Zoom: ${this.freeCamZoom.toFixed(2)}x`);
|
|
}
|
|
|
|
// SCREENSHOT MODE
|
|
toggleScreenshotMode() {
|
|
this.screenshotMode = !this.screenshotMode;
|
|
|
|
const uiScene = this.scene.scene.get('UIScene');
|
|
if (!uiScene) return;
|
|
|
|
if (this.screenshotMode) {
|
|
// Hide all UI
|
|
uiScene.children.list.forEach(child => {
|
|
if (child.setVisible) {
|
|
child.wasVisible = child.visible;
|
|
child.setVisible(false);
|
|
}
|
|
});
|
|
this.uiHidden = true;
|
|
console.log('📷 Screenshot mode: UI hidden (F7 to restore)');
|
|
} else {
|
|
// Restore UI
|
|
uiScene.children.list.forEach(child => {
|
|
if (child.setVisible && child.wasVisible !== undefined) {
|
|
child.setVisible(child.wasVisible);
|
|
}
|
|
});
|
|
this.uiHidden = false;
|
|
console.log('📷 Screenshot mode: UI restored');
|
|
}
|
|
}
|
|
|
|
// SAVE CAMERA POSITION
|
|
saveCameraPosition() {
|
|
const pos = {
|
|
x: this.camera.scrollX,
|
|
y: this.camera.scrollY,
|
|
zoom: this.camera.zoom
|
|
};
|
|
|
|
this.savedPositions.push(pos);
|
|
console.log(`📷 Camera position saved (${this.savedPositions.length}): x=${pos.x.toFixed(0)}, y=${pos.y.toFixed(0)}, zoom=${pos.zoom.toFixed(2)}`);
|
|
}
|
|
|
|
loadCameraPosition(index) {
|
|
if (index < 0 || index >= this.savedPositions.length) return;
|
|
|
|
const pos = this.savedPositions[index];
|
|
|
|
this.scene.tweens.add({
|
|
targets: this.camera,
|
|
scrollX: pos.x,
|
|
scrollY: pos.y,
|
|
zoom: pos.zoom,
|
|
duration: 1000,
|
|
ease: 'Sine.easeInOut'
|
|
});
|
|
|
|
console.log(`📷 Camera position loaded (${index + 1})`);
|
|
}
|
|
|
|
// CINEMATIC MODE
|
|
toggleCinematicMode() {
|
|
if (this.cinematicPlaying) {
|
|
this.stopCinematic();
|
|
} else {
|
|
this.startCinematic();
|
|
}
|
|
}
|
|
|
|
startCinematic() {
|
|
if (this.savedPositions.length < 2) {
|
|
console.log('📷 Need at least 2 saved positions for cinematic!');
|
|
return;
|
|
}
|
|
|
|
this.cinematicPlaying = true;
|
|
this.cinematicIndex = 0;
|
|
this.mode = 'cinematic';
|
|
|
|
this.playCinematicStep();
|
|
|
|
console.log('📷 Cinematic mode: Playing...');
|
|
}
|
|
|
|
playCinematicStep() {
|
|
if (!this.cinematicPlaying) return;
|
|
if (this.cinematicIndex >= this.savedPositions.length) {
|
|
this.stopCinematic();
|
|
return;
|
|
}
|
|
|
|
const pos = this.savedPositions[this.cinematicIndex];
|
|
|
|
this.scene.tweens.add({
|
|
targets: this.camera,
|
|
scrollX: pos.x,
|
|
scrollY: pos.y,
|
|
zoom: pos.zoom,
|
|
duration: 3000,
|
|
ease: 'Sine.easeInOut',
|
|
onComplete: () => {
|
|
this.cinematicIndex++;
|
|
this.scene.time.delayedCall(500, () => {
|
|
this.playCinematicStep();
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
stopCinematic() {
|
|
this.cinematicPlaying = false;
|
|
this.mode = 'follow';
|
|
this.camera.startFollow(this.scene.player.sprite);
|
|
console.log('📷 Cinematic mode: Stopped');
|
|
}
|
|
|
|
// PRESET CAMERA ANGLES
|
|
setPresetAngle(preset) {
|
|
const presets = {
|
|
'overview': { zoom: 0.5, y: -200 },
|
|
'closeup': { zoom: 1.5, y: 0 },
|
|
'wide': { zoom: 0.3, y: -300 },
|
|
'action': { zoom: 1.2, y: -50 }
|
|
};
|
|
|
|
const p = presets[preset];
|
|
if (!p) return;
|
|
|
|
this.scene.tweens.add({
|
|
targets: this.camera,
|
|
zoom: p.zoom,
|
|
scrollY: this.camera.scrollY + p.y,
|
|
duration: 1000,
|
|
ease: 'Sine.easeInOut'
|
|
});
|
|
|
|
console.log(`📷 Preset angle: ${preset}`);
|
|
}
|
|
|
|
// SHAKE EFFECTS
|
|
shake(intensity = 0.005, duration = 200) {
|
|
this.camera.shake(duration, intensity);
|
|
}
|
|
|
|
// FLASH EFFECTS
|
|
flash(color = 0xffffff, duration = 200) {
|
|
this.camera.flash(duration,
|
|
(color >> 16) & 0xff,
|
|
(color >> 8) & 0xff,
|
|
color & 0xff
|
|
);
|
|
}
|
|
|
|
// FADE EFFECTS
|
|
fadeOut(duration = 1000, callback) {
|
|
this.camera.fadeOut(duration, 0, 0, 0);
|
|
if (callback) {
|
|
this.camera.once('camerafadeoutcomplete', callback);
|
|
}
|
|
}
|
|
|
|
fadeIn(duration = 1000, callback) {
|
|
this.camera.fadeIn(duration, 0, 0, 0);
|
|
if (callback) {
|
|
this.camera.once('camerafadeincomplete', callback);
|
|
}
|
|
}
|
|
|
|
// PAN TO LOCATION
|
|
panTo(x, y, duration = 2000) {
|
|
this.scene.tweens.add({
|
|
targets: this.camera,
|
|
scrollX: x - this.camera.width / 2,
|
|
scrollY: y - this.camera.height / 2,
|
|
duration: duration,
|
|
ease: 'Sine.easeInOut'
|
|
});
|
|
}
|
|
|
|
// ZOOM TO
|
|
zoomTo(zoom, duration = 1000) {
|
|
this.scene.tweens.add({
|
|
targets: this.camera,
|
|
zoom: zoom,
|
|
duration: duration,
|
|
ease: 'Sine.easeInOut'
|
|
});
|
|
}
|
|
|
|
// UPDATE
|
|
update(delta) {
|
|
this.updateFreeCamera(delta);
|
|
}
|
|
|
|
// EXPORT CAMERA DATA (for trailer editing)
|
|
exportCameraData() {
|
|
const data = {
|
|
savedPositions: this.savedPositions,
|
|
timestamp: Date.now()
|
|
};
|
|
|
|
const json = JSON.stringify(data, null, 2);
|
|
console.log('📷 Camera data:', json);
|
|
|
|
// Copy to clipboard (if available)
|
|
if (navigator.clipboard) {
|
|
navigator.clipboard.writeText(json);
|
|
console.log('📷 Camera data copied to clipboard!');
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
// IMPORT CAMERA DATA
|
|
importCameraData(data) {
|
|
if (data.savedPositions) {
|
|
this.savedPositions = data.savedPositions;
|
|
console.log(`📷 Imported ${this.savedPositions.length} camera positions`);
|
|
}
|
|
}
|
|
}
|