function updateGameLogic() { // 1. Input Logging (Ducken) if (isCrouching) { inputLog.push({ t: currentTick - lastSentTick, act: "DUCK" }); } // 2. Geschwindigkeit (Basiert auf ZEIT/Ticks, nicht Score!) // Formel: Start bei 5, erhöht sich alle 3000 Ticks (ca. 50 Sek) um 0.5 let currentSpeed = 5 + (currentTick / 3000.0) * 0.5; if (currentSpeed > 20.0) currentSpeed = 20.0; // Max Speed Cap // 3. Spieler Physik & Größe const originalHeight = 50; const crouchHeight = 25; player.h = isCrouching ? crouchHeight : originalHeight; // Visuelle Korrektur Y (damit Füße am Boden bleiben) let drawY = isCrouching ? player.y + (originalHeight - crouchHeight) : player.y; // Schwerkraft player.vy += GRAVITY; if (isCrouching && !player.grounded) player.vy += 2.0; // Schneller fallen (Fast Fall) player.y += player.vy; // Boden-Kollision if (player.y + originalHeight >= GROUND_Y) { player.y = GROUND_Y - originalHeight; player.vy = 0; player.grounded = true; } else { player.grounded = false; } // 4. Hindernisse Bewegen & Kollision let nextObstacles = []; let rightmostX = 0; for (let obs of obstacles) { obs.x -= currentSpeed; // Hitbox für aktuellen Frame const playerHitbox = { x: player.x, y: drawY, w: player.w, h: player.h }; if (checkCollision(playerHitbox, obs)) { // A. MÜNZE (+2000 Punkte) if (obs.def.type === "coin") { score += 2000; continue; // Entfernen (Eingesammelt) } // B. POWERUP (Aktivieren) else if (obs.def.type === "powerup") { if (obs.def.id === "p_god") godModeLives = 3; if (obs.def.id === "p_bat") hasBat = true; if (obs.def.id === "p_boot") bootTicks = 600; lastPowerupTick = currentTick; continue; // Entfernen (Eingesammelt) } // C. GEGNER / HINDERNIS else { // Schläger vs Lehrer if (hasBat && obs.def.type === "teacher") { hasBat = false; // Schläger kaputt continue; // Lehrer weg } // Godmode vs Alles if (godModeLives > 0) { godModeLives--; // Ein Leben weg continue; // Hindernis ignoriert } // Tod player.color = "darkred"; if (!isGameOver) { sendChunk(); gameOver("Kollision"); } } } // Objekt behalten wenn noch im Bild if (obs.x + obs.def.width > -100) { nextObstacles.push(obs); if (obs.x + obs.def.width > rightmostX) rightmostX = obs.x + obs.def.width; } } obstacles = nextObstacles; // 5. Spawning (Basiert auf ZEIT/Ticks) if (rightmostX < GAME_WIDTH - 10 && gameConfig) { const gap = Math.floor(400 + rng.nextRange(0, 500)); let spawnX = rightmostX + gap; if (spawnX < GAME_WIDTH) spawnX = GAME_WIDTH; // Boss Phase abhängig von Zeit (nicht Score, wegen Münzen!) const isBossPhase = (currentTick % 1500) > 1200; let possibleObs = []; gameConfig.obstacles.forEach(def => { if (isBossPhase) { // Boss Phase: Nur Principal und Trashcan if (def.id === "principal" || def.id === "trashcan") possibleObs.push(def); } else { // Normal Phase if (def.id === "principal") return; // Eraser erst ab Tick 3000 (ca. 50 Sek) if (def.id === "eraser" && currentTick < 3000) return; possibleObs.push(def); } }); // Zufälliges Objekt wählen let def = rng.pick(possibleObs); // RNG Sync: Sprechblasen let speech = null; if (def && def.canTalk) { // WICHTIG: Reihenfolge muss 1:1 wie in Go sein if (rng.nextFloat() > 0.7) speech = rng.pick(def.speechLines); } // RNG Sync: Powerup Seltenheit (nur 10% Chance) if (def && def.type === "powerup") { if (rng.nextFloat() > 0.1) def = null; } // Hinzufügen if (def) { const yOffset = def.yOffset || 0; obstacles.push({ x: spawnX, y: GROUND_Y - def.height - yOffset, def: def, speech: speech }); } } } function checkCollision(p, obs) { const paddingX = 10; const realRightEdge = obs.x + obs.def.width - paddingX; if (realRightEdge < p.x + 5) { return false; } const paddingY_Top = (obs.def.type === "teacher") ? 25 : 10; const paddingY_Bottom = 5; // Geschwindigkeit schätzen (oder global holen) für CCD let currentSpeed = 5 + (score / 5000.0) * 0.5; // /5000 weil score hier /10 ist? // Moment, in main.js ist 'score' der rohe Wert. Also /500. // Da wir score global haben: currentSpeed = 5 + (score / 500.0) * 0.5; if (currentSpeed > 12.0) currentSpeed = 12.0; const pLeft = p.x + paddingX; const pRight = p.x + p.w - paddingX; const pTop = p.y + paddingY_Top; const pBottom = p.y + p.h - paddingY_Bottom; const oLeft = obs.x + paddingX; // CCD Erweiterung const oRight = obs.x + obs.def.width - paddingX + currentSpeed; const oTop = obs.y + paddingY_Top; const oBottom = obs.y + obs.def.height - paddingY_Bottom; return (pRight > oLeft && pLeft < oRight && pBottom > oTop && pTop < oBottom); }