<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>Star Catcher Deluxe!</title>
    <link rel="stylesheet" href="style.css">
    <link href="https://fonts.googleapis.com/css2?family=Nunito:wght@700&display=swap" rel="stylesheet">
</head>
<body>

    <div id="game-wrapper">
        <h1>Star Catcher Deluxe!</h1>

        <div id="game-stats">
            <span>Score: <span id="score">0</span></span>
            <span>Lives: <span id="lives">3</span></span>
            <span>High Score: <span id="high-score">0</span></span>
            <!-- Added Combo Display -->
            <span id="combo-display" class="hidden">Combo: x<span id="combo-multiplier">1</span></span>
        </div>

        <div id="game-container">
            <!-- Static background stars -->
            <div class="static-star" style="top: 10%; left: 15%; font-size: 10px; opacity: 0.5;"></div>
            <div class="static-star" style="top: 30%; left: 80%; font-size: 12px; opacity: 0.6;"></div>
            <div class="static-star" style="top: 60%; left: 5%; font-size: 8px; opacity: 0.4;">🌟</div>
            <div class="static-star" style="top: 80%; left: 90%; font-size: 11px; opacity: 0.5;"></div>
            <div class="static-star" style="top: 45%; left: 45%; font-size: 9px; opacity: 0.3;"></div>
            <!-- Falling items will be added here -->
            <div id="powerup-timer" class="hidden">⏰ Slow!</div> <!-- Visual cue for slow powerup -->
        </div>

        <!-- Moved Controls Up slightly via CSS -->
        <div id="controls">
             <button id="start-button">Start Game</button>
        </div>

        <div id="game-over-screen" class="hidden">
            <h2>Game Over!</h2>
            <p>Your Score: <span id="final-score">0</span></p>
            <p>High Score: <span id="final-high-score">0</span></p>
            <button id="restart-button">Play Again?</button>
        </div>
    </div>

    <script src="script.js"></script>
</body>
</html>
/* General Styles (Mostly Same) */
body {
    font-family: 'Nunito', sans-serif;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    background: linear-gradient(to bottom, #001f3f, #003366, #001f3f);
    color: #fff;
    margin: 0;
    overflow: hidden;
    user-select: none;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
}

#game-wrapper {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

h1 {
    color: #ffd700;
    text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
    margin-bottom: 10px; /* Reduced margin */
}

/* Game Stats */
#game-stats {
    font-size: 1.2em; /* Slightly smaller to fit combo */
    margin-bottom: 10px;
    background-color: rgba(0, 0, 0, 0.3);
    padding: 5px 10px;
    border-radius: 8px;
    min-width: 300px; /* Increased width */
    display: flex;
    justify-content: space-around;
    align-items: center; /* Vertically align items */
}

#game-stats span {
    margin: 0 8px; /* Adjusted margin */
}

#lives {
    color: #ff4136;
    font-weight: bold;
}
#high-score{
    color: #39cccc;
}

/* Combo Display Style */
#combo-display {
    color: #FFDC00; /* Gold color for combo */
    font-weight: bold;
    text-shadow: 1px 1px 2px rgba(0,0,0,0.5);
    transition: opacity 0.3s ease; /* Smooth hide/show */
}

/* Game Container */
#game-container {
    width: 90vw;
    max-width: 600px;
    height: 70vh;
    max-height: 500px;
    border: 4px solid #7fdbff;
    background-color: rgba(0, 20, 40, 0.5);
    position: relative;
    overflow: hidden;
    cursor: crosshair;
    box-shadow: 0 0 20px rgba(127, 219, 255, 0.6);
    border-radius: 10px;
    transition: border-color 0.3s ease; /* Added for powerup effect */
}

/* Static Background Stars */
.static-star {
    position: absolute;
    color: #fff;
    pointer-events: none;
}

/* Powerup Timer Visual Cue */
#powerup-timer {
    position: absolute;
    top: 10px;
    right: 10px;
    background-color: rgba(0, 150, 255, 0.8);
    color: white;
    padding: 5px 10px;
    border-radius: 5px;
    font-size: 0.9em;
    font-weight: bold;
    z-index: 5; /* Above items */
    box-shadow: 0 0 10px rgba(0, 150, 255, 0.7);
}


