Scan to open on your phone
Point a camera at the QR code - it opens this exact paste, no app needed.
https://codepastes.com/zzgsqgt07h9bwhqtuntitledPlain Text
<!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