DEV Community

Cover image for πŸš€ Building a Futuristic Neon Space Shooter Game with Epic Boss Battles By Gladiators Battle
Gladiators Battle
Gladiators Battle

Posted on

πŸš€ Building a Futuristic Neon Space Shooter Game with Epic Boss Battles By Gladiators Battle

In the ever-evolving world of web development, creating engaging and interactive experiences is key to captivating your audience. Today, we'll embark on an exciting journey to build a futuristic neon space shooter game featuring advanced animations, addictive gameplay, and epic boss battles. This game is entirely crafted using HTML5 Canvas, CSS3, and Vanilla JavaScript.

Check out the live demo on CodePen https://codepen.io/HanGPIIIErr/pen/dPbbwPR

🌟 What We'll Build

  • Advanced Animations: A visually stunning game with neon effects and smooth transitions.
  • Addictive Gameplay: Control a spaceship, defeat waves of enemies, and face challenging bosses.
  • Epic Boss Battles: Bosses appear every 1000 points, growing stronger each time.
  • Futuristic Design: A sleek neon aesthetic that enhances the gaming experience.
  • Responsive Controls: Smooth and responsive controls for optimal player experience.

πŸ›  Technologies Used

  • HTML5 Canvas for rendering game graphics.
  • CSS3 for styling and visual enhancements.
  • JavaScript (ES6) for game logic and interactivity.
  • Responsive Design principles to ensure compatibility across devices.

πŸ”§ Step-by-Step Tutorial

  1. Setting Up the Project Structure Create the following files in your project directory:

index.html β€” The main HTML file.
style.css β€” The CSS styles.
script.js β€” The JavaScript code.

  1. Crafting the HTML Structure

We'll start by setting up the basic HTML structure, including the game canvas, HUD (Heads-Up Display), and overlay elements.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Futuristic Neon Space Shooter Game</title>
  <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@700&display=swap" rel="stylesheet">
  <link rel="stylesheet" href="style.css">
</head>
<body>

<!-- Futuristic Overlay Elements -->
<div class="overlay">
  <div class="grid"></div>
  <div class="circuits"></div>
</div>

<div class="game-container">
  <!-- Heads-Up Display (HUD) -->
  <div class="hud">
    <div class="score">
      Score: <span id="score">0</span>
    </div>
    <div class="lives">
      Lives: <span id="lives">3</span>
    </div>
    <div class="instructions">
      <div class="control">
        <span class="icon">β¬†οΈβ¬‡οΈβ¬…οΈβž‘οΈ</span>
        <span class="text">Move</span>
      </div>
      <div class="control">
        <span class="icon">⎡</span>
        <span class="text">Shoot</span>
      </div>
    </div>
  </div>

  <!-- Game Canvas -->
  <canvas id="gameCanvas"></canvas>

  <!-- Game Over Screen -->
  <div class="game-over" id="gameOver">
    <h1>Game Over</h1>
    <p>Your Score: <span id="finalScore"></span></p>
    <button id="restartButton">Restart</button>
  </div>
</div>

<!-- Futuristic Background Elements -->
<div class="background-elements">
  <!-- Animated Stars -->
  <div class="stars"></div>
  <!-- Glowing Nebula -->
  <div class="nebula"></div>
</div>

<script src="script.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Futuristic Overlay Elements: These add dynamic visual effects like grids and circuits.
  • Game Container: Contains the HUD, game canvas, and game over screen.
  • HUD: Displays the score, lives, and instructions with minimalist icons.
  • Background Elements: Includes animated stars and a glowing nebula for depth.
  1. Styling with CSS

Next, we'll bring the game to life with CSS, enhancing the visuals to achieve a futuristic neon aesthetic.

/* Global Styles */
body {
  margin: 0;
  padding: 0;
  background: radial-gradient(circle at center, #0d0d0d, #000000 70%);
  font-family: 'Orbitron', sans-serif;
  overflow: hidden;
  color: #00f6ff;
}

/* Game Container */
.game-container {
  position: relative;
  width: 100%;
  height: 100vh;
  overflow: hidden;
}

/* Game Canvas */
#gameCanvas {
  display: block;
  background: transparent;
  position: relative;
  z-index: 2;
}