/* Falling Items */
.item {
    position: absolute;
    font-size: 28px;
    cursor: pointer;
    transition: transform 0.1s ease-out, opacity 0.2s ease-out;
    text-shadow: 1px 1px 3px rgba(0,0,0,0.4);
    /* Make items slightly transparent by default for slow effect */
    /* opacity: 0.9;  -- Optional visual change */
}
/* Specific styles for different items if needed */
.item[data-type="golden_star"] {
     /* Maybe a subtle glow? */
     text-shadow: 0 0 8px gold;
}
.item[data-type="slowdown"], .item[data-type="extralife"] {
     /* Maybe slightly larger or different effect */
     transform: scale(1.1);
}

.item.caught {
    animation: catchAnim 0.3s ease-out forwards;
}

.item.missed {
    animation: missAnim 0.5s ease-in forwards;
}

.item.bomb-clicked {
     animation: bombExplodeAnim 0.4s ease-out forwards;
}

/* Controls & Buttons */
#controls {
    margin-top: 10px; /* Reduced margin to move button up */
}

button {
    padding: 12px 25px;
    font-size: 1.2em;
    font-family: 'Nunito', sans-serif;
    cursor: pointer;
    border: none;
    border-radius: 8px;
    color: white;
    transition: background-color 0.3s ease, transform 0.1s ease;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
}
button:hover { filter: brightness(1.1); }
button:active {
    transform: translateY(2px);
    box-shadow: 0 2px 3px rgba(0, 0, 0, 0.2);
}
#start-button { background-color: #2ecc40; }
#restart-button { background-color: #ff851b; }


/* Game Over Screen (Same as before) */
#game-over-screen {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: rgba(40, 40, 90, 0.9);
    padding: 30px 40px;
    border-radius: 15px;
    border: 3px solid #ffd700;
    text-align: center;
    box-shadow: 0 0 25px rgba(255, 215, 0, 0.5);
    z-index: 10;
}
#game-over-screen h2 { color: #ffd700; margin-bottom: 15px; }
#game-over-screen p { font-size: 1.2em; margin: 10px 0; }

/* Animations (Same as before) */
@keyframes catchAnim { /* ... */ }
@keyframes missAnim { /* ... */ }
@keyframes bombExplodeAnim { /* ... */ }
/* Existing keyframes remain the same */
@keyframes catchAnim {
    0% { transform: scale(1); opacity: 1; }
    50% { transform: scale(1.5); opacity: 0.8; }
    100% { transform: scale(0.5); opacity: 0; }
}
@keyframes missAnim {
    0% { opacity: 1; transform: translateY(0); }
    100% { opacity: 0; transform: translateY(20px); }
}
@keyframes bombExplodeAnim {
    0% { transform: scale(1); opacity: 1; filter: brightness(1);}
    50% { transform: scale(2.5); opacity: 0.5; filter: brightness(3); }
    100% { transform: scale(0.1); opacity: 0; filter: brightness(0);}
}


/* Utility */
.hidden {
    display: none;
    opacity: 0; /* Also fade out for combo */
}
const gameContainer = document.getElementById('game-container');
const scoreDisplay = document.getElementById('score');
const livesDisplay = document.getElementById('lives');
const highScoreDisplay = document.getElementById('high-score');
const startButton = document.getElementById('start-button');
const gameOverScreen = document.getElementById('game-over-screen');
const restartButton = document.getElementById('restart-button');
const finalScoreDisplay = document.getElementById('final-score');
const finalHighScoreDisplay = document.getElementById('final-high-score');
const controlsDiv = document.getElementById('controls');
const comboDisplay = document.getElementById('combo-display'); // Combo UI
const comboMultiplierDisplay = document.getElementById('combo-multiplier'); // Combo value UI
const powerupTimerDisplay = document.getElementById('powerup-timer'); // Slow timer UI

