Spaces:
Running
Running
| document.addEventListener('DOMContentLoaded', () => { | |
| // Game state | |
| const gameState = { | |
| playerTurn: true, | |
| playerPosition: { x: 100, y: 100 }, | |
| selectedMove: null, | |
| enemies: [ | |
| { x: 300, y: 100, speed: 2, direction: 'right' }, | |
| { x: 200, y: 200, speed: 1, direction: 'down' } | |
| ], | |
| swordAngle: 0, | |
| swordSpinning: false, | |
| swordSpeed: 0, | |
| gameLog: [], | |
| moveConfirmed: false | |
| }; | |
| // DOM elements | |
| const gameCanvas = document.getElementById('gameCanvas'); | |
| const gameLog = document.getElementById('gameLog'); | |
| const turnIndicator = document.getElementById('turnIndicator'); | |
| // Movement buttons | |
| const moveUp = document.getElementById('moveUp'); | |
| const moveDown = document.getElementById('moveDown'); | |
| const moveLeft = document.getElementById('moveLeft'); | |
| const moveRight = document.getElementById('moveRight'); | |
| const spinBlade = document.getElementById('spinBlade'); | |
| // Initialize game | |
| initGame(); | |
| function initGame() { | |
| renderGame(); | |
| setupControls(); | |
| logMessage("Game started! Your turn to move."); | |
| } | |
| function renderGame() { | |
| // Clear canvas | |
| gameCanvas.innerHTML = ''; | |
| // Render player | |
| const player = document.createElement('div'); | |
| player.className = 'character'; | |
| player.style.left = `${gameState.playerPosition.x}px`; | |
| player.style.top = `${gameState.playerPosition.y}px`; | |
| gameCanvas.appendChild(player); | |
| // Render sword | |
| const sword = document.createElement('div'); | |
| sword.className = 'sword'; | |
| sword.style.left = `${gameState.playerPosition.x}px`; | |
| sword.style.top = `${gameState.playerPosition.y + 15}px`; | |
| sword.style.transform = `rotate(${gameState.swordAngle}deg)`; | |
| gameCanvas.appendChild(sword); | |
| // Render enemies | |
| gameState.enemies.forEach(enemy => { | |
| const enemyElement = document.createElement('div'); | |
| enemyElement.className = 'enemy'; | |
| enemyElement.style.left = `${enemy.x}px`; | |
| enemyElement.style.top = `${enemy.y}px`; | |
| gameCanvas.appendChild(enemyElement); | |
| }); | |
| } | |
| function setupControls() { | |
| moveUp.addEventListener('click', () => selectMove(0, -30)); | |
| moveDown.addEventListener('click', () => selectMove(0, 30)); | |
| moveLeft.addEventListener('click', () => selectMove(-30, 0)); | |
| moveRight.addEventListener('click', () => selectMove(30, 0)); | |
| spinBlade.addEventListener('click', () => { | |
| if (!gameState.moveConfirmed) { | |
| selectMove(0, 0, true); | |
| } | |
| }); | |
| // Add confirm button | |
| const confirmButton = document.createElement('button'); | |
| confirmButton.id = 'confirmMove'; | |
| confirmButton.className = 'btn-action bg-green-600 hover:bg-green-700 col-span-3'; | |
| confirmButton.innerHTML = '<i data-feather="check"></i> Confirm Move'; | |
| document.querySelector('.grid.grid-cols-3').appendChild(confirmButton); | |
| confirmButton.addEventListener('click', confirmMove); | |
| feather.replace(); | |
| } | |
| function selectMove(dx, dy, isSpin = false) { | |
| if (!gameState.playerTurn || gameState.moveConfirmed) return; | |
| const newX = gameState.playerPosition.x + dx; | |
| const newY = gameState.playerPosition.y + dy; | |
| // Boundary check for moves (not needed for spin) | |
| if (!isSpin && (newX < 0 || newX > gameCanvas.offsetWidth - 30 || | |
| newY < 0 || newY > gameCanvas.offsetHeight - 30)) { | |
| logMessage("Can't move there - out of bounds!"); | |
| return; | |
| } | |
| gameState.selectedMove = { dx, dy, isSpin }; | |
| logMessage(isSpin ? "Spin blade selected!" : `Move to (${newX}, ${newY}) selected`); | |
| } | |
| function confirmMove() { | |
| if (!gameState.playerTurn || !gameState.selectedMove || gameState.moveConfirmed) return; | |
| gameState.moveConfirmed = true; | |
| if (gameState.selectedMove.isSpin) { | |
| startSpin(); | |
| } else { | |
| gameState.playerPosition.x += gameState.selectedMove.dx; | |
| gameState.playerPosition.y += gameState.selectedMove.dy; | |
| renderGame(); | |
| endTurn(); | |
| } | |
| } | |
| function movePlayer(dx, dy) { | |
| if (!gameState.playerTurn) return; | |
| const newX = gameState.playerPosition.x + dx; | |
| const newY = gameState.playerPosition.y + dy; | |
| // Boundary check | |
| if (newX >= 0 && newX <= gameCanvas.offsetWidth - 30 && | |
| newY >= 0 && newY <= gameCanvas.offsetHeight - 30) { | |
| gameState.playerPosition.x = newX; | |
| gameState.playerPosition.y = newY; | |
| logMessage(`Moved to (${newX}, ${newY})`); | |
| renderGame(); | |
| endTurn(); | |
| } else { | |
| logMessage("Can't move there - out of bounds!"); | |
| } | |
| } | |
| function startSpin() { | |
| if (!gameState.playerTurn) return; | |
| gameState.swordSpinning = true; | |
| gameState.swordSpeed = 10; | |
| logMessage("Spinning blade! Enemies beware!"); | |
| endTurn(); | |
| } | |
| function updateSpinning() { | |
| if (gameState.swordSpinning) { | |
| gameState.swordAngle += gameState.swordSpeed; | |
| // Slow down over time | |
| gameState.swordSpeed *= 0.98; | |
| if (gameState.swordSpeed < 0.5) { | |
| gameState.swordSpinning = false; | |
| gameState.swordSpeed = 0; | |
| } | |
| // Check for collisions with enemies | |
| checkBladeCollisions(); | |
| renderGame(); | |
| } | |
| } | |
| function checkBladeCollisions() { | |
| const bladeLength = 40; | |
| const bladeX = gameState.playerPosition.x + Math.cos(gameState.swordAngle * Math.PI / 180) * bladeLength; | |
| const bladeY = gameState.playerPosition.y + 15 + Math.sin(gameState.swordAngle * Math.PI / 180) * bladeLength; | |
| gameState.enemies.forEach((enemy, index) => { | |
| const distance = Math.sqrt( | |
| Math.pow(bladeX - (enemy.x + 15), 2) + | |
| Math.pow(bladeY - (enemy.y + 15), 2) | |
| ); | |
| if (distance < 20) { | |
| // Enemy hit! | |
| gameState.enemies.splice(index, 1); | |
| logMessage("Enemy defeated by spinning blade!"); | |
| } | |
| }); | |
| } | |
| function moveEnemies() { | |
| gameState.enemies.forEach(enemy => { | |
| switch (enemy.direction) { | |
| case 'up': | |
| enemy.y = Math.max(0, enemy.y - enemy.speed); | |
| if (enemy.y === 0) enemy.direction = 'down'; | |
| break; | |
| case 'down': | |
| enemy.y = Math.min(gameCanvas.offsetHeight - 30, enemy.y + enemy.speed); | |
| if (enemy.y === gameCanvas.offsetHeight - 30) enemy.direction = 'up'; | |
| break; | |
| case 'left': | |
| enemy.x = Math.max(0, enemy.x - enemy.speed); | |
| if (enemy.x === 0) enemy.direction = 'right'; | |
| break; | |
| case 'right': | |
| enemy.x = Math.min(gameCanvas.offsetWidth - 30, enemy.x + enemy.speed); | |
| if (enemy.x === gameCanvas.offsetWidth - 30) enemy.direction = 'left'; | |
| break; | |
| } | |
| }); | |
| } | |
| function endTurn() { | |
| gameState.playerTurn = false; | |
| gameState.selectedMove = null; | |
| gameState.moveConfirmed = false; | |
| turnIndicator.textContent = "Enemy Turn"; | |
| turnIndicator.className = "px-3 py-1 bg-red-600 rounded-full"; | |
| setTimeout(() => { | |
| // Enemy moves | |
| moveEnemies(); | |
| renderGame(); | |
| // Blade keeps spinning if it was activated | |
| updateSpinning(); | |
| // Return to player turn | |
| setTimeout(() => { | |
| if (!gameState.swordSpinning) { | |
| gameState.playerTurn = true; | |
| turnIndicator.textContent = "Player Turn"; | |
| turnIndicator.className = "px-3 py-1 bg-blue-600 rounded-full"; | |
| logMessage("Your turn! Select a move."); | |
| } else { | |
| // If blade is still spinning, enemies get another turn | |
| endTurn(); | |
| } | |
| }, 500); | |
| }, 1000); | |
| } | |
| function logMessage(message) { | |
| gameState.gameLog.push(message); | |
| if (gameState.gameLog.length > 10) gameState.gameLog.shift(); | |
| gameLog.innerHTML = gameState.gameLog.map(msg => | |
| `<div class="mb-1 last:mb-0">${msg}</div>` | |
| ).join(''); | |
| gameLog.scrollTop = gameLog.scrollHeight; | |
| } | |
| // Game loop for spinning blade | |
| setInterval(() => { | |
| if (gameState.swordSpinning && !gameState.playerTurn) { | |
| updateSpinning(); | |
| } | |
| }, 16); | |
| }); |