/* HUD Styling */
.hud {
  position: absolute;
  top: 20px;
  left: 20px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  color: #00f6ff;
  z-index: 5;
  font-size: 18px;
  text-shadow: 0 0 10px #00f6ff;
}

.hud .score,
.hud .lives {
  margin: 5px 0;
}

.hud .instructions {
  margin-top: 10px;
  display: flex;
  flex-direction: column;
  font-size: 16px;
  color: #00f6ff;
  opacity: 0.9;
}

.hud .instructions .control {
  display: flex;
  align-items: center;
  margin: 3px 0;
}

.hud .instructions .icon {
  font-size: 20px;
  margin-right: 8px;
  display: flex;
  align-items: center;
}

.hud .instructions .text {
  font-size: 16px;
}

/* Game Over Screen */
.game-over {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(13, 13, 13, 0.95);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #00f6ff;
  text-align: center;
  z-index: 10;
  display: none;
}

.game-over h1 {
  font-size: 72px;
  margin: 0;
  text-shadow: 0 0 20px #00f6ff, 0 0 30px #00f6ff;
}

.game-over p {
  font-size: 24px;
}

#restartButton {
  padding: 15px 30px;
  font-size: 24px;
  color: #00f6ff;
  background: #111;
  border: none;
  border-radius: 10px;
  cursor: pointer;
  margin-top: 20px;
  box-shadow: 0 0 20px rgba(0, 246, 255, 0.5);
  transition: background 0.3s;
}

#restartButton:hover {
  background: #222;
}

/* Overlay Effects */
.overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 3;
  pointer-events: none;
}

.overlay .grid {
  position: absolute;
  width: 100%;
  height: 100%;
  background: repeating-linear-gradient(
      0deg,
      transparent,
      transparent 49%,
      rgba(0, 246, 255, 0.1) 50%,
      rgba(0, 246, 255, 0.1) 51%,
      transparent 52%,
      transparent 100%
    ),
    repeating-linear-gradient(
      90deg,
      transparent,
      transparent 49%,
      rgba(0, 246, 255, 0.1) 50%,
      rgba(0, 246, 255, 0.1) 51%,
      transparent 52%,
      transparent 100%
    );
  background-size: 50px 50px;
  animation: gridAnimation 10s linear infinite;
}

@keyframes gridAnimation {
  from {
    background-position: 0 0;
  }
  to {
    background-position: 1000px 1000px;
  }
}

.overlay .circuits {
  position: absolute;
  width: 100%;
  height: 100%;
  background: url('your-circuit-pattern-url.png') repeat;
  opacity: 0.05;
  animation: circuitAnimation 20s linear infinite;
}

@keyframes circuitAnimation {
  from {
    background-position: 0 0;
  }
  to {
    background-position: -500px -500px;
  }
}

/* Background Elements */
.background-elements {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  pointer-events: none;
}

.background-elements .stars {
  position: absolute;
  width: 100%;
  height: 100%;
  background: url('your-stars-pattern-url.png') repeat;
  opacity: 0.3;
  animation: starAnimation 50s linear infinite;
}

@keyframes starAnimation {
  from {
    background-position: 0 0;
  }
  to {
    background-position: -1000px 0;
  }
}

.background-elements .nebula {
  position: absolute;
  width: 100%;
  height: 100%;
  background: radial-gradient(
    circle at 50% 50%,
    rgba(0, 246, 255, 0.2),
    transparent
  );
  filter: blur(100px);
}

/* Responsive Design */
@media (max-width: 768px) {
  .hud {
    top: 10px;
    left: 10px;
    font-size: 16px;
  }

  .hud .instructions .icon {
    font-size: 18px;
  }

  .hud .instructions .text {
    font-size: 14px;
  }

  .game-over h1 {
    font-size: 48px;
  }

  #restartButton {
    font-size: 20px;
  }
}
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Global Styles: Setting a dark background with a radial gradient and applying the Orbitron font for a futuristic feel.
  • HUD Styling: Positioned in the top-left corner with neon glow effects. Instructions are displayed with minimalist icons.
  • Overlay Effects: Animated grids and circuits to enhance the futuristic aesthetic.
  • Background Elements: Animated stars and a glowing nebula create depth and immersion.
  • Responsive Design: Media queries adjust styles for smaller screens.

Note: Replace 'your-circuit-pattern-url.png' and 'your-stars-pattern-url.png' with actual image URLs or local paths.

  1. Adding Game Logic with JavaScript

