arthurformat/racer-rush-thunderbolt
0
1class RacingGame {2 constructor() {3 this.canvas = document.getElementById('gameCanvas');4 this.ctx = this.canvas.getContext('2d');5 this.score = 0;6 this.timer = 60;7 this.lives = 3;8 this.gameActive = false;9 this.gameLoop = null;10 11 // Game elements12 this.car = {13 x: this.canvas.width / 2 - 25,14 y: this.canvas.height - 100,15 width: 50,16 height: 80,17 speed: 718 };19 20 this.obstacles = [];21 this.obstacleSpeed = 3;22 this.obstacleFrequency = 120; // frames between obstacles23 24 this.keys = {};25 this.frameCount = 0;26 27 this.init();28 }29 30 init() {31 this.setupEventListeners();32 this.updateDisplay();33 this.startGame();34 }35 36 setupEventListeners() {37 document.addEventListener('keydown', (e) => {38 this.keys[e.key] = true;39 });40 41 document.addEventListener('keyup', (e) => {42 this.keys[e.key] = false;43 });44 45 document.getElementById('restartBtn').addEventListener('click', () => {46 this.restartGame();47 });48 49 // Touch controls for mobile50 this.canvas.addEventListener('touchstart', (e) => {51 const touchX = e.touches[0].clientX - this.canvas.getBoundingClientRect().left;52 if (touchX < this.canvas.width / 2) {53 this.keys['ArrowLeft'] = true;54 } else {55 this.keys['ArrowRight'] = true;56 }57 e.preventDefault();58 });59 60 this.canvas.addEventListener('touchend', (e) => {61 this.keys['ArrowLeft'] = false;62 this.keys['ArrowRight'] = false;63 e.preventDefault();64 });65 }66 67 startGame() {68 this.gameActive = true;69 this.gameLoop = setInterval(() => this.update(), 1000/60); // 60 FPS70 this.startTimer();71 }72 73 startTimer() {74 const timerInterval = setInterval(() => {75 if (this.gameActive && this.timer > 0) {76 this.timer--;77 this.updateDisplay();78 } else if (this.timer <= 0) {79 clearInterval(timerInterval);80 this.gameOver();81 }82 }, 1000);83 }84 85 update() {86 if (!this.gameActive) return;87 88 this.frameCount++;89 this.moveCar();90 this.updateObstacles();91 this.checkCollisions();92 this.draw();93 }94 95 moveCar() {96 if (this.keys['ArrowLeft'] && this.car.x > 50) {97 this.car.x -= this.car.speed;98 }99 if (this.keys['ArrowRight'] && this.car.x < this.canvas.width - this.car.width - 50) {100 this.car.x += this.car.speed;101 }102 }103 104 updateObstacles() {105 // Add new obstacles106 if (this.frameCount % this.obstacleFrequency === 0) {107 this.addObstacle();108 }109 110 // Move obstacles and remove off-screen ones111 this.obstacles = this.obstacles.filter(obstacle => {112 obstacle.y += this.obstacleSpeed;113 return obstacle.y < this.canvas.height;114 });115 }116 117 addObstacle() {118 const width = Math.random() * 60 + 40;119 const x = Math.random() * (this.canvas.width - width - 100) + 50;120 121 this.obstacles.push({122 x: x,123 y: -100,124 width: width,125 height: 60,126 color: this.getRandomObstacleColor()127 });128 }129 130 getRandomObstacleColor() {131 const colors = ['#ef4444', '#f97316', '#eab308', '#22c55e', '#3b82f6', '#8b5cf6'];132 return colors[Math.floor(Math.random() * colors.length)];133 }134 135 checkCollisions() {136 this.obstacles.forEach(obstacle => {137 if (this.isColliding(this.car, obstacle)) {138 this.lives--;139 this.obstacles = this.obstacles.filter(o => o !== obstacle);140 this.updateDisplay();141 142 if (this.lives <= 0) {143 this.gameOver();144 }145 }146 });147 }148 149 isColliding(rect1, rect2) {150 return rect1.x < rect2.x + rect2.width &&151 rect1.x + rect1.width > rect2.x &&152 rect1.y < rect2.y + rect2.height &&153 rect1.y + rect1.height > rect2.y;154 }155 156 draw() {157 // Clear canvas158 this.ctx.fillStyle = '#1e293b';159 this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);160 161 // Draw road162 this.drawRoad();163 164 // Draw obstacles165 this.obstacles.forEach(obstacle => {166 this.drawObstacle(obstacle);167 });168 169 // Draw car170 this.drawCar();171 172 // Update score when obstacles pass173 this.obstacles.forEach(obstacle => {174 if (obstacle.y + obstacle.height > this.car.y + this.car.height && !obstacle.passed) {175 obstacle.passed = true;176 this.score += 10;177 this.updateDisplay();178 }179 });180 }181 182 drawRoad() {183 // Road background184 this.ctx.fillStyle = '#374151';185 this.ctx.fillRect(50, 0, this.canvas.width - 100, this.canvas.height);186 187 // Road lines188 this.ctx.strokeStyle = '#facc15';189 this.ctx.lineWidth = 4;190 this.ctx.setLineDash([20, 20]);191 this.ctx.lineDashOffset = -this.frameCount % 40;192 193 this.ctx.beginPath();194 this.ctx.moveTo(this.canvas.width / 2, 0);195 this.ctx.lineTo(this.canvas.width / 2, this.canvas.height);196 this.ctx.stroke();197 198 this.ctx.setLineDash([]);199 200 // Road borders201 this.ctx.strokeStyle = '#ffffff';202 this.ctx.lineWidth = 2;203 this.ctx.strokeRect(50, 0, this.canvas.width - 100, this.canvas.height);204 }205 206 drawObstacle(obstacle) {207 this.ctx.fillStyle = obstacle.color;208 this.ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height);209 210 // Add some details to the obstacle211 this.ctx.fillStyle = '#000000';212 this.ctx.fillRect(obstacle.x + 5, obstacle.y + 5, obstacle.width - 10, obstacle.height - 10);213 }214 215 drawCar() {216 // Car body217 this.ctx.fillStyle = '#3b82f6';218 this.ctx.fillRect(this.car.x, this.car.y, this.car.width, this.car.height);219 220 // Car details221 this.ctx.fillStyle = '#ffffff';222 this.ctx.fillRect(this.car.x + 5, this.car.y + 10, this.car.width - 10, 20); // windshield223 this.ctx.fillRect(this.car.x + 5, this.car.y + this.car.height - 25, this.car.width - 10, 15); // bumper224 225 // Wheels226 this.ctx.fillStyle = '#000000';227 this.ctx.fillRect(this.car.x - 5, this.car.y + 10, 5, 20); // left wheel228 this.ctx.fillRect(this.car.x + this.car.width, this.car.y + 10, 5, 20); // right wheel229 this.ctx.fillRect(this.car.x - 5, this.car.y + this.car.height - 30, 5, 20); // left rear wheel230 this.ctx.fillRect(this.car.x + this.car.width, this.car.y + this.car.height - 30, 5, 20); // right rear wheel231 }232 233 updateDisplay() {234 document.getElementById('score').textContent = this.score;235 document.getElementById('timer').textContent = this.timer;236 document.getElementById('lives').textContent = this.lives;237 }238 239 gameOver() {240 this.gameActive = false;241 clearInterval(this.gameLoop);242 document.getElementById('finalScore').textContent = this.score;243 document.getElementById('gameOver').classList.remove('hidden');244 }245 246 restartGame() {247 this.score = 0;248 this.timer = 60;249 this.lives = 3;250 this.obstacles = [];251 this.frameCount = 0;252 this.car.x = this.canvas.width / 2 - 25;253 this.updateDisplay();254 document.getElementById('gameOver').classList.add('hidden');255 this.startGame();256 }257}258 259// Initialize game when page loads260document.addEventListener('DOMContentLoaded', () => {261 new RacingGame();262});