// --- Game State Variables ---
let score = 0;
let lives = 3;
let highScore = localStorage.getItem('starCatcherHighScore') || 0;
let gameIntervalId = null;
let moveIntervalId = null;
let fallingItems = [];
let isGameOver = true;
let baseSpeed = 1.5;
let speedMultiplier = 1.0; // Difficulty scaler
let powerUpSpeedModifier = 1.0; // For slow-down powerup
let baseCreationRate = 1200;
let creationRateMultiplier = 1.0; // Difficulty scaler

// --- New Logic Variables ---
let bombChance = 0.15; // Base chance
let powerupChance = 0.08; // Chance FOR ANY powerup to spawn instead of star/bomb
let goldenStarChance = 0.1; // Chance for a STAR to be GOLDEN

let comboCounter = 0;
let comboTimeoutId = null; // Timer to reset combo
const COMBO_WINDOW = 2000; // Milliseconds to continue combo
const MAX_LIVES = 5; // Maximum lives player can have

let slowDownActive = false;
let slowDownTimeoutId = null;
const SLOW_DOWN_DURATION = 5000; // 5 seconds
const SLOW_DOWN_FACTOR = 0.5; // Halves the speed

// --- Constants ---
const GAME_HEIGHT = gameContainer.clientHeight;
const GAME_WIDTH = gameContainer.clientWidth;
const ITEM_TYPES = {
    STAR:        { emojis: ['⭐', '✨'], points: 10, type: 'star' },
    GOLDEN_STAR: { emojis: ['🌟'], points: 50, type: 'golden_star' }, // Higher value
    BOMB:        { emojis: ['💣'], points: 0, type: 'bomb' }, // Points not used on click
    SLOW_DOWN:   { emojis: ['⏰'], type: 'slowdown' }, // Power-up
    EXTRA_LIFE:  { emojis: ['❤️'], type: 'extralife' } // Power-up
};
const MOVE_RATE = 20;

// Sound Placeholders...

// --- Initialization ---
function init() {
    highScoreDisplay.textContent = highScore;
    gameOverScreen.classList.add('hidden');
    controlsDiv.classList.remove('hidden');
    startButton.classList.remove('hidden');
    comboDisplay.classList.add('hidden'); // Hide combo initially
    powerupTimerDisplay.classList.add('hidden'); // Hide timer initially
    startButton.addEventListener('click', startGame);
    restartButton.addEventListener('click', startGame);
    gameContainer.addEventListener('click', handleItemClick);
    gameContainer.addEventListener('touchstart', handleItemClick, { passive: true });
}

// --- Game Logic ---

function startGame() {
    // Reset state
    score = 0;
    lives = 3;
    speedMultiplier = 1.0;
    powerUpSpeedModifier = 1.0; // Reset powerup effect
    creationRateMultiplier = 1.0;
    isGameOver = false;
    fallingItems.forEach(item => item.element.remove());
    fallingItems = [];
    resetCombo(); // Reset combo counter and UI
    resetSlowDown(); // Ensure slow down isn't active

    // Update UI
    scoreDisplay.textContent = score;
    livesDisplay.textContent = lives;
    livesDisplay.style.color = '#ff4136';
    gameOverScreen.classList.add('hidden');
    controlsDiv.classList.add('hidden');
    powerupTimerDisplay.classList.add('hidden'); // Hide timer

    // Start game loops
    gameIntervalId = setTimeout(createItemLoop, calculateCreationRate());
    moveIntervalId = setInterval(moveItems, MOVE_RATE);
}

function calculateSpeed() {
    // Apply difficulty scaler AND powerup modifier
    return baseSpeed * speedMultiplier * powerUpSpeedModifier;
}

function calculateCreationRate() {
    return Math.max(200, baseCreationRate * creationRateMultiplier);
}

function createItemLoop() {
    if (isGameOver) return;
    createItem();
    gameIntervalId = setTimeout(createItemLoop, calculateCreationRate());
}

