diff --git a/Games/Alien_Invasion/asset/Macbook-Air.png b/Games/Alien_Invasion/asset/Macbook-Air.png new file mode 100644 index 0000000000..a1fa56b1d8 Binary files /dev/null and b/Games/Alien_Invasion/asset/Macbook-Air.png differ diff --git a/Games/Alien_Invasion/asset/Mobile.png b/Games/Alien_Invasion/asset/Mobile.png new file mode 100644 index 0000000000..8c0ec401ec Binary files /dev/null and b/Games/Alien_Invasion/asset/Mobile.png differ diff --git a/Games/Alien_Invasion/asset/iPad-PRO-11.png b/Games/Alien_Invasion/asset/iPad-PRO-11.png new file mode 100644 index 0000000000..4040d94f1a Binary files /dev/null and b/Games/Alien_Invasion/asset/iPad-PRO-11.png differ diff --git a/Games/Alien_Invasion/index.html b/Games/Alien_Invasion/index.html index 760bb1af1b..cbb245a886 100644 --- a/Games/Alien_Invasion/index.html +++ b/Games/Alien_Invasion/index.html @@ -1,44 +1,18 @@ - - - - AttackAlienInvader Game - - - + + Bubble Shooter Game - - - - - - - - - - - - +
+
Score: 0
+
+ +
+ - - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/Games/Alien_Invasion/script.js b/Games/Alien_Invasion/script.js index 5e50da0a0c..b905db022b 100644 --- a/Games/Alien_Invasion/script.js +++ b/Games/Alien_Invasion/script.js @@ -1,543 +1,70 @@ -window.addEventListener('load', function () { - //canvas setup - const canvas = document.getElementById('canvas1'); - const ctx = canvas.getContext('2d'); - canvas.width = 1000; - canvas.height = 500; - - class InputHandler { - constructor(game) { - this.game = game; - window.addEventListener('keydown', e => { - if (((e.key === 'ArrowUp') || - (e.key === 'ArrowDown') - ) && this.game.keys.indexOf(e.key) === - 1) { - this.game.keys.push(e.key); - } else if (e.key === ' ') { - this.game.player.shootTop(); - } else if (e.key === 'd') { - this.game.debug = !this.game.debug; - } - }); - window.addEventListener('keyup', e => { - if (this.game.keys.indexOf(e.key) > -1) { - this.game.keys.splice(this.game.keys.indexOf(e.key), 1); - } - }); - } - } - - class Projectile { - constructor(game, x, y) { - this.game = game; - this.x = x; - this.y = y; - this.width = 10; - this.height = 3; - this.speed = 3; - this.markedForDeletion = false; - this.image = document.getElementById('projectile'); - } - update() { - this.x += this.speed; - if (this.x > this.game.width * 0.8) this.markedForDeletion = true; - } - draw(context) { - context.drawImage(this.image, this.x, this.y); - } - } - - class Particle { - constructor(game, x, y) { - this.game = game; - this.x = x; - this.y = y; - this.image = document.getElementById('gears'); - this.frameX = Math.floor(Math.random() * 3); - this.frameY = Math.floor(Math.random() * 3); - this.spriteSize = 50; - this.sizeModifier = (Math.random() * 0.5 + 0.5).toFixed(1); - this.size = this.spriteSize * this.sizeModifier; - this.speedX = Math.random() * 6 - 3; - this.speedY = Math.random() * -15; - this.gravity = 0.5; - this.markedForDeletion = false; - this.angle = 0; - this.va = Math.random() * 0.2 - 0.1; - this.bounced = 0; - this.bottomBounceBoundary = Math.random() * 80 + 60; - } - update() { - this.angle += this.va; - this.speedY += this.gravity; - this.x -= this.speedX - this.game.speed; - this.y += this.speedY; - if (this.y > this.game.height + this.size || this.x < 0 - this.size) this.markedForDeletion = true; - if (this.y > this.game.height - this.bottomBounceBoundary && this.bounced < 5) { - this.bounced++; - this.speedY *= -0.7; - } - } - draw(context) { - context.save(); - context.translate(this.x, this.y); - context.rotate(this.angle); - context.drawImage(this.image, this.frameX * this.spriteSize, - this.frameY * this.spriteSize, this.spriteSize, this.spriteSize, this.size * -0.5, - this.size * -0.5, this.size, this.size); - context.restore(); - } - } - - class Player { - constructor(game) { - this.game = game; - this.width = 120; - this.height = 190; - this.x = 20; - this.y = 100; - this.frameX = 0; - this.frameY = 0; - this.maxFrame = 37; - this.speedY = 0; - this.maxSpeed = 3; - this.projectiles = []; - this.image = document.getElementById('player'); - this.powerUp = false; - this.powerUpTimer = 0; - this.powerUpLimit = 10000; - } - update(deltaTime) { - if (this.game.keys.includes('ArrowUp')) this.speedY = -this.maxSpeed; - else if (this.game.keys.includes('ArrowDown')) this.speedY = this.maxSpeed; - else this.speedY = 0; - this.y += this.speedY; - // vertical boundaries - if (this.y > this.game.height - this.height * 0.5) this.y = this.game.height - this.height * 0.5; - else if (this.y < -this.height * 0.5) this.y - this.height * 0.5; - //handle projectiles - this.projectiles.forEach(projectile => { - projectile.update(); - }); - this.projectiles = this.projectiles.filter(projectile => !projectile.markedForDeletion); - //sprite animation - if (this.frameX < this.maxFrame) { - this.frameX++; - } else { - this.frameX = 0; +document.addEventListener("DOMContentLoaded", function() { + const gameArea = document.getElementById('game-area'); + const scoreDisplay = document.getElementById('score-value'); + const restartButton = document.getElementById('restart-btn'); + let score = 0; + let gameEnded = false; + + // Function to generate a random bubble + function createBubble() { + if (gameEnded) return; // Exit if game has ended + + const colors = ['red', 'green', 'blue', 'orange', 'yellow', 'purple']; + const randomColor = colors[Math.floor(Math.random() * colors.length)]; + const bubble = document.createElement('div'); + bubble.className = `bubble ${randomColor}`; + + // Set initial position at the bottom randomly + bubble.style.left = `${Math.random() * (gameArea.clientWidth - 30)}px`; + bubble.style.top = `${gameArea.clientHeight}px`; + + gameArea.appendChild(bubble); + + // Move the bubble upwards + let bubbleInterval = setInterval(function() { + bubble.style.top = `${parseInt(bubble.style.top) - 1}px`; + + // Check if bubble reaches the top of the game area + if (parseInt(bubble.style.top) <= 0) { + clearInterval(bubbleInterval); + gameArea.removeChild(bubble); + endGame(); } - // power up - if (this.powerUp) { - if (this.powerUpTimer > this.powerUpLimit) { - this.powerUpTimer = 0; - this.powerUp = false; - this.frameY = 0; - } else { - this.powerUpTimer += deltaTime; - this.frameY = 1; - this.game.ammo += 0.1; - } - } - } - draw(context) { - if (this.game.debug) context.strokeRect(this.x, this.y, this.width, this.height); - this.projectiles.forEach(projectile => { - projectile.draw(context); - }); - context.drawImage(this.image, this.frameX * this.width, this.frameY * this.height, this.width, this.height, this.x, this.y, this.width, this.height); - - } - shootTop() { - if (this.game.ammo > 0) { - this.projectiles.push(new Projectile(this.game, this.x + 80, this.y + 30)); - this.game.ammo--; - } - if (this.powerUp) this.shootBottom(); - } - shootBottom() { - if (this.game.ammo > 0) { - this.projectiles.push(new Projectile(this.game, this.x + 80, this.y + 175)); - } - } - - enterPowerUp() { - this.powerUpTimer = 0; - this.powerUp = true; - if (this.game.ammo < this.game.maxAmmo) this.game.ammo = this.game.maxAmmo; - } - } - class Enemy { - constructor(game) { - this.game = game; - this.x = this.game.width; - this.speedX = Math.random() * -1.5 - 0.5; - this.markedForDeletion = false; - this.frameX = 0; - this.frameY = 0; - this.maxFrame = 37; - } - update() { - this.x += this.speedX - this.game.speed; - if (this.x + this.width < 0) this.markedForDeletion = true; - // sprite animation - if (this.frameX < this.maxFrame) { - this.frameX++; - } else this.frameX = 0; - } - draw(context) { - if (this.game.debug) context.strokeRect(this.x, this.y, this.width, this.height); - context.drawImage(this.image, this.frameX * this.width, this.frameY * this.height, this.width, this.height, this.x, this.y, this.width, this.height); - if (this.game.debug) { - context.font = '20px Bangers'; - context.fillText(this.lives, this.x, this.y); + }, 10); + + // Handle click on bubble + bubble.addEventListener('click', function() { + if (!bubble.clicked) { + bubble.clicked = true; + clearInterval(bubbleInterval); + gameArea.removeChild(bubble); + score += 10; + scoreDisplay.textContent = score; } - } - } - class Angler1 extends Enemy { - constructor(game) { - super(game); - this.width = 228; - this.height = 169; - this.y = Math.random() * (this.game.height * 0.95 - this.height); - this.image = document.getElementById('angler1'); - this.frameY = Math.floor(Math.random() * 3); - this.lives = 5; - this.score = this.lives; - } - - } - class Angler2 extends Enemy { - constructor(game) { - super(game); - this.width = 213; - this.height = 165; - this.y = Math.random() * (this.game.height * 0.95 - this.height); - this.image = document.getElementById('angler2'); - this.frameY = Math.floor(Math.random() * 2); - this.lives = 6; - this.score = this.lives; - } - - } - - class LuckyFish extends Enemy { - constructor(game) { - super(game); - this.width = 99; - this.height = 95; - this.y = Math.random() * (this.game.height * 0.95 - this.height); - this.image = document.getElementById('lucky'); - this.frameY = Math.floor(Math.random() * 2); - this.lives = 5; - this.score = 15; - this.type = 'lucky' - } - } - - class HiveWhale extends Enemy { - constructor(game) { - super(game); - this.width = 400; - this.height = 227; - this.y = Math.random() * (this.game.height * 0.95 - this.height); - this.image = document.getElementById('hivewhale'); - this.frameY = 0; - this.lives = 20; - this.score = this.lives; - this.type = 'hive'; - this.speedX = Math.random() * -1.2 - 0.2; - } - } - - class Drone extends Enemy { - constructor(game, x, y) { - super(game); - this.width = 115; - this.height = 95; - this.x = x; - this.y = y; - this.image = document.getElementById('drone'); - this.frameY = Math.floor(Math.random() * 2); - this.lives = 3; - this.score = this.lives; - this.type = 'drone'; - this.speedX = Math.random() * -4.2 - 0.5; - } - } - - - class Layer { - constructor(game, image, speedModifier) { - this.game = game; - this.image = image; - this.speedModifier = speedModifier; - this.width = 1768; - this.height = 500; - this.x = 0; - this.y = 0; - } - update() { - if (this.x <= -this.width) this.x = 0; - this.x -= this.game.speed * this.speedModifier; - } - draw(context) { - context.drawImage(this.image, this.x, this.y); - context.drawImage(this.image, this.x + this.width, this.y); - } - } - - class Background { - constructor(game) { - this.game = game; - this.image1 = document.getElementById('layer1'); - this.image2 = document.getElementById('layer2'); - this.image3 = document.getElementById('layer3'); - this.image4 = document.getElementById('layer4'); - this.layer1 = new Layer(this.game, this.image1, 0.2); - this.layer2 = new Layer(this.game, this.image2, 0.4); - this.layer3 = new Layer(this.game, this.image3, 1); - this.layer4 = new Layer(this.game, this.image4, 1.5); - this.layers = [this.layer1, this.layer2, this.layer3, this.layer4]; - } - update() { - this.layers.forEach(layer => layer.update()); - } - draw(context) { - this.layers.forEach(layer => layer.draw(context)); - } - - } - - class Explosion { - constructor(game, x, y) { - this.game = game; - this.frameX = 0; - this.spriteWidth = 200; - this.spriteHeight = 200; - this.width = this.spriteWidth; - this.height = this.spriteHeight; - this.x = x - this.width * 0.5; - this.y = y - this.height * 0.5; - this.fps = 30; - this.time = 0; - this.interval = 1000 / this.fps; - this.markedForDeletion = false; - this.maxFrame = 8; - } - update(deltaTime) { - this.x -= this.game.speed; - if (this.timer > this.interval) { - this.frameX++; - this.timer = 0; - } else { - this.timer += deltaTime; - } - if (this.frameX > this.maxFrame) this.markedForDeletion = true; - } - draw(context) { - context.drawImage(this.image, this.frameX * this.spriteWidth, 0, this.spriteWidth, - this.spriteHeight, this.x, this.y, this.width, this.height); - } - } - - class SmokeExplosion extends Explosion { - constructor(game, x, y) { - super(game, x, y); - this.image = document.getElementById('smokeExplosion'); - } - } - - class FireExplosion extends Explosion { - constructor(game, x, y) { - super(game, x, y); - this.image = document.getElementById('fireExplosion'); - } - } - - - class UI { - constructor(game) { - this.game = game; - this.fontSize = 25; - this.fontFamily = 'Bangers'; - this.color = 'yellow'; - } - draw(context) { - context.save(); - context.fillStyle = this.color; - context.shadowOffsetX = 2; - context.shadowOffsetY = 2; - context.shadowColor = 'black'; - context.font = this.fontSize + 'px' + this.fontFamily; - //score - context.font = '20px Bangers'; - context.fillText('Score: ' + this.game.score, 20, 40); - - //timer - const formattedTime = (this.game.gameTime * 0.001).toFixed(1); - context.font = '20px Bangers'; - context.fillText('Timer:' + formattedTime, 20, 100); - - //game over messages - if (this.game.gameOver) { - context.textAlign = 'center'; - let message1; - let message2; - if (this.game.score > this.game.winningScore) { - message1 = 'Most Wondrous!'; - message2 = 'Well Done explorer!'; - } else { - message1 = 'Blazes!'; - message2 = 'Get my repair kit and try again!'; - } - context.font = '50px Bangers'; - context.fillText(message1, this.game.width * 0.5, this.game.height * 0.5 - 20); - context.font = '25px Bangers'; - context.fillText(message2, this.game.width * 0.5, this.game.height * 0.5 + 20); - } - //ammo - if (this.game.player.powerUp) context.fillStyle = '#ffffbd'; - for (let i = 0; i < this.game.ammo; i++) { - context.fillRect(20 + 5 * i, 50, 3, 20); - } - context.restore(); - } - } - class Game { - constructor(width, height) { - this.width = width; - this.height = height; - this.background = new Background(this); - this.player = new Player(this); - this.input = new InputHandler(this); - this.ui = new UI(this); - this.keys = []; - this.enemies = []; - this.particles = []; - this.explosions = []; - this.enemyTimer = 0; - this.enemyInterval = 2000; - this.ammo = 20; - this.maxAmmo = 50; - this.ammoTimer = 0; - this.ammoInterval = 350; - this.gameOver = false; - this.score = 0; - this.winningScore = 80; - this.gameTime = 0; - this.timeLimit = 30000; - this.speed = 1; - this.debug = false; - - } - update(deltaTime) { - if (!this.gameOver) this.gameTime += deltaTime; - if (this.gameTime > this.timeLimit) this.gameOver = true; - this.background.update(); - this.background.layer4.update(); - this.player.update(deltaTime); - if (this.ammoTimer > this.ammoInterval) { - if (this.ammo < this.maxAmmo) this.ammo++; - this.ammoTimer = 0; - } else { - this.ammoTimer += deltaTime; - } - this.particles.forEach(particle => particle.update()); - this.particles = this.particles.filter(particle => !particle.markedForDeletion); - this.explosions.forEach(explosion => explosion.update(deltaTime)); - this.explosions = this.explosions.filter(explosion => !explosion.markedForDeletion); - this.enemies.forEach(enemy => { - enemy.update(); - if (this.checkCollision(this.player, enemy)) { - enemy.markedForDeletion = true; - this.addExplosion(enemy); - for (let i = 0; i < enemy.score; i++) { - this.particles.push(new Particle(this, enemy.x + enemy.width * 0.5, enemy.y + enemy.height * 0.5)); - } - if (enemy.type === 'lucky') this.player.enterPowerUp(); - else if (!this.gameOver) this.score--; - } - this.player.projectiles.forEach(projectile => { - if (this.checkCollision(projectile, enemy)) { - enemy.lives--; - projectile.markedForDeletion = true; - this.particles.push(new Particle(this, enemy.x + enemy.width * 0.5, enemy.y + enemy.height * 0.5)); - if (enemy.lives <= 0) { - for (let i = 0; i < enemy.score; i++) { - this.particles.push(new Particle(this, enemy.x + enemy.width * 0.5, enemy.y + enemy.height * 0.5)); - } - enemy.markedForDeletion = true; - this.addExplosion(enemy); - if (enemy.type === 'hive') { - for (let i = 0; i < 5; i++) { - this.enemies.push(new Drone(this, enemy.x + Math.random() * enemy.width, - enemy.y + Math.random() * enemy.height + 0.5)); - } - } - if (!this.gameOver) this.score += enemy.score; - /*if (this.score > this.winningScore) this.gameOver = true;*/ - } - } - }); - }); - this.enemies = this.enemies.filter(enemy => !enemy.markedForDeletion); - if (this.enemyTimer > this.enemyInterval && !this.gameOver) { - this.addEnemy(); - this.enemyTimer = 0; - } else { - this.enemyTimer += deltaTime; - } - } - draw(context) { - this.background.draw(context); - this.ui.draw(context); - this.player.draw(context); - this.particles.forEach(particle => particle.draw(context)); - this.enemies.forEach(enemy => { - enemy.draw(context); - }); - this.explosions.forEach(explosion => { - explosion.draw(context); - }); - this.background.layer4.draw(context); - } - addEnemy() { - const randomize = Math.random(); - if (randomize < 0.3) this.enemies.push(new Angler1(this)); - else if (randomize < 0.6) this.enemies.push(new Angler2(this)); - else if (randomize < 0.7) this.enemies.push(new HiveWhale(this)); - else this.enemies.push(new LuckyFish(this)); - } - addExplosion(enemy) { - const randomize = Math.random(); - if (randomize < 0.5) { - this.explosions.push(new SmokeExplosion(this, enemy.x + enemy.width * 0.5, enemy.y + enemy.height * 0.5)); - } - else { - this.explosions.push(new FireExplosion(this, enemy.x + enemy.width * 0.5, enemy.y + enemy.height * 0.5)); - } - } - checkCollision(rect1, rect2) { - return (rect1.x < rect2.x + rect2.width && - rect1.x + rect1.width > rect2.x && - rect1.y < rect2.y + rect2.height && - rect1.height + rect1.y > rect2.y) - } - - } - - const game = new Game(canvas.width, canvas.height); - let lastTime = 0; - //animation loop - function animate(timeStamp) { - const deltaTime = timeStamp - lastTime; - console.log(deltaTime); - lastTime = timeStamp; - ctx.clearRect(0, 0, canvas.width, canvas.height); - game.draw(ctx); - game.update(deltaTime); - requestAnimationFrame(animate); - } - animate(0); + }); + } + + // Function to end the game + function endGame() { + gameEnded = true; + alert(`Game Over! Your score is ${score}`); + removeAllBubbles(); // Remove all remaining bubbles when game ends + } + + // Function to remove all bubbles from game area + function removeAllBubbles() { + const bubbles = document.querySelectorAll('.bubble'); + bubbles.forEach(bubble => gameArea.removeChild(bubble)); + } + + // Generate bubbles every 2 seconds + setInterval(createBubble, 2000); + + // Event listener for restart button + restartButton.addEventListener('click', function() { + removeAllBubbles(); // Remove all bubbles before restarting + score = 0; + scoreDisplay.textContent = score; + gameEnded = false; + }); }); - diff --git a/Games/Alien_Invasion/style.css b/Games/Alien_Invasion/style.css index 268a5f3b93..f705373767 100644 --- a/Games/Alien_Invasion/style.css +++ b/Games/Alien_Invasion/style.css @@ -1,34 +1,61 @@ -* { +body { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; margin: 0; - padding: 0; - box-sizing: border-box; + background-color: #f0f0f0; } -#canvas1 { - border: 5px solid black; +#game-container { + text-align: center; + background-color: #fff; + border: 1px solid #ccc; + padding: 20px; + max-width: 800px; + width: 90%; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); +} + +#game-area { + width: 100%; + max-height: 600px; + height: 90vh; + background-color: #e0e0e0; + position: relative; + overflow: hidden; +} +#score{ + font-family: monospace; + font-weight: 600; + font-size: 1.3rem; + margin: 1rem; +} +.bubble { + width: 30px; + height: 30px; + border-radius: 50%; position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background: #4d79bc; - max-width: 100%; - max-height: 100%; - font-family: 'Bangers', cursive; + cursor: pointer; } -#layer1, -#layer2, -#layer3, -#layer4, -#player, -#angler1, -#angler2, -#lucky, -#projectile, -#gears, -#hivewhale, -#drone, -#smokeExplosion, -#fireExplosion { - display: none; -} \ No newline at end of file +button{ + padding: 0.8rem 3rem; + background: black; + margin: 0.5rem; + border: 2px solid transparent; + border-radius: 0.6rem; + font-weight: 700; + color: white; +} +button:hover{ + background: transparent; + color: black; + border: 2px solid black; +} +.red { background-color: red; } +.green { background-color: green; } +.blue { background-color: blue; } +.orange { background-color: orange; } +.yellow { background-color: yellow; } +.purple { background-color: purple; }