Final Project - Complete Clicker Game
In this final episode of our mini-game project, we'll put everything together to create a complete clicker game with multiple levels, visual feedback, and win/lose conditions!
Welcome to the Final Project!
We've covered all the components needed for our clicker game:
- Game planning and concept development
- Scoring systems and point tracking
- Target creation and game elements
- Click handling and hit detection
- Timers and countdowns
- Difficulty progression
- Game states (start/stop/reset)
- Score displays and high score tracking
- Sound effects for feedback
Now, we'll combine everything into one complete game with the following requirements:
- Multiple levels with increasing difficulty
- Visual feedback for player actions
- Clear win/lose conditions
The McTweak Team Prepares for the Final Demo
The Current Problem
- Only one difficulty level
- No proper visual feedback for clicks
- Missing win/lose conditions
- Minimal player progression
Let's look at the current code and identify what needs improvement:
// Current game code - needs improvement let score = 0; let timeLeft = 30; let gameActive = false; function startGame() { score = 0; timeLeft = 30; gameActive = true; // Update UI document.getElementById('score').textContent = score; document.getElementById('time').textContent = timeLeft; // Start timer const timer = setInterval(() => { timeLeft--; document.getElementById('time').textContent = timeLeft; if (timeLeft <= 0) { clearInterval(timer); endGame(); } }, 1000); // Create targets createTarget(); } function createTarget() { if (!gameActive) return; const target = document.createElement('div'); target.className = 'target'; // Random position const gameArea = document.getElementById('game-area'); const maxX = gameArea.clientWidth - 50; const maxY = gameArea.clientHeight - 50; target.style.left = Math.random() * maxX + 'px'; target.style.top = Math.random() * maxY + 'px'; target.style.width = '50px'; target.style.height = '50px'; // Click handler target.addEventListener('click', () => { score++; document.getElementById('score').textContent = score; gameArea.removeChild(target); createTarget(); }); gameArea.appendChild(target); } function endGame() { gameActive = false; document.getElementById('game-area').innerHTML = 'GAME OVER LOSER'; // No level progression or win condition }
Implementing Multiple Levels
Let's implement a level system that increases difficulty as players progress:
// Level system implementation let currentLevel = 1; let targetSize = 50; // Starting size in pixels let targetDuration = 2000; // How long targets stay visible (ms) let pointsPerTarget = 1; let targetsToNextLevel = 10; // Targets needed to advance level let targetCount = 0; // Targets clicked in current level // Level configuration const levels = [ { level: 1, size: 50, duration: 2000, points: 1, required: 10 }, { level: 2, size: 40, duration: 1800, points: 2, required: 12 }, { level: 3, size: 35, duration: 1600, points: 3, required: 15 }, { level: 4, size: 30, duration: 1400, points: 5, required: 18 }, { level: 5, size: 25, duration: 1200, points: 8, required: 20 } ]; function startGame() { // Reset game state score = 0; timeLeft = 30; gameActive = true; currentLevel = 1; targetCount = 0; // Set initial difficulty based on level 1 targetSize = levels[0].size; targetDuration = levels[0].duration; pointsPerTarget = levels[0].points; targetsToNextLevel = levels[0].required; // Update UI updateUI(); // Start timer const timer = setInterval(() => { timeLeft--; document.getElementById('time').textContent = timeLeft; if (timeLeft <= 0) { clearInterval(timer); endGame(false); // Game over (lost) } }, 1000); // Create first target createTarget(); } function updateUI() { document.getElementById('score').textContent = score; document.getElementById('time').textContent = timeLeft; document.getElementById('level').textContent = currentLevel; } function handleTargetClick(target) { // Increase score and target count score += pointsPerTarget; targetCount++; // Check for level completion if (targetCount >= targetsToNextLevel) { advanceLevel(); } // Update UI and create new target updateUI(); createTarget(); } function advanceLevel() { // Check if there's another level if (currentLevel < levels.length) { currentLevel++; const levelConfig = levels[currentLevel - 1]; // Update level parameters targetSize = levelConfig.size; targetDuration = levelConfig.duration; pointsPerTarget = levelConfig.points; targetsToNextLevel = levelConfig.required; targetCount = 0; // Show level transition showLevelTransition(); // Add bonus time timeLeft += 10; updateUI(); } else { // Player completed all levels! endGame(true); // Game over (won) } }
- Each level has its own configuration (size, duration, points, targets required)
- Targets get smaller and disappear faster as levels increase
- Points per target increase to reward player progress
- Bonus time is awarded when advancing to a new level
- Win condition occurs when all levels are completed
Adding Visual Feedback
Now let's enhance the game with visual feedback to make it more engaging:
// Visual feedback implementation function createTarget() { if (!gameActive) return; // Clear any existing targets const existingTargets = document.querySelectorAll('.target'); existingTargets.forEach(target => target.remove()); const target = document.createElement('div'); target.className = 'target'; // Random position const gameArea = document.getElementById('game-area'); const maxX = gameArea.clientWidth - targetSize; const maxY = gameArea.clientHeight - targetSize; target.style.left = Math.random() * maxX + 'px'; target.style.top = Math.random() * maxY + 'px'; target.style.width = targetSize + 'px'; target.style.height = targetSize + 'px'; // Add level indicator target.dataset.level = currentLevel; // Visual appearance based on level switch(currentLevel) { case 1: target.style.background = 'radial-gradient(circle, #ff71ce, #b266ff)'; break; case 2: target.style.background = 'radial-gradient(circle, #01ffaa, #18e6ff)'; break; case 3: target.style.background = 'radial-gradient(circle, #fffb96, #ff9e64)'; break; case 4: target.style.background = 'radial-gradient(circle, #18e6ff, #b266ff)'; break; case 5: target.style.background = 'radial-gradient(circle, #ff9e64, #ff71ce)'; break; } // Pulsing animation target.style.animation = 'pulse 1.5s infinite'; // Click handler with visual feedback target.addEventListener('click', () => { // Visual pop effect target.classList.add('clicked'); // Show points indicator showPointsIndicator(target, pointsPerTarget); // Remove target after animation setTimeout(() => { gameArea.removeChild(target); handleTargetClick(target); }, 300); }); gameArea.appendChild(target); // Target disappears after duration setTimeout(() => { if (target.parentNode === gameArea) { // Fade out animation target.style.animation = 'fadeOut 0.5s'; setTimeout(() => { if (target.parentNode === gameArea) { gameArea.removeChild(target); createTarget(); } }, 500); } }, targetDuration); } function showPointsIndicator(target, points) { const indicator = document.createElement('div'); indicator.className = 'points-indicator'; indicator.textContent = '+' + points; // Position near the target const rect = target.getBoundingClientRect(); const gameRect = document.getElementById('game-area').getBoundingClientRect(); indicator.style.left = (rect.left - gameRect.left + rect.width / 2) + 'px'; indicator.style.top = (rect.top - gameRect.top - 20) + 'px'; document.getElementById('game-area').appendChild(indicator); // Animate and remove setTimeout(() => { indicator.remove(); }, 1000); } function showLevelTransition() { const overlay = document.createElement('div'); overlay.className = 'game-overlay level-transition'; const content = document.createElement('div'); content.innerHTML = ` <div class="overlay-title">Level ${currentLevel}!</div> <div class="level-desc">Targets are smaller and faster!</div> <div class="bonus">+10 seconds bonus time!</div> <button class="next-level-button">GO!</button> `; overlay.appendChild(content); document.getElementById('game-area').appendChild(overlay); // Pause gameplay gameActive = false; // Continue on button click overlay.querySelector('.next-level-button').addEventListener('click', () => { overlay.remove(); gameActive = true; createTarget(); }); }
- Targets have unique colors for each level
- Targets pulse to attract attention
- "Pop" animation when targets are clicked
- Points indicator appears to show score increase
- Targets fade out when they expire
- Level transition screens with bonus time notification
Implementing Win/Lose Conditions
Finally, let's implement clear win/lose conditions to complete our game:
// Win/Lose conditions implementation function endGame(isWin) { // Stop game activity gameActive = false; // Clear any remaining targets const existingTargets = document.querySelectorAll('.target'); existingTargets.forEach(target => target.remove()); // Create game over overlay const overlay = document.createElement('div'); overlay.className = 'game-overlay'; if (isWin) { // Player won by completing all levels overlay.innerHTML = ` <div class="overlay-title win">YOU WIN!</div> <div class="result-text">You completed all ${levels.length} levels!</div> <div class="final-score">Final Score: ${score}</div> <button class="start-button">Play Again</button> `; // Add celebration effects createConfetti(); } else { // Player lost (ran out of time) overlay.innerHTML = ` <div class="overlay-title lose">GAME OVER</div> <div class="result-text">You reached Level ${currentLevel}</div> <div class="final-score">Final Score: ${score}</div> <button class="start-button">Try Again</button> `; } // Check if high score was achieved let highScore = localStorage.getItem('clickerHighScore') ? JSON.parse(localStorage.getItem('clickerHighScore')) : 0; if (score > highScore) { // New high score! highScore = score; localStorage.setItem('clickerHighScore', JSON.stringify(highScore)); const highScoreElement = document.createElement('div'); highScoreElement.className = 'new-high-score'; highScoreElement.textContent = 'NEW HIGH SCORE!'; overlay.querySelector('.final-score').after(highScoreElement); } else { // Show current high score const highScoreElement = document.createElement('div'); highScoreElement.className = 'high-score'; highScoreElement.textContent = `High Score: ${highScore}`; overlay.querySelector('.final-score').after(highScoreElement); } document.getElementById('game-area').appendChild(overlay); // Add event listener to restart game overlay.querySelector('button').addEventListener('click', () => { overlay.remove(); startGame(); }); } function createConfetti() { const gameArea = document.getElementById('game-area'); const colors = ['#ff71ce', '#01ffaa', '#fffb96', '#18e6ff', '#b266ff']; // Create 50 confetti pieces for (let i = 0; i < 50; i++) { const confetti = document.createElement('div'); confetti.className = 'confetti'; confetti.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; confetti.style.left = Math.random() * 100 + '%'; confetti.style.top = '-20px'; confetti.style.transform = `rotate(${Math.random() * 360}deg)`; confetti.style.opacity = Math.random() * 0.7 + 0.3; confetti.style.animationDuration = (Math.random() * 3 + 2) + 's'; gameArea.appendChild(confetti); // Remove confetti after animation setTimeout(() => { confetti.remove(); }, 5000); } }
- Win: Complete all 5 levels
- Lose: Run out of time
- High score tracking with localStorage
- Special celebration effects for winning (confetti)
- Different visual treatments for win vs. lose screens
- Option to play again
Complete Game Features
| Feature | Implementation | Player Benefit |
|---|---|---|
| Multiple Levels | 5 levels with increasing difficulty | Sense of progression and achievement |
| Visual Feedback | Animations, colors, effects | Satisfying interactions, clear cause and effect |
| Win Conditions | Complete all levels | Goal to strive for, sense of completion |
| Lose Conditions | Time runs out | Challenge and tension |
| Difficulty Curve | Smaller targets, faster disappearing | Increasing challenge matches growing skill |
| Score System | Points per hit increase with level | Rewards for tackling harder challenges |
| High Score Tracking | localStorage persistence | Long-term goals and replayability |
Complete Clicker Game Demo
Here's the complete clicker game with multiple levels, visual feedback, and win/lose conditions:
Your Turn: Game Enhancements
Now it's your turn to enhance the clicker game with additional features! Choose one or more of the following challenges:
- Power-ups: Add special targets that give bonus effects (extra time, double points, etc.)
- Negative Targets: Add targets that should be avoided (subtract points or time if clicked)
- Multi-Target Challenge: Require players to click multiple targets in a specific sequence
- Custom Themes: Let players choose different visual themes for the game
- Achievement System: Create badges or achievements for specific accomplishments
Use the code we've developed as a starting point and add your own creative touches. Don't forget to include comments explaining your additions!
Chapter 9 Summary
Congratulations on completing Chapter 9! In this final episode, we created a complete clicker game with:
- Multiple levels that increase in difficulty
- Visual feedback to make interactions satisfying
- Clear win/lose conditions to give players goals
Throughout Chapter 9, we've learned about:
- Game planning and concept development
- Scoring and point tracking systems
- Creating and managing game elements
- Handling user interactions and event delegation
- Using timers for countdown mechanics
- Progressive difficulty implementation
- Managing game states (start/stop/reset)
- High score tracking with localStorage
- Adding audio feedback to games
- Creating a complete, polished gaming experience
In the next chapter, you'll apply everything you've learned to create your own web project from scratch!