function createItem() {
    let itemData;
    const randomType = Math.random();

    if (randomType < bombChance) {
        itemData = ITEM_TYPES.BOMB;
    } else if (randomType < bombChance + powerupChance) {
        // It's a powerup - choose between available ones
        itemData = Math.random() < 0.5 ? ITEM_TYPES.SLOW_DOWN : ITEM_TYPES.EXTRA_LIFE;
    } else {
        // It's a star - decide if it's golden
        if (Math.random() < goldenStarChance) {
            itemData = ITEM_TYPES.GOLDEN_STAR;
        } else {
            itemData = ITEM_TYPES.STAR;
        }
    }

    const itemEmoji = itemData.emojis[Math.floor(Math.random() * itemData.emojis.length)];

    const itemElement = document.createElement('div');
    itemElement.classList.add('item');
    itemElement.textContent = itemEmoji;
    itemElement.dataset.type = itemData.type; // Store type

    const itemSize = 30;
    const maxLeft = GAME_WIDTH - itemSize;
    const randomLeft = Math.random() * maxLeft;
    itemElement.style.left = `${randomLeft}px`;
    itemElement.style.top = `-${itemSize}px`;

    gameContainer.appendChild(itemElement);
    fallingItems.push({ element: itemElement, type: itemData.type });
}

function moveItems() {
    if (isGameOver) return;

    const currentSpeed = calculateSpeed();

    for (let i = fallingItems.length - 1; i >= 0; i--) {
        const item = fallingItems[i];
        if (!item || !item.element) continue;

        let currentTop = parseFloat(item.element.style.top);
        currentTop += currentSpeed;
        item.element.style.top = `${currentTop}px`;

        if (currentTop > GAME_HEIGHT) {
            handleMissedItem(item, i);
        }
    }
    updateDifficulty();
}

function handleItemClick(event) {
    if (isGameOver || !event.target.classList.contains('item')) return;

    const clickedElement = event.target;
    const itemIndex = fallingItems.findIndex(item => item.element === clickedElement);

    if (itemIndex === -1) return;

    const item = fallingItems[itemIndex];

    // Route based on type
    switch (item.type) {
        case 'star':
        case 'golden_star':
            catchStar(item, itemIndex);
            break;
        case 'bomb':
            clickBomb(item, itemIndex);
            break;
        case 'slowdown':
        case 'extralife':
            catchPowerUp(item, itemIndex);
            break;
    }
}

function catchStar(item, index) {
    const basePoints = ITEM_TYPES[item.type.toUpperCase()].points;
    const currentComboMultiplier = Math.max(1, comboCounter); // Combo multiplier (at least 1)
    const pointsEarned = basePoints * currentComboMultiplier;

    score += pointsEarned;
    scoreDisplay.textContent = score;
    // catchSound.play();

    item.element.classList.add('caught');
    setTimeout(() => item.element.remove(), 300);
    fallingItems.splice(index, 1);

    increaseCombo(); // Increase or start combo
}

function clickBomb(item, index) {
    // bombSound.play();
    item.element.classList.add('bomb-clicked');
    setTimeout(() => item.element.remove(), 400);
    fallingItems.splice(index, 1);

    resetCombo(); // Bomb breaks combo
    loseLife();
}

function catchPowerUp(item, index) {
    item.element.classList.add('caught'); // Use same catch animation
    setTimeout(() => item.element.remove(), 300);
    fallingItems.splice(index, 1);

    if (item.type === 'slowdown') {
        activateSlowDown();
        // Optional: Play specific powerup sound
    } else if (item.type === 'extralife') {
        gainLife();
        // Optional: Play specific powerup sound
    }

    increaseCombo(); // Powerups also contribute to combo
}

function handleMissedItem(item, index) {
    if (item.type === 'star' || item.type === 'golden_star') {
        // missSound.play();
        item.element.classList.add('missed');
        setTimeout(() => item.element.remove(), 500);
        resetCombo(); // Missing a star breaks combo
        loseLife();
    } else {
        // Bombs & Powerups disappear harmlessly if missed
        item.element.remove();
    }
    // Always remove from array regardless of type
    if (fallingItems[index] === item) { // Ensure it wasn't already removed by a click race condition
        fallingItems.splice(index, 1);
    }
}

