Created
February 2, 2021 09:31
-
-
Save Tseberechts/8a6058371ad2d5494b53470c6648d413 to your computer and use it in GitHub Desktop.
robots vs aliens ES6
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const canvas = document.getElementById('canvas1'); | |
const ctx = canvas.getContext('2d'); | |
canvas.width = 900; | |
canvas.height = 600; | |
// global variables | |
const cellSize = 100; | |
const cellGap = 3; | |
const gameGrid = []; | |
const defenders = []; | |
const enemies = []; | |
const enemyPosition = []; | |
let numberOfResources = 300; | |
let enemiesInterval = 600; | |
let frame = 0; | |
let gameOver = false; | |
const projectiles = []; | |
let score = 0; | |
const resources = []; | |
const winningScore = 50; | |
// mouse | |
const mouse = { | |
x: 10, | |
y: 10, | |
width: .1, | |
height: .1 | |
} | |
let canvasPosition = canvas.getBoundingClientRect(); | |
canvas.addEventListener('mousemove', e => { | |
mouse.x = e.x - canvasPosition.left; | |
mouse.y = e.y - canvasPosition.top; | |
}) | |
canvas.addEventListener('mouseleave', e => { | |
mouse.x = undefined; | |
mouse.y = undefined; | |
}) | |
// game board | |
const controlsBar = { | |
width: canvas.width, | |
height: cellSize, | |
} | |
class Cell { | |
constructor(x, y) { | |
this.x = x; | |
this.y = y; | |
this.width = cellSize; | |
this.height = cellSize; | |
} | |
draw() { | |
if (mouse.x && mouse.y && collision(this, mouse)) { | |
ctx.strokeStyle = 'black'; | |
ctx.strokeRect(this.x, this.y, this.width, this.height); | |
} | |
} | |
} | |
function createGrid() { | |
for (let y = cellSize; y < canvas.height; y += cellSize) { | |
for (let x = 0; x < canvas.width; x += cellSize) { | |
gameGrid.push(new Cell(x, y)); | |
} | |
} | |
} | |
createGrid(); | |
function handleGameGrid() { | |
gameGrid.forEach(cell => cell.draw()); | |
} | |
// projectiles | |
class Projectile { | |
constructor(x, y) { | |
this.x = x; | |
this.y = y; | |
this.width = 10; | |
this.height = 10; | |
this.power = 20; | |
this.speed = 5; | |
} | |
update() { | |
this.x += this.speed; | |
return this; | |
} | |
draw() { | |
ctx.fillStyle = 'black'; | |
ctx.beginPath(); | |
ctx.arc(this.x, this.y, this.width, 0, Math.PI * 2); | |
ctx.fill(); | |
} | |
} | |
function handleProjectiles() { | |
projectiles.forEach((projectile, i) => { | |
projectile.update().draw(); | |
enemies.forEach(enemy => { | |
if (collision(projectile, enemy)) { | |
enemy.health -= projectile.power; | |
projectiles.splice(i, 1); | |
} | |
}) | |
if (projectile.x > canvas.width - cellSize) { | |
projectiles.splice(i, 1); | |
} | |
}) | |
} | |
// defenders | |
class Defender { | |
constructor(x, y) { | |
this.x = x; | |
this.y = y; | |
this.width = cellSize - cellGap * 2; | |
this.height = cellSize - cellGap * 2; | |
this.shooting = false; | |
this.health = 100; | |
this.timer = 0; | |
} | |
update() { | |
if (this.shooting) { | |
this.timer++; | |
if (this.timer % 100 === 0) { | |
projectiles.push(new Projectile(this.x + 70, this.y + 50)); | |
} | |
} else { | |
this.timer = 0; | |
} | |
return this; | |
} | |
draw() { | |
ctx.fillStyle = 'blue'; | |
ctx.fillRect(this.x, this.y, this.width, this.height); | |
ctx.fillStyle = 'gold'; | |
ctx.font = '30px Orbitron'; | |
ctx.fillText(Math.floor(this.health), this.x + 15, this.y + 25); | |
} | |
} | |
canvas.addEventListener('click', () => { | |
const gridPositionX = mouse.x - (mouse.x % cellSize) + cellGap; | |
const gridPositionY = mouse.y - (mouse.y % cellSize) + cellGap; | |
if (gridPositionY < cellSize) return; | |
if (defenders.find(defender => defender.x === gridPositionX && defender.y === gridPositionY)) return; | |
let defenderCost = 100; | |
if (numberOfResources >= defenderCost) { | |
defenders.push(new Defender(gridPositionX, gridPositionY)); | |
numberOfResources -= defenderCost; | |
} | |
}) | |
function handleDefenders() { | |
defenders.forEach((defender, i) => { | |
defender.update().draw(); | |
if(enemyPosition.includes(defender.y)){ | |
defender.shooting = true; | |
} else { | |
defender.shooting = false; | |
} | |
enemies.forEach(enemy => { | |
if (collision(defender, enemy)) { | |
enemy.movement = 0; | |
defender.health -= .2; | |
} | |
if (defender.health <= 0) { | |
defenders.splice(i, 1); | |
enemy.movement = enemy.speed; | |
} | |
} | |
) | |
} | |
) | |
} | |
// enemies | |
class Enemy { | |
constructor(verticalPosition) { | |
this.x = canvas.width; | |
this.y = verticalPosition; | |
this.width = cellSize - cellGap * 2; | |
this.height = cellSize - cellGap * 2; | |
this.speed = Math.random() * .2 + .4; | |
this.movement = this.speed; | |
this.health = 100; | |
this.maxHealth = this.health; | |
} | |
update() { | |
this.x -= this.movement; | |
return this; | |
} | |
draw() { | |
ctx.fillStyle = 'red'; | |
ctx.fillRect(this.x, this.y, this.width, this.height); | |
ctx.fillStyle = 'black'; | |
ctx.font = '30px Orbitron'; | |
ctx.fillText(Math.floor(this.health), this.x + 15, this.y + 25); | |
} | |
} | |
function handleEnemies() { | |
enemies.forEach((enemy, i) => { | |
enemy.update().draw(); | |
if (enemy.x < 0) { | |
gameOver = true; | |
} | |
if (enemy.health <= 0) { | |
let gainedResources = enemy.maxHealth / 5; | |
numberOfResources += gainedResources; | |
score += gainedResources; | |
const positionIndex = enemyPosition.indexOf(enemy.y); | |
enemyPosition.splice(positionIndex, 1); | |
enemies.splice(i, 1); | |
} | |
}); | |
if (frame % enemiesInterval === 0 && score < winningScore) { | |
let verticalPosition = Math.floor(Math.random() * 5 + 1) * cellSize + cellGap; | |
enemies.push(new Enemy(verticalPosition)); | |
enemyPosition.push(verticalPosition); | |
if (enemiesInterval > 120) enemiesInterval -= 50; | |
} | |
} | |
// resources | |
const amounts = [20, 30, 40] | |
class Resource { | |
constructor() { | |
this.x = Math.random() * (canvas.width - cellSize); | |
this.y = (Math.floor(Math.random() * 5) + 1) * cellSize + 25; | |
this.width = cellSize * .6; | |
this.height = cellSize * .6; | |
this.amount = amounts[Math.floor(Math.random() * amounts.length)]; | |
} | |
draw() { | |
ctx.fillStyle = 'green'; | |
ctx.fillRect(this.x, this.y, this.width, this.height); | |
ctx.fillStyle = 'black'; | |
ctx.font = '20px Orbitron'; | |
ctx.fillText(this.amount, this.x + 15, this.y + 25); | |
} | |
} | |
function handleResources() { | |
if(frame !== 0 && frame % 500 === 0 && score < winningScore) { | |
resources.push(new Resource()) | |
} | |
resources.forEach((resource, i) => { | |
resource.draw(); | |
if(mouse.x && mouse.y && collision(resource, mouse)){ | |
numberOfResources += resource.amount; | |
resources.splice(i, 1); | |
} | |
}) | |
} | |
// utils | |
function handleGameStatus() { | |
ctx.fillStyle = 'gold'; | |
ctx.font = '30px Orbitron'; | |
ctx.fillText(`Resources: ${numberOfResources}`, 20, 35); | |
ctx.fillText(`Score: ${score}`, 20, 75); | |
if (gameOver) { | |
ctx.fillStyle = 'black'; | |
ctx.font = '90px Orbitron'; | |
ctx.fillText('GAME OVER', 153, 330); | |
} | |
if(score > winningScore && enemies.length === 0) { | |
ctx.fillStyle = 'black'; | |
ctx.font = '60px Orbitron'; | |
ctx. fillText('LEVEL COMPLETE', 130, 300); | |
ctx.font = '30px Orbitron'; | |
ctx.fillText(`You win with ${score} points!`, 134, 340); | |
} | |
} | |
function animate() { | |
ctx.clearRect(0, 0, canvas.width, canvas.height); | |
ctx.fillStyle = 'blue'; | |
ctx.fillRect(0, 0, controlsBar.width, controlsBar.height); | |
handleGameGrid(); | |
handleResources(); | |
handleDefenders(); | |
handleEnemies(); | |
handleProjectiles(); | |
handleGameStatus(); | |
frame++; | |
if (!gameOver) requestAnimationFrame(animate); | |
} | |
animate(); | |
function collision(first, second) { | |
return !( | |
first.x > second.x + second.width || | |
first.x + first.width < second.x || | |
first.y > second.y + second.height || | |
first.y + first.height < second.y | |
); | |
} | |
window.addEventListener('resize', () => { | |
canvasPosition = canvas.getBoundingClientRect(); | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment