Spaces:
Running
Running
<html> | |
<head> | |
<title>Stickman Javelin Battle</title> | |
<style> | |
body { | |
margin: 0; | |
overflow: hidden; | |
background: linear-gradient(to bottom, #87CEEB, #E0F6FF); | |
font-family: Arial, sans-serif; | |
} | |
#gameCanvas { | |
border: 2px solid #333; | |
cursor: crosshair; | |
} | |
#menu { | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
transform: translate(-50%, -50%); | |
text-align: center; | |
background: rgba(255, 255, 255, 0.9); | |
padding: 20px; | |
border-radius: 10px; | |
box-shadow: 0 0 10px rgba(0,0,0,0.3); | |
} | |
.btn { | |
padding: 10px 20px; | |
font-size: 18px; | |
background: #4CAF50; | |
color: white; | |
border: none; | |
border-radius: 5px; | |
cursor: pointer; | |
transition: all 0.3s; | |
} | |
.health-bar { | |
position: absolute; | |
width: 200px; | |
height: 20px; | |
background: #333; | |
border-radius: 10px; | |
overflow: hidden; | |
} | |
.health-bar-fill { | |
height: 100%; | |
background: linear-gradient(90deg, #ff0000, #ff4444); | |
transition: width 0.3s ease; | |
} | |
#player1Health { | |
top: 20px; | |
left: 20px; | |
} | |
#player2Health { | |
top: 20px; | |
right: 20px; | |
} | |
.player-label { | |
position: absolute; | |
color: white; | |
font-size: 14px; | |
font-weight: bold; | |
text-shadow: 1px 1px 2px black; | |
} | |
#powerIndicator { | |
position: absolute; | |
bottom: 20px; | |
left: 50%; | |
transform: translateX(-50%); | |
width: 200px; | |
height: 10px; | |
background: rgba(0, 0, 0, 0.5); | |
border-radius: 5px; | |
} | |
#powerBar { | |
width: 0%; | |
height: 100%; | |
background: #ffff00; | |
border-radius: 5px; | |
transition: width 0.1s ease; | |
} | |
#turnIndicator { | |
position: absolute; | |
top: 50px; | |
left: 50%; | |
transform: translateX(-50%); | |
color: white; | |
font-size: 20px; | |
text-shadow: 1px 1px 2px black; | |
} | |
</style> | |
</head> | |
<body> | |
<canvas id="gameCanvas"></canvas> | |
<div id="menu"> | |
<h1>Stickman Javelin Battle</h1> | |
<button class="btn" onclick="startGame()">Start Game</button> | |
</div> | |
<div id="player1Health" class="health-bar"> | |
<div id="player1HealthFill" class="health-bar-fill" style="width: 100%"></div> | |
<span class="player-label">Player 1: 100</span> | |
</div> | |
<div id="player2Health" class="health-bar"> | |
<div id="player2HealthFill" class="health-bar-fill" style="width: 100%"></div> | |
<span class="player-label">Player 2: 100</span> | |
</div> | |
<div id="turnIndicator"></div> | |
<div id="powerIndicator"> | |
<div id="powerBar"></div> | |
</div> | |
<script> | |
const canvas = document.getElementById('gameCanvas'); | |
const ctx = canvas.getContext('2d'); | |
const menu = document.getElementById('menu'); | |
const turnIndicator = document.getElementById('turnIndicator'); | |
const player1HealthFill = document.getElementById('player1HealthFill'); | |
const player2HealthFill = document.getElementById('player2HealthFill'); | |
const powerBar = document.getElementById('powerBar'); | |
let gameActive = false; | |
let currentPlayer = 1; | |
let isMouseDown = false; | |
let powerLevel = 0; | |
let aimAngle = 0; | |
const player1 = { | |
x: 100, | |
y: 575, | |
height: 60, | |
width: 20, | |
color: '#FF6B6B', | |
health: 100 | |
}; | |
const player2 = { | |
x: 700, | |
y: 575, | |
height: 60, | |
width: 20, | |
color: '#4ECDC4', | |
health: 100 | |
}; | |
const javelin = { | |
x: 0, | |
y: 0, | |
angle: 0, | |
power: 0, | |
throwing: false, | |
velocity: { x: 0, y: 0 } | |
}; | |
function resizeCanvas() { | |
canvas.width = window.innerWidth; | |
canvas.height = window.innerHeight; | |
} | |
function startGame() { | |
menu.style.display = 'none'; | |
gameActive = true; | |
currentPlayer = 1; | |
player1.health = 100; | |
player2.health = 100; | |
updateHealthBars(); | |
updateTurnIndicator(); | |
gameLoop(); | |
} | |
function updateTurnIndicator() { | |
turnIndicator.textContent = `Player ${currentPlayer}'s Turn`; | |
} | |
function updateHealthBars() { | |
player1HealthFill.style.width = `${player1.health}%`; | |
player2HealthFill.style.width = `${player2.health}%`; | |
document.querySelector('#player1Health .player-label').textContent = `Player 1: ${player1.health}`; | |
document.querySelector('#player2Health .player-label').textContent = `Player 2: ${player2.health}`; | |
} | |
function drawAimLine(x, y, angle, power) { | |
ctx.beginPath(); | |
ctx.moveTo(x, y); | |
ctx.lineTo(x + Math.cos(angle) * power * 10, y + Math.sin(angle) * power * 10); | |
ctx.strokeStyle = '#ff0000'; | |
ctx.setLineDash([5, 5]); | |
ctx.stroke(); | |
ctx.setLineDash([]); | |
} | |
function drawStickman(x, y, color) { | |
ctx.strokeStyle = color; | |
ctx.lineWidth = 4; | |
ctx.beginPath(); | |
// Head (hitbox area) | |
ctx.arc(x + 10, y - 40, 10, 0, Math.PI * 2); | |
// Body (hitbox area) | |
ctx.moveTo(x + 10, y - 30); | |
ctx.lineTo(x + 10, y); | |
// Arms (hitbox areas) | |
ctx.moveTo(x + 10, y - 20); | |
ctx.lineTo(x - 5, y - 10); | |
ctx.moveTo(x + 10, y - 20); | |
ctx.lineTo(x + 25, y - 10); | |
// Legs (hitbox areas) | |
ctx.moveTo(x + 10, y); | |
ctx.lineTo(x, y + 20); | |
ctx.moveTo(x + 10, y); | |
ctx.lineTo(x + 20, y + 20); | |
ctx.stroke(); | |
} | |
function drawJavelin(x, y, angle) { | |
ctx.save(); | |
ctx.translate(x, y); | |
ctx.rotate(angle); | |
ctx.fillStyle = '#8B4513'; | |
ctx.fillRect(-25, -2, 50, 4); | |
ctx.restore(); | |
} | |
function handleMouseDown(e) { | |
if (!javelin.throwing && gameActive) { | |
isMouseDown = true; | |
powerLevel = 0; | |
} | |
} | |
function handleMouseMove(e) { | |
if (isMouseDown) { | |
const rect = canvas.getBoundingClientRect(); | |
const mouseX = e.clientX - rect.left; | |
const mouseY = e.clientY - rect.top; | |
const playerX = currentPlayer === 1 ? player1.x : player2.x; | |
const playerY = currentPlayer === 1 ? player1.y - 20 : player2.y - 20; | |
const dx = mouseX - playerX; | |
const dy = mouseY - playerY; | |
aimAngle = Math.atan2(dy, dx); | |
} | |
} | |
function handleMouseUp(e) { | |
if (isMouseDown && !javelin.throwing && gameActive) { | |
const playerX = currentPlayer === 1 ? player1.x : player2.x; | |
const playerY = currentPlayer === 1 ? player1.y - 20 : player2.y - 20; | |
javelin.x = playerX; | |
javelin.y = playerY; | |
javelin.angle = aimAngle; | |
javelin.power = powerLevel; | |
javelin.velocity.x = Math.cos(aimAngle) * powerLevel; | |
javelin.velocity.y = Math.sin(aimAngle) * powerLevel; | |
javelin.throwing = true; | |
} | |
isMouseDown = false; | |
powerLevel = 0; | |
powerBar.style.width = '0%'; | |
} | |
function checkHit(x, y, targetX, targetY) { | |
const headHitbox = { x: targetX + 10, y: targetY - 40, radius: 10 }; | |
const bodyHitbox = { | |
x: targetX + 10, | |
y: targetY - 15, | |
width: 4, | |
height: 30 | |
}; | |
// Check head hit (20 damage) | |
const dx = x - headHitbox.x; | |
const dy = y - headHitbox.y; | |
if (Math.sqrt(dx * dx + dy * dy) < headHitbox.radius) { | |
return 20; | |
} | |
// Check body hit (10 damage) | |
if (x >= targetX && x <= targetX + 20 && | |
y >= targetY - 30 && y <= targetY + 20) { | |
return 10; | |
} | |
return 0; | |
} | |
function updateJavelin() { | |
if (javelin.throwing) { | |
javelin.x += javelin.velocity.x; | |
javelin.y += javelin.velocity.y; | |
javelin.velocity.y += 0.5; // Gravity | |
const target = currentPlayer === 1 ? player2 : player1; | |
const damage = checkHit(javelin.x, javelin.y, target.x, target.y); | |
if (damage > 0) { | |
target.health = Math.max(0, target.health - damage); | |
updateHealthBars(); | |
resetJavelin(); | |
checkGameOver(); | |
} | |
// Check if javelin is out of bounds | |
if (javelin.x < 0 || javelin.x > canvas.width || | |
javelin.y > canvas.height) { | |
resetJavelin(); | |
} | |
} | |
} | |
function resetJavelin() { | |
javelin.throwing = false; | |
currentPlayer = currentPlayer === 1 ? 2 : 1; | |
updateTurnIndicator(); | |
} | |
function checkGameOver() { | |
if (player1.health <= 0 || player2.health <= 0) { | |
endGame(); | |
} | |
} | |
function endGame() { | |
gameActive = false; | |
menu.style.display = 'block'; | |
const winner = player1.health <= 0 ? 2 : 1; | |
menu.innerHTML = ` | |
<h1>Game Over!</h1> | |
<h2>Player ${winner} Wins!</h2> | |
<button class="btn" onclick="startGame()">Play Again</button> | |
`; | |
} | |
function gameLoop() { | |
ctx.clearRect(0, 0, canvas.width, canvas.height); | |
// Draw ground | |
ctx.fillStyle = '#90EE90'; | |
ctx.fillRect(0, canvas.height - 50, canvas.width, 50); | |
drawStickman(player1.x, player1.y, player1.color); | |
drawStickman(player2.x, player2.y, player2.color); | |
if (isMouseDown && !javelin.throwing) { | |
const playerX = currentPlayer === 1 ? player1.x : player2.x; | |
const playerY = currentPlayer === 1 ? player1.y - 20 : player2.y - 20; | |
powerLevel = Math.min(powerLevel + 0.5, 20); | |
powerBar.style.width = `${(powerLevel / 20) * 100}%`; | |
drawAimLine(playerX, playerY, aimAngle, powerLevel); | |
} | |
if (javelin.throwing) { | |
drawJavelin(javelin.x, javelin.y, javelin.angle); | |
updateJavelin(); | |
} | |
if (gameActive) { | |
requestAnimationFrame(gameLoop); | |
} | |
} | |
window.addEventListener('resize', resizeCanvas); | |
canvas.addEventListener('mousedown', handleMouseDown); | |
canvas.addEventListener('mousemove', handleMouseMove); | |
canvas.addEventListener('mouseup', handleMouseUp); | |
resizeCanvas(); | |
</script> | |
</body> | |
</html> |