
This is the continuation of the part 2 of this article series about "Making a Simple Space Shooter using p5.js and ES6".
What we have accomplished so far is to make the Player class fire bullets and to generate Enemies.
Next is let's make the game re initialize when, an Enemy collide with the Player.
1. Gameover function
renderPlayer() {
this.player.pos.x = constrain(mouseX, this.player.size.x / 2, width - (this.player.size.x / 2));
this.player.update();
this.player.show();
const bullet = this.player.fireBullet(this.assetManager.bulletImg);
if(bullet) {
this.bullets.push(bullet);
}
if (this.enemies.reduce((acc, e) => acc || e.isCollided(this.player.pos, this.player.size),false)) {
this.init();
}
}
We have updated the our renderPlayer() to check if it has collided to an enemy, then repeat the game otherwise continue.
2. Stars and score
On the popular Messenger game Everwing, player earns score, when he/she catches the falling coins. Let's make our own version of it using stars as alternative to coins.
Let's update our GameManager class, init() method :
init() {
this.bullets = [];
this.enemies = [];
this.enemyGenerateSpeed = 200;
this.enemySpeed = 2;
this.stars = [];
this.score = 0;
this.player = new Player(
createVector(width / 2, height - 100),
createVector(0, 0),
this.assetManager.playerImg,
createVector(75, 75),
100,
'player'
);
}
We have added two new variables in the init() function:
- stars - will contains all the stars that is currently in the canvas.
- score - will the count of stars that the player catches
Let's now update our renderEnemies method inside the GameManager class, to create a star every time an enemy dies.
renderEnemies() {
this.enemies.forEach(e => {
e.update();
e.show();
});
this.enemies = this.enemies.filter(e => {
let isDead = e.life < 0;
if (isDead) {
this.stars.push(new GameObject( // creates a new star and push it in the stars array
e.pos,
createVector(random(-1, 1), random(3, 6)), // random velocity
this.assetManager.starImg,
createVector(25, 25),
60,
'star'
))
}
return !isDead;
});
}
After that, we just need to show the stars by creating a new method inside GameManager class named renderStars(), it shows and updates star's position and also check if the star collided to the player
remove the star and increments the score.
renderStars() {
this.stars.forEach(s => {
s.update();
s.show();
});
this.stars = this.stars.filter(s => {
const isCollided = s.isCollided(this.player.pos, this.player.size);
this.score += (isCollided) ? 1 : 0; // increments the score if the player has collided to the star
return !isCollided;
});
}
Let's now create a new method on our GameManager class named renderScore(), to display the score :
renderScore() {
push();
translate(10, 10);
image(this.assetManager.starImg, 0, 0, 30, 30);
fill(255);
textSize(30);
text(`: ${this.score}`, 40, 28);
pop();
}
Now we are all set, let's call all the new methods we have added, in the update method of our GameManager class:
update() {
this.renderPlayer();
this.renderBullets();
this.renderEnemies();
this.generateEnemy();
this.renderStars();
this.renderScore();
}
Our GameManager class now should look like this:
class GameManager {
constructor() {
this.assetManager = new AssetManager();
}
init() {
this.bullets = [];
this.enemies = [];
this.enemyGenerateSpeed = 200;
this.enemySpeed = 2;
this.stars = [];
this.score = 0;
this.player = new Player(
createVector(width / 2, height - 100),
createVector(0, 0),
this.assetManager.playerImg,
createVector(75, 75),
100,
'player'
);
}
loadAssets() {
this.assetManager.preload();
}
update() {
this.renderPlayer();
this.renderBullets();
this.renderEnemies();
this.generateEnemy();
this.renderStars();
this.renderScore();
}
renderBullets() {
this.bullets.forEach(b => {
b.update();
b.show();
});
this.bullets = this.bullets.filter(b => {
let isCollided = false;
this.enemies = this.enemies.map(e => {
if (!isCollided && b.isCollided(e.pos, e.size)) {
e.life -= this.player.damage;
isCollided = true;
}
return e;
});
return !(b.pos.y < 0 || isCollided);
});
}
renderPlayer() {
this.player.pos.x = constrain(mouseX, 37.5, width - 37.5);
this.player.update();
this.player.show();
const bullet = this.player.fireBullet(this.assetManager.bulletImg);
if (bullet) {
this.bullets.push(bullet);
}
}
generateEnemy() {
if (frameCount % this.enemyGenerateSpeed === 0) {
const enemyCount = random(2, 6);
let posX = [0, 1, 2, 3, 4, 5];
[...Array(parseInt(enemyCount)).keys()].forEach(a => {
let xIndex = posX.splice(parseInt(random(0, posX.length - 1)), 1)[0];
this.enemies.push(new GameObject(
createVector((xIndex * 75) + 37.5, 0 - 75),
createVector(0, this.enemySpeed),
random(this.assetManager.enemiesImg),
createVector(70, 70),
60,
'enemy'
));
})
}
}
renderEnemies() {
this.enemies.forEach(e => {
e.update();
e.show();
});
this.enemies = this.enemies.filter(e => {
let isDead = e.life < 0;
if (isDead) {
this.stars.push(new GameObject(
e.pos,
createVector(random(-1, 1), random(3, 6)), // random velocity
this.assetManager.starImg,
createVector(25, 25),
60,
'star'
))
}
return !isDead;
});
}
renderStars() {
this.stars.forEach(s => {
s.update();
s.show();
});
this.stars = this.stars.filter(s => {
const isCollided = s.isCollided(this.player.pos, this.player.size);
this.score += (isCollided) ? 1 : 0;
return !isCollided;
});
}
renderScore() {
push();
translate(10, 10);
image(this.assetManager.starImg, 0, 0, 30, 30);
fill(255);
textSize(30);
text(`: ${this.score}`, 40, 28);
pop();
}
}
After we run our game it will look like this:
And that concludes our article series.
Source File: https://github.com/onecompileman/sample-space-shooter