Spaces:
Running
Running
<html lang="ko"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>ํด์ ์ ๋ต ์๋ฎฌ๋ ์ด์ </title> | |
<style> | |
body { | |
margin: 0; | |
padding: 20px; | |
background-color: #f0f0f0; | |
font-family: Arial, sans-serif; | |
} | |
#gameContainer { | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
} | |
#gameCanvas { | |
border: 2px solid #333; | |
box-shadow: 0 0 10px rgba(0,0,0,0.2); | |
background-color: #fff; | |
} | |
#gameInfo { | |
margin-top: 20px; | |
padding: 10px; | |
background-color: #fff; | |
border: 1px solid #ccc; | |
border-radius: 5px; | |
} | |
.controls { | |
margin-top: 10px; | |
display: flex; | |
gap: 10px; | |
} | |
button { | |
padding: 5px 10px; | |
cursor: pointer; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="gameContainer"> | |
<canvas id="gameCanvas"></canvas> | |
<div id="gameInfo"> | |
<div id="turnInfo">ํ์ฌ ํด: ์ ์๊ตฐ</div> | |
<div id="selectedUnit">์ ํ๋ ์ ๋: ์์</div> | |
<div class="controls"> | |
<button id="endTurn">ํด ์ข ๋ฃ</button> | |
<button id="resetGame">๊ฒ์ ์ฌ์์</button> | |
</div> | |
</div> | |
</div> | |
<script> | |
// ๊ฒ์ ์์ | |
const GRID_SIZE = 80; | |
const COLS = 10; | |
const ROWS = 6; | |
// Canvas ์ค์ | |
const canvas = document.getElementById('gameCanvas'); | |
const ctx = canvas.getContext('2d'); | |
canvas.width = GRID_SIZE * COLS; | |
canvas.height = GRID_SIZE * ROWS; | |
// ์งํ ๋ฐ์ดํฐ | |
const elevationData = [ | |
[1, 1, 2, 2, 2, 2, 1, 1, 1, 1], | |
[1, 2, 2, 3, 3, 2, 2, 1, 1, 1], | |
[1, 2, 3, 3, 2, 2, 2, 2, 1, 1], | |
[1, 2, 2, 2, 2, 2, 3, 2, 2, 1], | |
[1, 1, 2, 2, 2, 3, 2, 2, 1, 1], | |
[1, 1, 1, 2, 2, 2, 2, 1, 1, 1] | |
]; | |
// ์ ๋ ํด๋์ค | |
class Unit { | |
constructor(type, team, x, y) { | |
this.type = type; | |
this.team = team; | |
this.x = x; | |
this.y = y; | |
this.hp = this.getInitialHP(); | |
this.moved = false; | |
this.attacked = false; | |
// ์ ๋ ํ์ ๋ณ ์คํฏ | |
const stats = { | |
'Infantry': { move: 2, attack: 3, defense: 3, range: 1 }, | |
'Archer': { move: 2, attack: 2, defense: 2, range: 3 }, | |
'Cavalry': { move: 3, attack: 4, defense: 2, range: 1 } | |
}; | |
Object.assign(this, stats[type]); | |
} | |
getInitialHP() { | |
const hpValues = { | |
'Infantry': 25, | |
'Archer': 20, | |
'Cavalry': 22 | |
}; | |
return hpValues[this.type]; | |
} | |
draw() { | |
const x = this.x * GRID_SIZE; | |
const y = this.y * GRID_SIZE; | |
// ์ ๋ ๊ธฐ๋ณธ ๋ชจ์ | |
ctx.fillStyle = this.team === 'red' ? '#ff0000' : '#0000ff'; | |
ctx.beginPath(); | |
ctx.arc(x + GRID_SIZE/2, y + GRID_SIZE/2, GRID_SIZE/3, 0, Math.PI * 2); | |
ctx.fill(); | |
// ์ ๋ ํ์ ํ์ | |
ctx.fillStyle = '#ffffff'; | |
ctx.font = '14px Arial'; | |
ctx.textAlign = 'center'; | |
ctx.fillText(this.type[0], x + GRID_SIZE/2, y + GRID_SIZE/2 + 5); | |
// HP ๋ฐ | |
this.drawHealthBar(x, y); | |
} | |
drawHealthBar(x, y) { | |
const maxHP = this.getInitialHP(); | |
const barWidth = GRID_SIZE * 0.8; | |
const barHeight = 5; | |
const barX = x + GRID_SIZE * 0.1; | |
const barY = y + GRID_SIZE * 0.8; | |
// ๋ฐฐ๊ฒฝ | |
ctx.fillStyle = '#ff0000'; | |
ctx.fillRect(barX, barY, barWidth, barHeight); | |
// ํ์ฌ ์ฒด๋ ฅ | |
ctx.fillStyle = '#00ff00'; | |
ctx.fillRect(barX, barY, (this.hp / maxHP) * barWidth, barHeight); | |
} | |
} | |
// ๊ฒ์ ์ํ | |
let gameState = { | |
units: [], | |
selectedUnit: null, | |
currentTurn: 'red', | |
turnCount: 1 | |
}; | |
// ๊ฒ์ ์ด๊ธฐํ | |
function initGame() { | |
gameState.units = []; | |
gameState.currentTurn = 'red'; | |
gameState.turnCount = 1; | |
gameState.selectedUnit = null; | |
// ์ ์๊ตฐ ์ ๋ ๋ฐฐ์น | |
for(let i = 0; i < 6; i++) { | |
gameState.units.push(new Unit('Infantry', 'red', 0, i)); | |
} | |
for(let i = 0; i < 3; i++) { | |
gameState.units.push(new Unit('Archer', 'red', 1, i*2)); | |
gameState.units.push(new Unit('Cavalry', 'red', 2, i*2)); | |
} | |
// ์ฒญ์๊ตฐ ์ ๋ ๋ฐฐ์น | |
for(let i = 0; i < 6; i++) { | |
gameState.units.push(new Unit('Infantry', 'blue', 9, i)); | |
} | |
for(let i = 0; i < 3; i++) { | |
gameState.units.push(new Unit('Archer', 'blue', 8, i*2)); | |
gameState.units.push(new Unit('Cavalry', 'blue', 7, i*2)); | |
} | |
} | |
// ๊ฒฉ์ ๊ทธ๋ฆฌ๊ธฐ | |
function drawGrid() { | |
ctx.strokeStyle = '#ccc'; | |
ctx.lineWidth = 1; | |
for(let x = 0; x <= canvas.width; x += GRID_SIZE) { | |
ctx.beginPath(); | |
ctx.moveTo(x, 0); | |
ctx.lineTo(x, canvas.height); | |
ctx.stroke(); | |
} | |
for(let y = 0; y <= canvas.height; y += GRID_SIZE) { | |
ctx.beginPath(); | |
ctx.moveTo(0, y); | |
ctx.lineTo(canvas.width, y); | |
ctx.stroke(); | |
} | |
} | |
// ์งํ ๊ทธ๋ฆฌ๊ธฐ | |
function drawTerrain() { | |
// ๋ฐฐ๊ฒฝ | |
ctx.fillStyle = '#e8e8d0'; | |
ctx.fillRect(0, 0, canvas.width, canvas.height); | |
// ๋๋ฎ์ด ํ์ | |
elevationData.forEach((row, y) => { | |
row.forEach((height, x) => { | |
ctx.fillStyle = `rgba(0,0,0,${height * 0.1})`; | |
ctx.fillRect(x * GRID_SIZE, y * GRID_SIZE, GRID_SIZE, GRID_SIZE); | |
}); | |
}); | |
// ๊ฐ | |
ctx.strokeStyle = '#4040ff'; | |
ctx.lineWidth = 20; | |
ctx.beginPath(); | |
ctx.moveTo(0, canvas.height/2); | |
ctx.bezierCurveTo( | |
canvas.width/4, canvas.height/2 - 40, | |
canvas.width*3/4, canvas.height/2 + 40, | |
canvas.width, canvas.height/2 | |
); | |
ctx.stroke(); | |
} | |
// ๊ฒ์ ํ๋ฉด ๊ฐฑ์ | |
function render() { | |
ctx.clearRect(0, 0, canvas.width, canvas.height); | |
drawTerrain(); | |
drawGrid(); | |
// ์ ๋ ๊ทธ๋ฆฌ๊ธฐ | |
gameState.units.forEach(unit => unit.draw()); | |
// ์ ํ๋ ์ ๋ ํ์ด๋ผ์ดํธ | |
if(gameState.selectedUnit) { | |
const x = gameState.selectedUnit.x * GRID_SIZE; | |
const y = gameState.selectedUnit.y * GRID_SIZE; | |
ctx.strokeStyle = '#ffff00'; | |
ctx.lineWidth = 3; | |
ctx.strokeRect(x, y, GRID_SIZE, GRID_SIZE); | |
} | |
// ํด ์ ๋ณด ์ ๋ฐ์ดํธ | |
document.getElementById('turnInfo').textContent = | |
`ํ์ฌ ํด: ${gameState.currentTurn === 'red' ? '์ ์๊ตฐ' : '์ฒญ์๊ตฐ'} (${gameState.turnCount}ํด)`; | |
document.getElementById('selectedUnit').textContent = | |
gameState.selectedUnit ? | |
`์ ํ๋ ์ ๋: ${gameState.selectedUnit.type} (HP: ${gameState.selectedUnit.hp})` : | |
'์ ํ๋ ์ ๋: ์์'; | |
} | |
// ์ด๋ฒคํธ ๋ฆฌ์ค๋ | |
canvas.addEventListener('click', handleClick); | |
document.getElementById('endTurn').addEventListener('click', endTurn); | |
document.getElementById('resetGame').addEventListener('click', () => { | |
initGame(); | |
render(); | |
}); | |
function handleClick(e) { | |
const rect = canvas.getBoundingClientRect(); | |
const x = Math.floor((e.clientX - rect.left) / GRID_SIZE); | |
const y = Math.floor((e.clientY - rect.top) / GRID_SIZE); | |
const clickedUnit = gameState.units.find(unit => unit.x === x && unit.y === y); | |
if(clickedUnit && clickedUnit.team === gameState.currentTurn) { | |
gameState.selectedUnit = clickedUnit; | |
} else if(gameState.selectedUnit) { | |
// ์ด๋ ๋๋ ๊ณต๊ฒฉ ๋ก์ง | |
moveUnit(gameState.selectedUnit, x, y); | |
} | |
render(); | |
} | |
function moveUnit(unit, targetX, targetY) { | |
if(!unit.moved && isValidMove(unit, targetX, targetY)) { | |
unit.x = targetX; | |
unit.y = targetY; | |
unit.moved = true; | |
} | |
} | |
function isValidMove(unit, targetX, targetY) { | |
const dx = Math.abs(targetX - unit.x); | |
const dy = Math.abs(targetY - unit.y); | |
return dx + dy <= unit.move; | |
} | |
function endTurn() { | |
gameState.currentTurn = gameState.currentTurn === 'red' ? 'blue' : 'red'; | |
if(gameState.currentTurn === 'red') gameState.turnCount++; | |
// ์ ๋ ์ํ ์ด๊ธฐํ | |
gameState.units.forEach(unit => { | |
unit.moved = false; | |
unit.attacked = false; | |
}); | |
gameState.selectedUnit = null; | |
render(); | |
} | |
// ๊ฒ์ ์์ | |
initGame(); | |
render(); | |
</script> | |
</body> | |
</html> |