Below is the game I have created, a retro styled classic: Space Shooter!
and below is the code for this game:
//Declaring all variables to be used let bullets = []; let enemies = []; let stars = []; let powerups = []; let gamestate; let posterImage; let fighter; let player; let laser; let enemy; let score = 0; let title_screen_audio; let playing_screen_audio; let end_screen_audio; let laser_sound_effect; let enemySpawnRate =1; let timeElapsed = 0; function preload() { posterImage = loadImage('SpaceShooterBackground.png'); //Loading main menu fighter = loadImage('NicePng_spaceship-png_138961.png'); //Loading spaceship laser = loadImage('LaserBullet.png'); //Loading laser bullet enemy = loadImage('invader.png'); //Loading enemies font = loadFont('GameOverFont.ttf'); //Loading Game Over Screen Font title_screen_audio = loadSound("SkyFire (Title Screen).mp3"); playing_screen_audio = loadSound("Battle in the Stars.mp3"); //Loading menu music end_screen_audio = loadSound("gameEndMusic.mp3"); //Load Game Over Screen Music laser_sound_effect = loadSound("lasershot.wav"); //Load laser sound effect } function setup() { createCanvas(400, 600); gamestate = 'menu'; //Setting gamestate menu player = new Spaceship(67, 61); //Initializing Sapceship class as the player for (let i = 0; i < 100; i++) { stars[i] = new Star(random(width), random(height), random(1, 5)); //Randomly generating stars } } function draw() { if (gamestate == 'menu') { image(posterImage, 0, 0, width, height); //Displaying menu screen if gamestate is menu if (!title_screen_audio.isPlaying()) { title_screen_audio.play(); //Plays menu music } } if (gamestate == 'playing') { title_screen_audio.stop(); //Stops menu music when gamestate is playing if (!playing_screen_audio.isPlaying()) { playing_screen_audio.play(); //Plays battle music } background(1, 22, 64); player.show(); for (let star of stars) { star.show(); //Displaying stars } // Add enemies randomly if (frameCount % (60 / enemySpawnRate) == 0) { let enemy = new Enemy(random(width-50), -50, random(1, 4)); enemies.push(enemy); } for (let i = 0; i < bullets.length; i++) { bullets[i].update(); //Adding velocity to bullets bullets[i].show(); //Displaying bullets for (let j = 0; j < enemies.length; j++) { let enemyHitbox = enemies[j].getHitbox(); //Initializing enemies with hitbox if (bullets[i].hits(enemyHitbox)) { bullets.splice(i, 1); //Remove bullets when it hits an enemy enemies[j].hits(); //Registers hit to enemy score += 1; //Incremements score on hit enemies.splice(j, 1); // remove the enemy object from the array break; } } } for (let i = 0; i < enemies.length; i++) { enemies[i].update(); //Makes enemies fall enemies[i].show(); //Displays enemies } let anyEnemyReachedBottom = false; // flag to indicate if any enemy has reached the bottom for (let i = 0; i < enemies.length; i++) { if (enemies[i].reachedBottomFlag) { anyEnemyReachedBottom = true; //Turns true when enemy reaches bottom break; } } if (anyEnemyReachedBottom) { gamestate = 'gameover'; //Sets gamestate to gameover once enemy reaches the bottom } textSize(20); strokeWeight(1); textFont(font); fill(255); text("Score: " + score, 10, 30); //Displays score at top left } if (gamestate == 'gameover') { playing_screen_audio.stop(); //Stops battle music if (!end_screen_audio.isPlaying()) { end_screen_audio.play(); //Plays defeat music } background(1, 22, 64); for (let star of stars) { star.show(); //Displays stars } textSize(30); strokeWeight(1); fill(255); textFont(font); text("Game Over", width / 2 - 80, height / 2 - 20); text("Score: " + score, width / 2 - 65, height / 2 + 20); text("Press Space to retry!", width / 2 - 150, height / 2 + 60); } timeElapsed += deltaTime / 1000; if (timeElapsed >= 40) { // increase spawn rate every 40 seconds enemySpawnRate++; timeElapsed = 0; } } function mouseClicked() { if (gamestate == 'menu') { gamestate = 'playing'; //Changes gameststate on mouseclick } if (gamestate == 'playing') { let bullet = new Bullet(mouseX + 3, height - 20, 10); bullets.push(bullet); //Fires bullet on every click laser_sound_effect.play(); //Plays laser sound on every click } } function keyPressed(){ if (key == ' ' && gamestate == 'gameover'){ score = 0; bullets = []; enemies = []; restartGame(); end_screen_audio.stop(); //Restarts game by pressing space on game over screen } } function restartGame() { gamestate = 'playing'; enemySpawnRate = 1; } class Bullet { //Setting variables constructor(x, y, velocity) { this.x = x; this.y = y; this.velocity = velocity; this.size = 20; } update() { this.y -= this.velocity; //Fires bullet upward } show() { image(laser, this.x - this.size/2, this.y - this.size/2, this.size, this.size); //Laser image } hits(hitbox) { let d = dist(this.x, this.y, hitbox.x + hitbox.width/2, hitbox.y + hitbox.height/2); if (d < (this.size + hitbox.width)/2) { return true; //Hitbox registration } else { return false; } } } class Spaceship { constructor(x,y) { this.x = x; this.y = y; // Setting variables } show(){ //Prevents fighter from going out of bounds if (mouseX - 30 < 0) { image(fighter,0,height-50,this.x,this.y); } else if (mouseX - 30 > width) { image(fighter,width - this.x,height-50,this.x,this.y); } else { image(fighter,mouseX-30,height-50,this.x,this.y); } } } //Creates stars in background class Star { constructor(x, y, size) { this.x = x; this.y = y; this.size = size; } show() { stroke(255); strokeWeight(this.size); point(this.x, this.y); } } class Enemy { constructor(x, y, velocity) { this.x = x; this.y = y; this.velocity = velocity; this.size = 30; this.reachedBottomFlag = false; // flag to indicate if this enemy has reached the bottom } update() { this.y += this.velocity; if (this.y >= height) { this.reachedBottomFlag = true; //Detects if enemy has reached bottom } } show() { image(enemy, this.x, this.y, this.size, this.size); //Creating enemies images } hits() { this.velocity = 0; //Sets velocity to 0 on hit } getHitbox() { return { x: this.x, y: this.y, width: this.size, height: this.size //Creates hitbox of enemies } } }
I was inspired by the many retro classic games. These games bring a long a sense of nostalgia that no other games bring. Since I am an avid space enjoyer and all things sci-fi, I decided to combine these 2 concepts into the game Space Shooter. The story is you are a space fighter defending the human race from these purple invaders! Your mission is to prevent these invaders to breaking through into your back line.
Behind the scenes, I used Canva in order to create the opening menu of this game. I then created separate classes for the player’s spaceship, enemies, bullets, and stars. I tied the spaceship position and laser firing position to the mouseX coordinate while invaders fall between a random set of x values. I essentially created a hitbox for the enemies so the laser can register whether it hits an enemy or not. I also made it so that it tracks how long the game goes on and after every 30 seconds, the spawn rate of the enemies increasing making the game get progressively difficult. Just for some extra personalization, I made it so the stars in the background are randomly generated so there is always something that is a tiny bit new in every playthrough.
I am especially proud of making the hitbox method in order to deal with collision. I initially struggled with collision but after researching and messing around, I managed to finally solve it and in quite the efficient way I like to think. I’m also proud of the laser bullet and invader sprites. I managed to find a good vector sprite for the spaceship but importing different sized bullets and invaders could be messy. So, I made them on my own using online software allowing me to personalize them into whatever size or shape I need. This further simplified my work and going forward and gave it a bit more of my own touch and creativity into this project.
I still feel as there are many more improvements that can be made into this. For starters, I could add other enemy types where they require multiple hits in order to be destroyed. I can also add powerups where the game could be slowed for example. I was also told about adding a pause screen which I initially thought wouldn’t fit as it is a retro game where pause menus didn’t exist but still could be added as a quality-of-life improvement.