Week 5 – Midterm Progress

Inspiration

The idea is creating a top-down shooter game. I was inspired by  Nuclear Throne, where players control a character in a confined space and must shoot incoming enemies. The thrill of dodging enemies while strategically shooting at them creates an engaging and fast-paced gameplay experience. The goal was to recreate this immersive feeling while keeping the implementation simple and beginner-friendly using p5.js.

Concept and User Interaction

The game concept revolves around a player-controlled character that moves around the screen and shoots at enemy units that spawn randomly and chase the player. The user can interact with the game in the following ways:

  • Movement: The player uses the arrow keys or WASD to move in different directions.
  • Shooting: The player shoots bullets towards the mouse cursor by pressing the spacebar.
  • Enemies: Randomly spawned enemies move towards the player and can be destroyed by bullets.
  • Survival Challenge: The player must continuously avoid enemies while shooting them down.

This simple yet engaging mechanic ensures a dynamic game experience where quick reflexes and strategic positioning are key to survival.

Designing the Code Structure

Before diving into the code, I designed a modular approach to keep the project manageable and scalable. The core elements of the game were broken down into:

  1. Player Class: Handles movement, shooting, and rendering.
  2. Bullet Class: Manages bullet behavior, movement, and collision detection.
  3. Enemy Class: Controls enemy spawning, movement, and interaction with bullets.
  4. Game Loop: Updates and renders all game elements in each frame.
  5. Collision Handling: Detects when bullets hit enemies and removes them from the game.
  6. Enemy Spawning System: Ensures a steady challenge for the player.

By structuring the game this way, each component is easy to manage and modify.

Example – Player Class:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Player {
constructor() {
this.pos = createVector(width / 2, height / 2);
this.speed = 4;
}
update() {
if (keyIsDown(UP_ARROW) || keyIsDown(87)) this.pos.y -= this.speed;
if (keyIsDown(DOWN_ARROW) || keyIsDown(83)) this.pos.y += this.speed;
if (keyIsDown(LEFT_ARROW) || keyIsDown(65)) this.pos.x -= this.speed;
if (keyIsDown(RIGHT_ARROW) || keyIsDown(68)) this.pos.x += this.speed;
this.pos.x = constrain(this.pos.x, 0, width);
this.pos.y = constrain(this.pos.y, 0, height);
}
show() {
fill(0, 255, 0);
ellipse(this.pos.x, this.pos.y, 30, 30);
}
shoot() {
if (millis() - lastShotTime > 200) {
bullets.push(new Bullet(this.pos.x, this.pos.y));
lastShotTime = millis();
}
}
}
class Player { constructor() { this.pos = createVector(width / 2, height / 2); this.speed = 4; } update() { if (keyIsDown(UP_ARROW) || keyIsDown(87)) this.pos.y -= this.speed; if (keyIsDown(DOWN_ARROW) || keyIsDown(83)) this.pos.y += this.speed; if (keyIsDown(LEFT_ARROW) || keyIsDown(65)) this.pos.x -= this.speed; if (keyIsDown(RIGHT_ARROW) || keyIsDown(68)) this.pos.x += this.speed; this.pos.x = constrain(this.pos.x, 0, width); this.pos.y = constrain(this.pos.y, 0, height); } show() { fill(0, 255, 0); ellipse(this.pos.x, this.pos.y, 30, 30); } shoot() { if (millis() - lastShotTime > 200) { bullets.push(new Bullet(this.pos.x, this.pos.y)); lastShotTime = millis(); } } }
class Player {
  constructor() {
    this.pos = createVector(width / 2, height / 2);
    this.speed = 4;
  }

  update() {
    if (keyIsDown(UP_ARROW) || keyIsDown(87)) this.pos.y -= this.speed;
    if (keyIsDown(DOWN_ARROW) || keyIsDown(83)) this.pos.y += this.speed;
    if (keyIsDown(LEFT_ARROW) || keyIsDown(65)) this.pos.x -= this.speed;
    if (keyIsDown(RIGHT_ARROW) || keyIsDown(68)) this.pos.x += this.speed;
    
    this.pos.x = constrain(this.pos.x, 0, width);
    this.pos.y = constrain(this.pos.y, 0, height);
  }

  show() {
    fill(0, 255, 0);
    ellipse(this.pos.x, this.pos.y, 30, 30);
  }

  shoot() {
    if (millis() - lastShotTime > 200) {
      bullets.push(new Bullet(this.pos.x, this.pos.y));
      lastShotTime = millis();
    }
  }
}

Identifying and Addressing Key Challenges

One of the most challenging parts of the project is collision detection between bullets and enemies. Ensuring that fast-moving bullets accurately register hits on enemies can be tricky, especially in a game with rapid movement and frequent object interactions. Also, I wanted to add a multiplayer gameplay experience, so 2 players could play in the same session. However, I do not think it is possible without the use of socket.io.

Next Steps

Moving forward, possible improvements could include:

  • Adding different enemy types with unique behaviors.
  • Implementing a score system to track progress.
  • Introducing power-ups to enhance gameplay variety.
  • Multiplayer Mode: Implementing real-time multiplayer gameplay using Socket.IO so that two players can play together from different machines. This would involve syncing player movement, bullets, and enemies across connected clients through a Node.js server.

By integrating multiplayer functionality, the game could become even more engaging and interactive. Using real-time communication, players could strategize together, compete for the highest score, or even introduce cooperative play against waves of enemies. Setting up server-side logic to handle multiple players efficiently is a challenge but would greatly enhance the gaming experience.

Leave a Reply