diff --git a/kittyurl-frontend/src/components/FlappyCat.tsx b/kittyurl-frontend/src/components/FlappyCat.tsx index 6114196..be8552c 100644 --- a/kittyurl-frontend/src/components/FlappyCat.tsx +++ b/kittyurl-frontend/src/components/FlappyCat.tsx @@ -1,12 +1,46 @@ import React, { useState, useEffect, useRef, useCallback } from 'react'; import { ArrowLeft, Trophy, Sparkles } from 'lucide-react'; -import { DetailedKitty } from './DetailedKitty'; -// --- STAŁE KONFIGURACYJNE (Wartości na sekundę) --- +// --- MODEL KOTA --- +interface DetailedKittyProps { + isGameOver: boolean; +} + +const DetailedKitty: React.FC = ({ isGameOver }) => { + const mainColor = isGameOver ? '#cbd5e1' : '#f472b6'; + const stripeColor = '#ec4899'; + const earColor = '#fbcfe8'; + + return ( +
+
+
+
+
+
+
+
+
+
+
+
+
+ {isGameOver ? 'x' :
} +
+
+ {isGameOver ? 'x' :
} +
+
+
+
+ ); +}; + +// --- KONFIGURACJA --- const GAP_SIZE = 170; const PIPE_WIDTH = 70; const PIPE_SPEED = 250; // px/s -const PIPE_SPAWN_RATE = 1.5; // Sekundy +const PIPE_SPAWN_RATE = 1.5; // sekundy const GRAVITY = 1600; // px/s^2 const FLAP_STRENGTH = -450; // px/s const CANVAS_HEIGHT = 450; @@ -24,7 +58,6 @@ export const FlappyCat: React.FC<{ onBack: () => void }> = ({ onBack }) => { const [displayPipes, setDisplayPipes] = useState<{ x: number; topHeight: number; id: number }[]>([]); const [rotation, setRotation] = useState(0); - // Referencje do fizyki i czasu const kittyYRef = useRef(150); const velocityRef = useRef(0); const pipesRef = useRef<{ x: number; topHeight: number; id: number; passed?: boolean }[]>([]); @@ -67,28 +100,19 @@ export const FlappyCat: React.FC<{ onBack: () => void }> = ({ onBack }) => { const update = (currentTime: number) => { if (gameOver || !isPlaying) return; - // 1. Obliczanie Delta Time const dt = (currentTime - lastTimeRef.current) / 1000; lastTimeRef.current = currentTime; - - // Zabezpieczenie przed "skokami" przy lagach (max 100ms) const frameTime = Math.min(dt, 0.1); - // 2. Fizyka Kota velocityRef.current += GRAVITY * frameTime; kittyYRef.current += velocityRef.current * frameTime; + setRotation(Math.min(Math.max(velocityRef.current * 0.15, -20), 90)); - // Wizualny obrót (od -20 stopni przy locie w górę do 90 przy spadaniu) - const targetRotation = Math.min(Math.max(velocityRef.current * 0.15, -20), 90); - setRotation(targetRotation); - - // 3. Kolizja z granicami ekranu if (kittyYRef.current > CANVAS_HEIGHT - 40 || kittyYRef.current < -20) { endGame(); return; } - // 4. Zarządzanie Rurami (Spawning) spawnTimerRef.current += frameTime; if (spawnTimerRef.current >= PIPE_SPAWN_RATE) { const topHeight = Math.random() * (220 - 70) + 70; @@ -96,13 +120,11 @@ export const FlappyCat: React.FC<{ onBack: () => void }> = ({ onBack }) => { spawnTimerRef.current = 0; } - // 5. Ruch rur i Kolizje const updatedPipes = []; - for (let p of pipesRef.current) { + // POPRAWKA: użycie 'const p' zamiast 'let p' + for (const p of pipesRef.current) { p.x -= PIPE_SPEED * frameTime; - // Sprawdzanie kolizji - // Kitty X jest stałe na ok. 50-90px. Kot ma szerokość ok. 40px w uproszczeniu kolizyjnym. if (p.x < 100 && p.x + PIPE_WIDTH > 50) { if (kittyYRef.current < p.topHeight || kittyYRef.current > p.topHeight + GAP_SIZE - 45) { endGame(); @@ -110,24 +132,20 @@ export const FlappyCat: React.FC<{ onBack: () => void }> = ({ onBack }) => { } } - // Punktacja if (p.x < 50 && !p.passed) { p.passed = true; scoreRef.current += 1; setScore(scoreRef.current); } - // Usuwanie rur poza ekranem if (p.x > -PIPE_WIDTH) { updatedPipes.push(p); } } pipesRef.current = updatedPipes; - // 6. Sync UI setDisplayKittyY(kittyYRef.current); setDisplayPipes([...pipesRef.current]); - requestRef.current = requestAnimationFrame(update); }; @@ -158,60 +176,40 @@ export const FlappyCat: React.FC<{ onBack: () => void }> = ({ onBack }) => { className="relative w-full max-w-[600px] h-[450px] bg-sky-100 rounded-[3rem] shadow-2xl border-4 border-white overflow-hidden cursor-pointer select-none" onClick={() => { if (!isPlaying || gameOver) startGame(); else flap(); }} > - {/* Punkty */} + {/* DEKORACJE - 'Sparkles' jest teraz używane i zaimportowane */} +
+
+
-
Score: {score}
-
- Record: {highScore} -
+
Score: {score}
+
Record: {highScore}
- {/* KOTEK */} -
- +
+
- {/* DRAPAKI */} {displayPipes.map(p => ( -
-
+
+
))} - {/* Ekrany informacyjne */} {!isPlaying && !gameOver && (
-
-

Flappy Cat 🎈

- -

Click or Space

+
+

Flappy Cat 🎈

+
)} {gameOver && ( -
+

Oops! 😿

Score: {score}

- +
)}
diff --git a/kittyurl-frontend/src/components/KittyGame.tsx b/kittyurl-frontend/src/components/KittyGame.tsx index cb3dcd3..23dcd8b 100644 --- a/kittyurl-frontend/src/components/KittyGame.tsx +++ b/kittyurl-frontend/src/components/KittyGame.tsx @@ -1,7 +1,7 @@ import React, { useState, useEffect, useRef, useCallback } from 'react'; import { ArrowLeft, Trophy, Sparkles, Moon, Sun } from 'lucide-react'; -// --- ZAAWANSOWANY MODEL KOTA (Bez zmian w UI) --- +// --- ZAAWANSOWANY MODEL KOTA (DetailedKitty) --- interface DetailedKittyProps { isJumping: boolean; isNight: boolean; @@ -15,6 +15,7 @@ const DetailedKitty: React.FC = ({ isJumping, isNight, isGam return (
+ {/* OGON */}
= ({ isJumping, isNight, isGam animation: !isGameOver ? 'tail-wag 0.8s ease-in-out infinite' : 'none' }} /> + + {/* TUŁÓW */}
+ + {/* GŁOWA */}
@@ -33,16 +38,20 @@ const DetailedKitty: React.FC = ({ isJumping, isNight, isGam
+
{isGameOver ? 'x' :
}
{isGameOver ? 'x' :
}
+
+ + {/* ŁAPKI */}
= ({ isJumping, isNight, isGam ); }; -// --- GŁÓWNY KOMPONENT GRY (Zoptymalizowany pod Delta Time) --- +// --- GŁÓWNY KOMPONENT GRY --- export const KittyGame: React.FC<{ onBack: () => void }> = ({ onBack }) => { const [isPlaying, setIsPlaying] = useState(false); const [gameOver, setGameOver] = useState(false); @@ -74,30 +83,30 @@ export const KittyGame: React.FC<{ onBack: () => void }> = ({ onBack }) => { }); const [displayKittyY, setDisplayKittyY] = useState(0); - const [displayObstacleX, setDisplayObstacleX] = useState(600); + const [displayObstacleX, setDisplayObstacleX] = useState(650); const isNight = Math.floor(score / 10) % 2 === 1; - // Referencje do fizyki + // Referencje do fizyki i czasu const kittyYRef = useRef(0); - const obstacleXRef = useRef(600); + const obstacleXRef = useRef(650); const velocityRef = useRef(0); const scoreRef = useRef(0); const requestRef = useRef(0); const lastTimeRef = useRef(0); - // STAŁE FIZYKI (Wartości na sekundę) + // STAŁE KONFIGURACYJNE (Wartości na sekundę) const GRAVITY = 1800; // px/s^2 const JUMP_FORCE = -550; // Moc skoku const INITIAL_SPEED = 350; // px/s - const SPEED_INCREMENT = 15; // Przyspieszenie z każdym punktem + const SPEED_INCREMENT = 15; // Przyspieszenie za każdy punkt const GROUND_Y = 0; const endGame = useCallback(() => { setGameOver(true); setIsPlaying(false); - const currentHighScore = parseInt(localStorage.getItem('kittyHighScore') || '0', 10); - if (scoreRef.current > currentHighScore) { + const currentHS = parseInt(localStorage.getItem('kittyHighScore') || '0', 10); + if (scoreRef.current > currentHS) { setHighScore(scoreRef.current); localStorage.setItem('kittyHighScore', scoreRef.current.toString()); } @@ -111,7 +120,7 @@ export const KittyGame: React.FC<{ onBack: () => void }> = ({ onBack }) => { kittyYRef.current = 0; obstacleXRef.current = 650; velocityRef.current = 0; - lastTimeRef.current = performance.now(); // Reset czasu startu + lastTimeRef.current = performance.now(); setDisplayKittyY(0); setDisplayObstacleX(650); }, []); @@ -126,25 +135,23 @@ export const KittyGame: React.FC<{ onBack: () => void }> = ({ onBack }) => { const update = (time: number) => { if (gameOver || !isPlaying) return; - // Oblicz delta time (czas w sekundach) - const deltaTime = (time - lastTimeRef.current) / 1000; + // Delta time (dt) w sekundach + const dt = (time - lastTimeRef.current) / 1000; lastTimeRef.current = time; + const frameTime = Math.min(dt, 0.1); // Limit klatki - // Ogranicz deltaTime, aby uniknąć gigantycznych skoków przy lagach - const dt = Math.min(deltaTime, 0.1); - - // Fizyka Skoku - velocityRef.current += GRAVITY * dt; - kittyYRef.current -= velocityRef.current * dt; + // Fizyka kota + velocityRef.current += GRAVITY * frameTime; + kittyYRef.current -= velocityRef.current * frameTime; if (kittyYRef.current <= GROUND_Y) { kittyYRef.current = GROUND_Y; velocityRef.current = 0; } - // Fizyka Przeszkody + // Ruch przeszkody const currentSpeed = INITIAL_SPEED + (scoreRef.current * SPEED_INCREMENT); - obstacleXRef.current -= currentSpeed * dt; + obstacleXRef.current -= currentSpeed * frameTime; if (obstacleXRef.current < -60) { obstacleXRef.current = 700; @@ -153,7 +160,7 @@ export const KittyGame: React.FC<{ onBack: () => void }> = ({ onBack }) => { } // Kolizja - if (obstacleXRef.current < 90 && obstacleXRef.current > 20 && kittyYRef.current < 45) { + if (obstacleXRef.current < 110 && obstacleXRef.current > 30 && kittyYRef.current < 45) { endGame(); return; } @@ -191,7 +198,7 @@ export const KittyGame: React.FC<{ onBack: () => void }> = ({ onBack }) => { ${isNight ? 'bg-slate-950 border-indigo-500 shadow-indigo-500/20' : 'bg-white border-pink-100 shadow-pink-200/50'}`} onClick={() => { if (!isPlaying || gameOver) startGame(); else jump(); }} > - {/* Niebo i Słońce/Księżyc */} + {/* Niebo (Używamy Moon i Sun) */}
@@ -199,7 +206,7 @@ export const KittyGame: React.FC<{ onBack: () => void }> = ({ onBack }) => {
- {/* Score UI */} + {/* Wyniki (Używamy Trophy) */}
Score: {score}
@@ -215,7 +222,7 @@ export const KittyGame: React.FC<{ onBack: () => void }> = ({ onBack }) => { {/* PRZESZKODA */}
@@ -223,16 +230,16 @@ export const KittyGame: React.FC<{ onBack: () => void }> = ({ onBack }) => { {/* Ziemia */}
+ ${isNight ? 'bg-slate-900 border-indigo-900 text-indigo-900' : 'bg-pink-50 border-pink-100 text-pink-200'}`}> {[...Array(9)].map((_, i) => 🐾)}
- {/* Ekrany informacyjne */} + {/* Ekrany informacyjne (Używamy Sparkles) */} {!isPlaying && !gameOver && (
-
@@ -241,10 +248,10 @@ export const KittyGame: React.FC<{ onBack: () => void }> = ({ onBack }) => { {gameOver && (
+ ${isNight ? 'bg-slate-950/90' : 'bg-pink-50/90'}`}>

Meow! 😿

Score: {score}

-
diff --git a/kittyurl-frontend/vite.config.ts b/kittyurl-frontend/vite.config.ts index f706cbe..10533e3 100644 --- a/kittyurl-frontend/vite.config.ts +++ b/kittyurl-frontend/vite.config.ts @@ -33,4 +33,8 @@ export default defineConfig({ } } }, + preview: { + port: 6568, + + }, }) \ No newline at end of file