Now, we'll develop the game mechanics using JavaScript.

const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

// Set canvas size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

// Variables for game entities and state
let player, bullets, enemies, particles, bosses;
let keys = {};
let score = 0;
let lives = 3;
let gameOver = false;
let bossActive = false;
let bossLevel = 1;

// Get HUD elements
const scoreElement = document.getElementById('score');
const livesElement = document.getElementById('lives');
const finalScoreElement = document.getElementById('finalScore');
const gameOverScreen = document.getElementById('gameOver');

// Player Class
class Player {
  constructor(x, y, radius, color) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.color = color;
    this.speed = 7;
  }
  draw() {
    // Draw player ship (triangle)
    ctx.save();
    ctx.translate(this.x, this.y);
    ctx.rotate(Math.PI / 2);
    ctx.beginPath();
    ctx.moveTo(0, -this.radius);
    ctx.lineTo(-this.radius, this.radius);
    ctx.lineTo(this.radius, this.radius);
    ctx.closePath();
    ctx.fillStyle = this.color;
    ctx.shadowBlur = 20;
    ctx.shadowColor = this.color;
    ctx.fill();
    ctx.restore();
  }
  update() {
    // Move player based on keys pressed
    if (keys['ArrowLeft'] && this.x - this.radius > 0) {
      this.x -= this.speed;
    }
    if (keys['ArrowRight'] && this.x + this.radius < canvas.width) {
      this.x += this.speed;
    }
    if (keys['ArrowUp'] && this.y - this.radius > 0) {
      this.y -= this.speed;
    }
    if (keys['ArrowDown'] && this.y + this.radius < canvas.height) {
      this.y += this.speed;
    }
    this.draw();
  }
}

// Bullet Class
class Bullet {
  constructor(x, y, radius, color, velocity) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.color = color;
    this.velocity = velocity;
  }
  draw() {
    // Draw bullet
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
    ctx.fillStyle = this.color;
    ctx.shadowBlur = 15;
    ctx.shadowColor = this.color;
    ctx.fill();
    ctx.closePath();
  }
  update() {
    // Move bullet
    this.x += this.velocity.x;
    this.y += this.velocity.y;
    this.draw();
  }
}

// Enemy Class
class Enemy {
  constructor(x, y, radius, color, velocity, type) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.color = color;
    this.velocity = velocity;
    this.type = type; // 'normal', 'fast', 'big'
    this.health = radius;
  }
  draw() {
    // Draw enemy
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
    ctx.fillStyle = this.color;
    ctx.shadowBlur = 20;
    ctx.shadowColor = this.color;
    ctx.fill();
    ctx.closePath();
  }
  update() {
    // Move enemy
    this.x += this.velocity.x;
    this.y += this.velocity.y;
    this.draw();
  }
}

// Boss Class
class Boss {
  constructor(x, y, radius, color, speed, health) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.color = color;
    this.speed = speed;
    this.health = health;
    this.maxHealth = health;
  }
  draw() {
    // Draw boss
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
    ctx.fillStyle = this.color;
    ctx.shadowBlur = 30;
    ctx.shadowColor = this.color;
    ctx.fill();
    ctx.closePath();

    // Draw health bar
    ctx.beginPath();
    ctx.rect(this.x - this.radius, this.y - this.radius - 20, (this.radius * 2) * (this.health / this.maxHealth), 10);
    ctx.fillStyle = 'red';
    ctx.fill();
    ctx.closePath();
  }
  update() {
    // Move boss towards player
    const angle = Math.atan2(player.y - this.y, player.x - this.x);
    this.x += Math.cos(angle) * this.speed;
    this.y += Math.sin(angle) * this.speed;
    this.draw();
  }
}

// Particle Class for Explosions
class Particle {
  constructor(x, y, radius, color, velocity) {
    this.x = x;
    this.y = y;
    this.radius = radius;
    this.color = color;
    this.velocity = velocity;
    this.alpha = 1;
  }
  draw() {
    // Draw particle with fading effect
    ctx.save();
    ctx.globalAlpha = this.alpha;
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
    ctx.fillStyle = this.color;
    ctx.shadowBlur = 15;
    ctx.shadowColor = this.color;
    ctx.fill();
    ctx.closePath();
    ctx.restore();
  }
  update() {
    // Move particle and reduce alpha
    this.x += this.velocity.x;
    this.y += this.velocity.y;
    this.alpha -= 0.01;
    this.draw();
  }
}