// --- Combo Logic ---
function increaseCombo() {
    comboCounter++;
    comboMultiplierDisplay.textContent = comboCounter;
    comboDisplay.classList.remove('hidden'); // Show combo display
     // Add a little visual pulse to the combo display
    comboDisplay.style.transform = 'scale(1.2)';
    setTimeout(() => { comboDisplay.style.transform = 'scale(1)';}, 100);


    // Reset combo timer
    clearTimeout(comboTimeoutId);
    comboTimeoutId = setTimeout(resetCombo, COMBO_WINDOW);
}

function resetCombo() {
    clearTimeout(comboTimeoutId);
    comboCounter = 0;
    comboDisplay.classList.add('hidden'); // Hide combo display
    comboMultiplierDisplay.textContent = '1'; // Reset display value
}

// --- Power-up Logic ---
function activateSlowDown() {
    if (slowDownActive) {
        // If already active, just reset the timer
        clearTimeout(slowDownTimeoutId);
    } else {
        // Activate
        slowDownActive = true;
        powerUpSpeedModifier = SLOW_DOWN_FACTOR;
        powerupTimerDisplay.classList.remove('hidden'); // Show timer UI
        gameContainer.style.borderColor = '#00bfff'; // Visual cue: change border color
    }

    // Set timer to deactivate
    slowDownTimeoutId = setTimeout(resetSlowDown, SLOW_DOWN_DURATION);
}

function resetSlowDown() {
    clearTimeout(slowDownTimeoutId);
    slowDownActive = false;
    powerUpSpeedModifier = 1.0; // Restore normal speed modifier
    powerupTimerDisplay.classList.add('hidden'); // Hide timer UI
    if (!isGameOver) { // Don't change border if game over screen is showing
       gameContainer.style.borderColor = '#7fdbff'; // Restore border color
    }
}

function gainLife() {
    if (lives < MAX_LIVES) {
        lives++;
        livesDisplay.textContent = lives;
        // Add visual feedback for gaining life (e.g., temporary green glow on lives)
        livesDisplay.style.color = '#2ECC40'; // Green
        setTimeout(() => {
             if (!isGameOver) livesDisplay.style.color = '#ff4136'; // Back to normal red unless game over
        }, 300);
    }
    // Optional: Play sound effect
}


// --- Life and Game Over Logic ---
function loseLife() {
    if (isGameOver) return;
    lives--;
    livesDisplay.textContent = lives;
    livesDisplay.style.color = '#FF0000';
    gameContainer.style.borderColor = '#FF0000';
    setTimeout(() => {
        if (!isGameOver) {
             livesDisplay.style.color = '#ff4136';
             gameContainer.style.borderColor = '#7fdbff';
        }
    }, 300);

    if (lives <= 0) {
        endGame();
    }
}

function updateDifficulty() {
    // Adjust base speed and creation rate based on score
    speedMultiplier = 1.0 + Math.floor(score / 75) * 0.08; // Slower speed increase
    creationRateMultiplier = 1.0 / (1.0 + Math.floor(score / 100) * 0.12); // Slower rate increase

    // Optionally, slightly increase bomb/powerup chances over time?
    // bombChance = Math.min(0.3, 0.15 + Math.floor(score / 200) * 0.02);
}


function endGame() {
    if (isGameOver) return;
    isGameOver = true;
    // gameOverSound.play();

    clearTimeout(gameIntervalId);
    clearInterval(moveIntervalId);
    resetCombo(); // Clear combo state
    resetSlowDown(); // Clear slowdown state

    if (score > highScore) {
        highScore = score;
        localStorage.setItem('starCatcherHighScore', highScore);
        highScoreDisplay.textContent = highScore;
    }

    finalScoreDisplay.textContent = score;
    finalHighScoreDisplay.textContent = highScore;
    gameOverScreen.classList.remove('hidden');
    gameContainer.style.borderColor = '#7fdbff'; // Ensure border is reset
}

// --- Start ---
window.addEventListener('load', init);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.