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> |