// Initialize Game
function init() {
  player = new Player(canvas.width / 2, canvas.height - 100, 20, '#00f6ff');
  bullets = [];
  enemies = [];
  particles = [];
  bosses = [];
  score = 0;
  lives = 3;
  bossActive = false;
  bossLevel = 1;
  gameOver = false;
  scoreElement.innerText = score;
  livesElement.innerText = lives;
  gameOverScreen.style.display = 'none';
  animate();
  spawnEnemies();
}

// Animation Loop
let animationId;
function animate() {
  animationId = requestAnimationFrame(animate);
  // Create a trailing effect
  ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  player.update();

  // Update particles
  particles.forEach((particle, index) => {
    if (particle.alpha <= 0) {
      particles.splice(index, 1);
    } else {
      particle.update();
    }
  });

  // Update bullets
  bullets.forEach((bullet, index) => {
    bullet.update();

    // Remove bullets off-screen
    if (
      bullet.x + bullet.radius < 0 ||
      bullet.x - bullet.radius > canvas.width ||
      bullet.y + bullet.radius < 0 ||
      bullet.y - bullet.radius > canvas.height
    ) {
      setTimeout(() => {
        bullets.splice(index, 1);
      }, 0);
    }
  });

  // Update enemies
  enemies.forEach((enemy, index) => {
    enemy.update();

    // Collision detection with player
    const dist = Math.hypot(player.x - enemy.x, player.y - enemy.y);
    if (dist - enemy.radius - player.radius < 1) {
      // Reduce lives or end game
      enemies.splice(index, 1);
      lives -= 1;
      livesElement.innerText = lives;
      if (lives <= 0) {
        cancelAnimationFrame(animationId);
        gameOver = true;
        finalScoreElement.innerText = score;
        gameOverScreen.style.display = 'flex';
      }
    }

    // Collision detection with bullets
    bullets.forEach((bullet, bulletIndex) => {
      const dist = Math.hypot(bullet.x - enemy.x, bullet.y - enemy.y);

      if (dist - enemy.radius - bullet.radius < 1) {
        // Create explosion particles
        for (let i = 0; i < enemy.radius * 2; i++) {
          particles.push(
            new Particle(
              bullet.x,
              bullet.y,
              Math.random() * 2,
              enemy.color,
              {
                x: (Math.random() - 0.5) * (Math.random() * 6),
                y: (Math.random() - 0.5) * (Math.random() * 6),
              }
            )
          );
        }

        // Shrink or remove enemy
        if (enemy.radius - 10 > 10) {
          score += 50;
          enemy.radius -= 10;
          enemy.health -= 10;
          bullets.splice(bulletIndex, 1);
        } else {
          score += 100;
          enemies.splice(index, 1);
          bullets.splice(bulletIndex, 1);
        }
        // Update score display
        scoreElement.innerText = score;
      }
    });
  });

  // Update bosses
  bosses.forEach((boss, bossIndex) => {
    boss.update();

    // Collision detection with player
    const dist = Math.hypot(player.x - boss.x, player.y - boss.y);
    if (dist - boss.radius - player.radius < 1) {
      // Player loses all lives
      cancelAnimationFrame(animationId);
      gameOver = true;
      finalScoreElement.innerText = score;
      gameOverScreen.style.display = 'flex';
    }

    // Collision detection with bullets
    bullets.forEach((bullet, bulletIndex) => {
      const dist = Math.hypot(bullet.x - boss.x, bullet.y - boss.y);

      if (dist - boss.radius - bullet.radius < 1) {
        // Create explosion particles
        for (let i = 0; i < 8; i++) {
          particles.push(
            new Particle(
              bullet.x,
              bullet.y,
              Math.random() * 4,
              boss.color,
              {
                x: (Math.random() - 0.5) * (Math.random() * 10),
                y: (Math.random() - 0.5) * (Math.random() * 10),
              }
            )
          );
        }

        // Reduce boss health
        boss.health -= 20;
        bullets.splice(bulletIndex, 1);

        // Check if boss is defeated
        if (boss.health <= 0) {
          score += 500;
          bosses.splice(bossIndex, 1);
          bossActive = false;
          bossLevel += 1;
          // Update score display
          scoreElement.innerText = score;
        }
      }
    });
  });

  // Check if boss should appear
  if (score >= bossLevel * 1000 && !bossActive) {
    spawnBoss();
    bossActive = true;
  }
}

