Skip to content

Instantly share code, notes, and snippets.

@David-Else
Last active June 20, 2018 13:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save David-Else/33f5bddc1bc2d0f1f8a4a9c104b820a2 to your computer and use it in GitHub Desktop.
Save David-Else/33f5bddc1bc2d0f1f8a4a9c104b820a2 to your computer and use it in GitHub Desktop.
es6-zombie-attack-bundle
/* https://www.elsewebdevelopment.com/ */
class OnScreenObject {
constructor({ xPosition, yPosition }) {
this.xPosition = xPosition;
this.yPosition = yPosition;
}
move() {
this.xPosition += this.xSpeed;
this.yPosition += this.ySpeed;
}
rotate(degreesToRotate) {
this.angle += degreesToRotate;
}
draw(ctx) {
ctx.save();
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.translate(
this.xPosition + this.width / 2,
this.yPosition + this.height / 2,
);
if (this.angle !== null) {
ctx.rotate(this.angle * (Math.PI / 180));
}
ctx.fillRect(this.width / -2, this.height / -2, this.width, this.height);
ctx.restore();
}
detectCollision(other) {
const left = this.xPosition;
const right = this.xPosition + this.width;
const top = this.yPosition;
const bottom = this.yPosition + this.height;
const otherLeft = other.xPosition;
const otherRight = other.xPosition + other.width;
const otherTop = other.yPosition;
const otherBottom = other.yPosition + other.height;
return !(
left > otherRight ||
right <= otherLeft ||
top >= otherBottom ||
bottom <= otherTop
);
}
}
class Hero extends OnScreenObject {
constructor({ xPosition, yPosition }) {
super({ xPosition, yPosition });
this.angle = 0;
this.speed = 1;
this.color = 'red';
this.width = 25;
this.height = 50;
this.alive = true;
this.firePaused = false;
}
}
class Zombie extends OnScreenObject {
constructor({ xPosition, yPosition }) {
super({ xPosition, yPosition });
this.width = 15;
this.height = 15;
this.color = 'green';
this.walkingSpeed = 0.1;
this.xSpeed = null;
this.ySpeed = null;
}
directTowardsHero(hero) {
if (hero.xPosition > this.xPosition) {
this.xSpeed = this.walkingSpeed;
} else {
this.xSpeed = -this.walkingSpeed;
}
if (hero.yPosition > this.yPosition) {
this.ySpeed = this.walkingSpeed;
} else {
this.ySpeed = -this.walkingSpeed;
}
}
}
class Bullet extends OnScreenObject {
constructor({ xPosition, yPosition, angle }) {
super({ xPosition, yPosition });
this.angle = angle;
this.xSpeed = 1;
this.ySpeed = 1;
this.width = 5;
this.height = 15;
this.color = 'gray';
}
move() {
this.xPosition += this.xSpeed * Math.sin(this.angle * (Math.PI / 180));
this.yPosition -= this.ySpeed * Math.cos(this.angle * (Math.PI / 180));
}
}
class Text extends OnScreenObject {
constructor({ xPosition, yPosition }) {
super({ xPosition, yPosition });
}
// overwrite inherited method from onScreenObject
draw(ctx, numberOfZombies, numberOfBullets, lives) {
ctx.font = '25px Arial';
ctx.fillText(`Zombies ${numberOfZombies}`, this.xPosition, this.yPosition);
ctx.fillText(
`Bullets ${numberOfBullets}`,
this.xPosition,
this.xPosition + 50,
);
ctx.fillText(`Lives ${lives}`, this.xPosition, this.xPosition + 75);
}
}
class Boundaries extends OnScreenObject {
constructor({ xPosition, yPosition, width, height }) {
super({ xPosition, yPosition, width, height });
}
}
class Game {
constructor(canvas) {
this.canvasWidth = canvas.width;
this.canvasHeight = canvas.height;
this.ctx = canvas.getContext('2d');
this.options = {
lives: 3,
numberOfBullets: null,
numberOfZombies: null,
};
this.hero = new Hero({
xPosition: this.canvasWidth / 2,
yPosition: this.canvasHeight / 2,
});
this.text = new Text({
xPosition: 10,
yPosition: 35,
});
this.boundaries = new Boundaries({
xPosition: 0,
yPosition: 0,
width: this.canvasWidth,
height: this.canvasHeight,
});
this.sounds = {
playerShoots: new Audio('./assets/shoot.wav'),
zombieDies: new Audio('./assets/invaderkilled.wav'),
playerDies: new Audio('./assets/explosion.wav'),
};
this.zombies = [];
this.bullets = [];
}
createZombies() {
function randomOnScreenPosition(axisLength, heroPosition) {
const distanceFromHeroRequired = 10;
const randomPos = Math.round(Math.random() * axisLength);
return randomPos > heroPosition
? randomPos + axisLength / distanceFromHeroRequired
: randomPos - axisLength / distanceFromHeroRequired;
}
for (let i = 0; i < this.options.numberOfZombies; i += 1) {
this.zombies.push(
new Zombie({
xPosition: randomOnScreenPosition(
this.canvasWidth,
this.hero.xPosition,
),
yPosition: randomOnScreenPosition(
this.canvasHeight,
this.hero.yPosition,
),
}),
);
}
}
createBullet() {
this.bullets.push(
new Bullet({
xPosition: this.hero.xPosition + this.hero.width / 2,
yPosition: this.hero.yPosition + this.hero.height / 2,
angle: this.hero.angle,
}),
);
}
deleteZombie(zombieIndex) {
this.zombies.splice(zombieIndex, 1);
this.options.numberOfZombies -= 1;
}
deleteBullet(bulletIndex) {
this.bullets.splice(bulletIndex, 1);
}
detectCollision() {
// outer loop for zombies
this.zombies.forEach((zombie, index) => {
if (this.hero.detectCollision(zombie)) {
this.hero.alive = false;
return;
}
// inner loop for bullets
this.bullets.forEach((bullet, innerIndex) => {
if (zombie.detectCollision(bullet)) {
this.deleteZombie(index);
this.deleteBullet(innerIndex);
} else if (!this.boundaries.detectCollision(bullet)) {
this.deleteBullet(innerIndex);
}
});
});
}
// make all zombies go towards the hero
animateZombies() {
this.zombies.forEach(zombieInArray => {
zombieInArray.directTowardsHero(this.hero);
zombieInArray.move();
zombieInArray.draw(this.ctx);
});
}
// make all bullets on the screen continue firing in their path
animateBullets() {
this.bullets.forEach(bulletInArray => {
bulletInArray.move();
bulletInArray.draw(this.ctx);
});
}
clearCanvas() {
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
}
}
// keyboard handler
let rightPressed;
let leftPressed;
let firePressed;
function keyHandler(event) {
switch (event.code) {
case 'KeyF':
firePressed = event.type === 'keydown';
break;
case 'ArrowLeft':
event.preventDefault();
leftPressed = event.type === 'keydown';
break;
case 'ArrowRight':
event.preventDefault();
rightPressed = event.type === 'keydown';
break;
// no default
}
}
addEventListener('keydown', keyHandler);
addEventListener('keyup', keyHandler);
// Create the main game object that contains all the state and on-screen characters
const game = new Game(document.getElementById('canvas'));
// creates the bullet while making a sound and decreasing the bullets counter
function fireBullet() {
game.sounds.playerShoots.currentTime = 0;
game.sounds.playerShoots.play();
game.createBullet();
game.options.numberOfBullets -= 1;
}
// reacts to the incomming key press data from the key handler module
function actOnKeyPress() {
if (rightPressed) {
game.hero.rotate(game.hero.speed);
} else if (leftPressed) {
game.hero.rotate(-game.hero.speed);
}
if (!firePressed) {
game.hero.firePaused = false;
}
if (firePressed && game.options.numberOfBullets > 0) {
if (!game.hero.firePaused) {
fireBullet();
game.hero.firePaused = true;
}
}
}
function looseALife() {
console.log('You died!');
setTimeout(() => {
game.hero.alive = true;
game.options.lives -= 1;
init();
}, 2000);
}
function mainLoop() {
if (game.hero.alive) {
game.clearCanvas();
game.text.draw(
game.ctx,
game.options.numberOfZombies,
game.options.numberOfBullets,
game.options.lives,
);
game.hero.draw(game.ctx);
game.detectCollision();
game.animateBullets();
game.animateZombies();
actOnKeyPress();
requestAnimationFrame(mainLoop);
} else {
looseALife();
}
}
function init() {
game.options.numberOfZombies = 50;
game.options.numberOfBullets = 100;
game.zombies = [];
game.bullets = [];
game.createZombies();
mainLoop();
}
init();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment