UNPKG

wavingflags-mensuino

Version:

Waving Flags is an engaging JavaScript game that challenges players to navigate a flag through various levels filled with obstacles. Utilizing a simple yet captivating mechanic, players must adeptly manage the flag's movement.

360 lines (306 loc) 9.69 kB
class Flag { constructor(image, position) { this.image = image; this.position = position; this.velocity = { x: 0, y: 0 }; } update() { this.position.x += this.velocity.x; this.position.y += this.velocity.y; } draw(context) { context.drawImage(this.image, this.position.x, this.position.y); } } class Obstacle { constructor(position, width, height) { this.position = position; this.width = width; this.height = height; } draw(context) { context.fillRect(this.position.x, this.position.y, this.width, this.height); } } class Wind { constructor(strength) { this.strength = strength; } applyTo(flag) { flag.velocity.x += this.strength.x; flag.velocity.y += this.strength.y; } } class Game { constructor(canvas) { this.canvas = canvas; this.context = canvas.getContext('2d'); this.flags = []; this.obstacles = []; this.wind = new Wind({ x: 0.1, y: 0 }); this.init(); } init() { this.bindEvents(); } bindEvents() { window.addEventListener('keydown', (e) => { const flag = this.flags[0]; switch (e.key) { case 'ArrowUp': flag.velocity.y -= 1; break; case 'ArrowDown': flag.velocity.y += 1; break; case 'ArrowLeft': flag.velocity.x -= 1; break; case 'ArrowRight': flag.velocity.x += 1; break; } }); } addFlag(flag) { this.flags.push(flag); } addObstacle(obstacle) { this.obstacles.push(obstacle); } update() { this.flags.forEach(flag => { this.wind.applyTo(flag); flag.update(); }); this.detectCollisions(); } detectCollisions() { this.flags.forEach(flag => { this.obstacles.forEach(obstacle => { if (flag.position.x < obstacle.position.x + obstacle.width && flag.position.x + 50 > obstacle.position.x && flag.position.y < obstacle.position.y + obstacle.height && flag.position.y + 30 > obstacle.position.y) { alert('Collision detected!'); } }); }); } draw() { this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); this.flags.forEach(flag => { flag.draw(this.context); }); this.obstacles.forEach(obstacle => { obstacle.draw(this.context); }); } run() { this.update(); this.draw(); requestAnimationFrame(this.run.bind(this)); } } const game = new Game(document.getElementById('gameCanvas')); game.addFlag(new Flag(document.getElementById('flagImage'), { x: 100, y: 100 })); game.addObstacle(new Obstacle({ x: 150, y: 150 }, 100, 50)); game.run(); class Moon { constructor(ctx, width, height) { this.ctx = ctx; this.width = width; this.height = height; this.circle_x = width / 2; this.circle_y = width; this.circle_r = width; this.angle = Math.atan2(Math.sqrt(width * width * 3 / 4), -width / 2); this.startAngle = Math.atan2(Math.sqrt(width * width * 3 / 4), -width / 2 - 400); this.endAngle = Math.atan2(Math.sqrt(width * width * 3 / 4), width / 2 + 200); this.x = 0; this.y = 0; } draw() { let {ctx, x, y, width, height} = this; var gradient = ctx.createRadialGradient(x, y, 50, x, y, 600); gradient.addColorStop(0, 'rgb(255,255,255)'); gradient.addColorStop(0.01, 'rgb(70,70,80)'); gradient.addColorStop(0.2, 'rgb(40,40,50)'); gradient.addColorStop(0.4, 'rgb(20,20,30)'); gradient.addColorStop(1, '#080d23'); ctx.save(); ctx.fillStyle = gradient; ctx.fillRect(0, 0, width, height); ctx.restore(); } move() { let {circle_x, circle_y, circle_r, angle, startAngle, endAngle,} = this; this.angle = angle - 0.0001; if (this.angle <= endAngle) { this.angle = startAngle; } this.x = circle_x + (circle_r * Math.cos(angle)); this.y = circle_y - (circle_r * Math.sin(angle)) + 50; } } class Stars { constructor(ctx, width, height, amount) { this.ctx = ctx; this.width = width; this.height = height; this.stars = this.getStars(amount); } getStars(amount) { let stars = []; while (amount--) { stars.push({ x: Math.random() * this.width, y: Math.random() * this.height, r: Math.random() + 0.5 }) } return stars } draw() { let ctx = this.ctx; ctx.save(); ctx.fillStyle = 'white'; this.stars.forEach(star => { ctx.beginPath(); ctx.arc(star.x, star.y, star.r, 0, 2 * Math.PI); ctx.fill() }); ctx.restore() } blink() { this.stars = this.stars.map(star => { let sign = Math.random() > 0.5 ? 1 : -1; star.r += sign * 0.2; if (star.r < 0) { star.r = -star.r } else if (star.r > 1) { star.r -= 0.2 } return star }) } } class Meteor { constructor(ctx, x, h) { this.ctx = ctx; this.x = x; this.y = 0; this.h = h; this.vx = -(5 + Math.random() * 5); this.vy = -this.vx; this.len = Math.random() * 300 + 100; } flow() { if (this.x < -this.len || this.y > this.h + this.len) { return false } this.x += this.vx; this.y += this.vy; return true } draw() { let ctx = this.ctx, gra = ctx.createRadialGradient( this.x, this.y, 0, this.x, this.y, this.len); const PI = Math.PI; gra.addColorStop(0, 'rgba(255,255,255,1)'); gra.addColorStop(1, 'rgba(0,0,0,0)'); ctx.save(); ctx.fillStyle = gra; ctx.beginPath(); ctx.arc(this.x, this.y, .5, PI / 4, 5 * PI / 4); ctx.lineTo(this.x + this.len, this.y - this.len); ctx.closePath(); ctx.fill(); ctx.restore(); } } const meteorGenerator = () => { let x = Math.random() * width; meteors.push(new Meteor(ctx, x, height)); }; const frame = () => { count++; count % 10 == 0 && stars.blink(); count % 300 == 0 && meteorGenerator(); moon.move(); moon.draw(); stars.draw(); meteors.forEach((meteor, index, arr) => { if (meteor.flow() ) { meteor.draw() } else { arr.splice(index, 1) } }); requestAnimationFrame(frame); }; let width = window.innerWidth, height = window.innerHeight, canvas = document.getElementById("canvas"), ctx = canvas.getContext('2d'), moon = new Moon(ctx, width, height), stars = new Stars(ctx, width, height, 200), meteors = [], count = 0; canvas.width = width; canvas.height = height; frame(); function randomWindChange() { this.wind.strength.x = Math.random() * 2 - 1; this.wind.strength.y = Math.random() * 2 - 1; } function increaseDifficulty() { this.obstacles.forEach(obstacle => { obstacle.width = obstacle.width * 1.1; obstacle.height = obstacle.height * 1.1; }); } function decreaseDifficulty() { this.obstacles.forEach(obstacle => { obstacle.width = obstacle.width * 0.9; obstacle.height = obstacle.height * 0.9; }); } function addRandomObstacle() { const x = Math.random() * this.canvas.width; const y = Math.random() * this.canvas.height; const width = Math.random() * 50 + 50; const height = Math.random() * 30 + 30; this.addObstacle(new Obstacle({x, y}, width, height)); } function changeFlagSpeed() { this.flags.forEach(flag => { flag.velocity.x = Math.random() * 2 - 1; flag.velocity.y = Math.random() * 2 - 1; }); } function teleportFlag() { const flag = this.flags[0]; flag.position.x = Math.random() * this.canvas.width; flag.position.y = Math.random() * this.canvas.height; } function randomizeFlags() { this.flags.forEach(flag => { flag.image = this.flagImages[Math.floor(Math.random() * this.flagImages.length)]; }); } function resetGame() { this.flags = []; this.obstacles = []; this.init(); } function adjustWindRandomly() { setInterval(() => { this.wind.strength.x += Math.random() - 0.5; this.wind.strength.y += Math.random() - 0.5; }, 1000); } function spawnMovingObstacles() { const x = Math.random() * this.canvas.width; const y = Math.random() * this.canvas.height; const width = Math.random() * 50 + 20; const height = Math.random() * 30 + 10; const obstacle = new Obstacle({x, y}, width, height); obstacle.velocity = {x: Math.random() * 2 - 1, y: Math.random() * 2 - 1}; this.addObstacle(obstacle); }