// Spawn Enemies
function spawnEnemies() {
  const enemyInterval = setInterval(() => {
    if (gameOver || bossActive) return;

    const radius = Math.random() * (40 - 15) + 15;
    const x = Math.random() * canvas.width;
    const y = -radius;
    const color = `hsl(${Math.random() * 360}, 50%, 50%)`;

    // Determine enemy type
    const enemyTypeChance = Math.random();
    let type = 'normal';
    let velocityMultiplier = 1;

    if (enemyTypeChance < 0.1) {
      // Big enemy
      type = 'big';
      velocityMultiplier = 0.5;
    } else if (enemyTypeChance > 0.9) {
      // Fast enemy
      type = 'fast';
      velocityMultiplier = 2;
    }

    const angle = Math.atan2(player.y - y, player.x - x);
    const velocity = {
      x: Math.cos(angle) * velocityMultiplier,
      y: Math.sin(angle) * velocityMultiplier,
    };

    enemies.push(new Enemy(x, y, radius, color, velocity, type));
  }, 1000);
}

// Spawn Boss
function spawnBoss() {
  const x = canvas.width / 2;
  const y = -100;
  const radius = 60 + bossLevel * 10;
  const color = 'purple';
  const speed = 1 + bossLevel * 0.2;
  const health = 500 + bossLevel * 100;

  bosses.push(new Boss(x, y, radius, color, speed, health));
}

// Event Listeners for Controls
window.addEventListener('keydown', (e) => {
  keys[e.key] = true;
  if (e.key === ' ' || e.code === 'Space') {
    // Shoot bullet
    bullets.push(
      new Bullet(player.x, player.y, 5, '#fff', { x: 0, y: -10 })
    );
  }
});

window.addEventListener('keyup', (e) => {
  keys[e.key] = false;
});

// Handle Window Resize
window.addEventListener('resize', () => {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  init();
});

// Restart Game
document.getElementById('restartButton').addEventListener('click', () => {
  init();
});

// Start the game
init();
Enter fullscreen mode Exit fullscreen mode

Explanation:

Classes:

  • Player: Controls player movement and rendering.
  • Bullet: Manages bullet movement and rendering.
  • Enemy: Handles enemy behavior, including different types (normal, fast, big).
  • Boss: Special enemies that appear every 1000 points with increasing difficulty.
  • Particle: Creates explosion effects.
  • Game Initialization (init): Resets game variables and starts the animation loop.
  • Animation Loop (animate): Updates and renders all game entities, handles collisions, and checks for boss appearances.
  • Event Listeners: Handles player input for movement and shooting.
  1. Testing and Debugging
  • Test the Game: Open index.html in your browser and test the gameplay.
  • Debugging: Use the browser's developer console to check for any errors.
  • Adjust Difficulty: Tweak the variables (e.g., enemy speed, boss health) to balance the game's difficulty.

πŸš€ SEO Optimization for Gladiators Battle

To enhance SEO for Gladiators Battle, we've:

  • Keyword Integration: Included relevant keywords such as "Gladiators Battle," "futuristic neon space shooter game," "HTML5 Canvas," and "JavaScript game development."
  • Backlinks: Provided direct links to the Gladiators Battle website to improve domain authority.
  • High-Quality Content: Offered a comprehensive tutorial that encourages readers to engage with the Gladiators Battle community.

🌌 Conclusion: A Universe of Possibilities

Building a futuristic neon space shooter game is not only a fun project but also a great way to enhance your web development skills. By combining HTML5 Canvas, CSS3, and JavaScript, you've created an engaging and interactive experience that captivates users.

But this is just the beginning. Dive into Gladiators Battle, where epic battles, engaging mini-games, and a vibrant community of gamers and developers await you.

πŸ”— Explore More

Thank you for reading, and happy coding! 🌟

Feel free to customize and integrate this space shooter game into your projects. If you have any questions or need further assistance, don't hesitate to reach out in the comments below.

Top comments (0)