LineBattle / index.html
kolaslab's picture
Update index.html
7243134 verified
<!DOCTYPE html>
<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>