Created
June 10, 2024 21:31
-
-
Save EncodeTheCode/8dc88a7a11106e549dc99b91d9c94292 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Jedi Lightsaber Swing Game</title> | |
<style> | |
body { margin: 0; overflow: hidden; } | |
canvas { background: #FFF; display: block; } | |
</style> | |
</head> | |
<body> | |
<canvas id="gameCanvas"></canvas> | |
<script> | |
const canvas = document.getElementById('gameCanvas'); | |
const ctx = canvas.getContext('2d'); | |
canvas.width = window.innerWidth; | |
canvas.height = window.innerHeight; | |
const PLAYER_SPEED = 3; | |
const ENEMY_SPEED = 1; | |
const SPAWN_RADIUS = 250; | |
const SWING_RADIUS = 100; | |
const SWING_ANGLE = Math.PI / 4; // 45 degrees | |
const ENEMY_SPAWN_INTERVAL = 10000; // milliseconds | |
let gameOver = false; | |
class Player { | |
constructor(x, y, radius, color) { | |
this.x = x; | |
this.y = y; | |
this.radius = radius; | |
this.color = color; | |
this.angle = 0; | |
this.dx = 0; | |
this.dy = 0; | |
this.swingStep = 0; | |
} | |
draw() { | |
ctx.beginPath(); | |
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); | |
ctx.fillStyle = this.color; | |
ctx.fill(); | |
ctx.closePath(); | |
} | |
update() { | |
this.x += this.dx; | |
this.y += this.dy; | |
this.x = Math.max(this.radius, Math.min(canvas.width - this.radius, this.x)); | |
this.y = Math.max(this.radius, Math.min(canvas.height - this.radius, this.y)); | |
} | |
swing() { | |
if (this.swingStep < 24) { | |
const stepAngle = SWING_ANGLE / 24; | |
const startAngle = this.angle - SWING_ANGLE / 8 + stepAngle * this.swingStep; | |
const endAngle = startAngle + stepAngle; | |
ctx.beginPath(); | |
ctx.arc(this.x, this.y, SWING_RADIUS, startAngle, endAngle, false); | |
ctx.lineWidth = 55; | |
ctx.strokeStyle = 'blue'; | |
ctx.stroke(); | |
ctx.closePath(); | |
this.swingStep++; | |
} else { | |
this.swingStep = 0; | |
swinging = false; | |
} | |
} | |
updateAngle(mouseX, mouseY) { | |
const dx = mouseX - this.x; | |
const dy = mouseY - this.y; | |
this.angle = Math.atan2(dy, dx); | |
} | |
hurtEnemies(enemies) { | |
const endAngle = this.angle + SWING_ANGLE / 8; | |
const startAngle = this.angle - SWING_ANGLE / 8; | |
enemies.forEach(enemy => { | |
const dx = enemy.x - this.x; | |
const dy = enemy.y - this.y; | |
const distance = Math.sqrt(dx * dx + dy * dy); | |
const angleToEnemy = Math.atan2(dy, dx); | |
if (distance < SWING_RADIUS && angleToEnemy > startAngle && angleToEnemy < endAngle) { | |
enemy.hurt(); | |
} | |
}); | |
} | |
} | |
class Enemy { | |
constructor(x, y, radius, color) { | |
this.x = x; | |
this.y = y; | |
this.radius = radius; | |
this.color = color; | |
this.health = 100; | |
} | |
draw() { | |
ctx.beginPath(); | |
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); | |
ctx.fillStyle = this.color; | |
ctx.fill(); | |
ctx.closePath(); | |
} | |
update(player) { | |
const dx = player.x - this.x; | |
const dy = player.y - this.y; | |
const distance = Math.sqrt(dx * dx + dy * dy); | |
const moveX = (dx / distance) * ENEMY_SPEED; | |
const moveY = (dy / distance) * ENEMY_SPEED; | |
this.x += moveX; | |
this.y += moveY; | |
} | |
hurt() { | |
this.health -= 50; | |
} | |
} | |
const player = new Player(canvas.width / 2, canvas.height / 2, 20, 'green'); | |
let enemies = []; | |
let swinging = false; | |
function spawnEnemy() { | |
const angle = Math.random() * Math.PI * 2; | |
const x = player.x + SPAWN_RADIUS * Math.cos(angle); | |
const y = player.y + SPAWN_RADIUS * Math.sin(angle); | |
enemies.push(new Enemy(x, y, 20, 'red')); | |
} | |
function animate() { | |
if (gameOver) return; | |
ctx.clearRect(0, 0, canvas.width, canvas.height); | |
player.update(); | |
player.draw(); | |
enemies = enemies.filter(enemy => enemy.health > 0); // Remove dead enemies | |
enemies.forEach(enemy => { | |
enemy.update(player); | |
enemy.draw(); | |
const dx = player.x - enemy.x; | |
const dy = player.y - enemy.y; | |
const distance = Math.sqrt(dx * dx + dy * dy); | |
if (distance < player.radius + enemy.radius && enemy.health > 0) { | |
gameOver = true; | |
alert('Game Over!'); | |
} | |
}); | |
if (swinging) { | |
player.swing(); | |
player.hurtEnemies(enemies); | |
} | |
requestAnimationFrame(animate); | |
} | |
canvas.addEventListener('mousemove', (event) => { | |
player.updateAngle(event.clientX, event.clientY); | |
}); | |
canvas.addEventListener('click', () => { | |
if (!swinging) { | |
swinging = true; | |
player.swingStep = 0; | |
} | |
}); | |
window.addEventListener('keydown', (event) => { | |
switch (event.key) { | |
case 'w': player.dy = -PLAYER_SPEED; break; | |
case 'a': player.dx = -PLAYER_SPEED; break; | |
case 's': player.dy = PLAYER_SPEED; break; | |
case 'd': player.dx = PLAYER_SPEED; break; | |
} | |
}); | |
window.addEventListener('keyup', (event) => { | |
switch (event.key) { | |
case 'w': | |
case 's': player.dy = 0; break; | |
case 'a': | |
case 'd': player.dx = 0; break; | |
} | |
}); | |
setInterval(spawnEnemy, ENEMY_SPAWN_INTERVAL); | |
animate(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment