untitled

Pasted Oct 21, 2026, 7:36 AM1 file220 lines

Scan to open on your phone

Point a camera at the QR code - it opens this exact paste, no app needed.

https://codepastes.com/zzgsqgt07h9bwhqt
untitled
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>2D Castle Clash</title>
  <style>
    body {
      background-color: #1a1a1a;
      color: white;
      font-family: Arial, sans-serif;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      height: 100vh;
      margin: 0;
    }
    canvas {
      border: 3px solid #ffffff;
      background-color: #2e7d32;
      box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
    }
    .instructions {
      margin-top: 15px;
      font-size: 18px;
    }
    .key {
      background-color: #444;
      padding: 3px 8px;
      border-radius: 4px;
      font-weight: bold;
    }
  </style>
</head>
<body>

  <h1>2D Lane Battle</h1>
  <canvas id="gameCanvas" width="800" height="400"></canvas>
  <div class="instructions">
    <p>Press <span class="key">1</span> to spawn Blue Troop | Press <span class="key">0</span> to spawn Red Troop</p>
  </div>

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

    const LANE_Y = 250;

    class Castle {
      constructor(x, color, team) {
        this.x = x;
        this.y = LANE_Y - 50;
        this.width = 60;
        this.height = 100;
        this.color = color;
        this.team = team;
        this.maxHp = 500;
        this.hp = 500;
      }

      draw() {
        // Castle body
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);

        // Battlements
        ctx.fillStyle = '#333';
        ctx.fillRect(this.x - 5, this.y - 15, this.width + 10, 15);

        // Health bar background
        ctx.fillStyle = '#ff0000';
        ctx.fillRect(this.x, this.y - 30, this.width, 8);

        // Current health bar
        ctx.fillStyle = '#00ff00';
        const currentHpWidth = Math.max(0, (this.hp / this.maxHp) * this.width);
        ctx.fillRect(this.x, this.y - 30, currentHpWidth, 8);
      }
    }

    class Troop {
      constructor(x, team, color, direction) {
        this.x = x;
        this.y = LANE_Y + 20;
        this.radius = 15;
        this.team = team;
        this.color = color;
        this.direction = direction; // 1 for moving right, -1 for moving left
        this.speed = 1.5;
        this.maxHp = 100;
        this.hp = 100;
        this.damage = 0.5;
        this.attackRange = 20;
        this.isAttacking = false;
      }

      update() {
        if (!this.isAttacking) {
          this.x += this.speed * this.direction;
        }
      }

      draw() {
        // Draw troop body
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
        ctx.fillStyle = this.color;
        ctx.fill();
        ctx.strokeStyle = '#ffffff';
        ctx.lineWidth = 2;
        ctx.stroke();

        // Troop health bar
        const barWidth = 30;
        ctx.fillStyle = '#ff0000';
        ctx.fillRect(this.x - barWidth / 2, this.y - this.radius - 12, barWidth, 5);
        ctx.fillStyle = '#00ff00';
        const currentHpWidth = Math.max(0, (this.hp / this.maxHp) * barWidth);
        ctx.fillRect(this.x - barWidth / 2, this.y - this.radius - 12, currentHpWidth, 5);
      }
    }

    const blueCastle = new Castle(40, '#2196F3', 'blue');
    const redCastle = new Castle(700, '#F44336', 'red');

    const blueTroops = [];
    const redTroops = [];

    let gameOver = false;
    let winnerMessage = '';

    window.addEventListener('keydown', (e) => {
      if (gameOver) return;

      if (e.key === '1') {
        blueTroops.push(new Troop(blueCastle.x + blueCastle.width + 20, 'blue', '#2196F3', 1));
      } else if (e.key === '0') {
        redTroops.push(new Troop(redCastle.x - 20, 'red', '#F44336', -1));
      }
    });

    function handleCollisionsAndAttacks() {
      // Reset attack state each frame
      blueTroops.forEach(b => b.isAttacking = false);
      redTroops.forEach(r => r.isAttacking = false);

      // Troop vs Troop combat
      blueTroops.forEach(blue => {
        redTroops.forEach(red => {
          const distance = Math.abs(blue.x - red.x);
          if (distance <= blue.attackRange + red.attackRange) {
            blue.isAttacking = true;
            red.isAttacking = true;
            blue.hp -= red.damage;
            red.hp -= blue.damage;
          }
        });
      });

      // Troop vs Castle combat
      blueTroops.forEach(blue => {
        if (!blue.isAttacking && blue.x >= redCastle.x - blue.attackRange) {
          blue.isAttacking = true;
          redCastle.hp -= blue.damage;
        }
      });

      redTroops.forEach(red => {
        if (!red.isAttacking && red.x <= blueCastle.x + blueCastle.width + red.attackRange) {
          red.isAttacking = true;
          blueCastle.hp -= red.damage;
        }
      });
    }

    function update() {
      if (gameOver) return;

      handleCollisionsAndAttacks();

      // Update positions
      blueTroops.forEach(t => t.update());
      redTroops.forEach(t => t.update());

      // Remove defeated troops
      for (let i = blueTroops.length - 1; i >= 0; i--) {
        if (blueTroops[i].hp <= 0) blueTroops.splice(i, 1);
      }
      for (let i = redTroops.length - 1; i >= 0; i--) {
        if (redTroops[i].hp <= 0) redTroops.splice(i, 1);
      }

      // Check win condition
      if (blueCastle.hp <= 0) {
        gameOver = true;
        winnerMessage = 'Red Team Wins!';
      } else if (redCastle.hp <= 0) {
        gameOver = true;
        winnerMessage = 'Blue Team Wins!';
      }
    }

    function draw() {
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      // Draw walking path line
      ctx.beginPath();
      ctx.moveTo(0, LANE_Y + 35);
      ctx.lineTo(800, LANE_Y + 35);
      ctx.strokeStyle = '#1b5e20';
      ctx.lineWidth = 4;
      ctx.stroke();

      // Draw castles
      blueCastle.draw();
      redCastle.draw();

      // Draw troops
      blueTroops.forEach(t => t.draw());
      redTroops.forEach(t => t.draw());

6,007 chars · codepastes.com