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
JavaScript
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);
}