HexagonGame / index.html
awacke1's picture
Create index.html
42db519 verified
raw
history blame
10.9 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hexagon Ecosystem Game</title>
<style>
body { text-align: center; background-color: #282c34; color: white; font-family: Arial; }
#gameContainer { display: flex; justify-content: space-between; }
#sidebar { width: 300px; text-align: left; padding: 10px; }
canvas { background-color: #1e1e1e; cursor: pointer; }
#timer, #counts, #selection { font-size: 18px; margin-top: 10px; }
button { margin: 3px; padding: 8px; font-size: 14px; cursor: pointer; }
.category { margin-top: 15px; }
</style>
</head>
<body>
<h1>🌱 Hexagon Ecosystem Game 🐝</h1>
<div id="gameContainer">
<div id="sidebar">
<div id="timer">Time Left: 5:00</div>
<div id="counts">Counts: Loading...</div>
<div id="selection">
<div class="category"><strong>Plants</strong></div>
<div id="plantSelection"></div>
<div class="category"><strong>Insects</strong></div>
<div id="insectSelection"></div>
<div class="category"><strong>Animals</strong></div>
<div id="animalSelection"></div>
</div>
</div>
<canvas id="gameCanvas" width="800" height="600"></canvas>
</div>
<script>
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
const hexSize = 40;
const hexWidth = Math.sqrt(3) * hexSize;
const hexHeight = 2 * hexSize;
const offsetX = hexWidth;
const offsetY = hexHeight * 0.75;
const rows = 10;
const cols = 10;
let hexGrid = [];
let timer = 300;
let selectedEntity = null;
const entities = {
plants: ["🌱", "🌿", "🍁", "🌺", "🌸", "🌼", "🌻", "🌾", "🌳", "🌴", "πŸ‚", "πŸƒ", "πŸ‡", "🍊", "🍎", "πŸ‘", "πŸ’", "πŸ“", "🍍", "πŸ₯•"],
insects: ["🐝", "πŸ¦‹", "🐞"],
animals: ["πŸ‡", "🦊", "🦌", "🐦", "🐿️"]
};
let resources = {};
let counts = {};
function initializeEntities() {
Object.keys(entities).forEach(category => {
entities[category].forEach(entity => {
resources[entity] = 5;
counts[entity] = 0;
});
});
}
function generateHexGrid() {
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
let x = col * offsetX + 150;
let y = row * hexHeight + (col % 2 ? offsetY : 0) + 50;
hexGrid.push({ x, y, type: "empty", entities: [], pollinated: false });
}
}
}
function selectEntity(entity) {
selectedEntity = entity;
}
function drawHex(hex) {
const { x, y, type, entities } = hex;
ctx.beginPath();
for (let i = 0; i < 6; i++) {
let angle = (Math.PI / 3) * i;
let px = x + hexSize * Math.cos(angle);
let py = y + hexSize * Math.sin(angle);
ctx.lineTo(px, py);
}
ctx.closePath();
ctx.fillStyle = type === "empty" ? "#C2B280" : "#90EE90";
ctx.fill();
ctx.stroke();
ctx.fillStyle = "white";
ctx.font = "20px Arial";
entities.forEach((entity, index) => {
let randX = x - 10 + (Math.random() * 20 - 10);
let randY = y + 5 + (Math.random() * 20 - 10);
ctx.fillText(entity, randX, randY);
});
}
function getNeighbors(hexIndex) {
const neighbors = [];
const row = Math.floor(hexIndex / cols);
const col = hexIndex % cols;
const directions = [
[-1, 0], [1, 0], [0, -1], [0, 1],
col % 2 ? [-1, -1] : [-1, 1],
col % 2 ? [1, -1] : [1, 1]
];
directions.forEach(([dr, dc]) => {
const newRow = row + dr;
const newCol = col + dc;
if (newRow >= 0 && newRow < rows && newCol >= 0 && newCol < cols) {
neighbors.push(newRow * cols + newCol);
}
});
return neighbors;
}
function pollinate() {
hexGrid.forEach((hex, index) => {
if (hex.entities.some(e => entities.insects.includes(e))) {
hex.entities.forEach(entity => {
if (entities.plants.includes(entity)) {
getNeighbors(index).forEach(n => {
if (hexGrid[n].type === "empty" && Math.random() < 0.1) {
hexGrid[n].entities.push(entity);
hexGrid[n].type = "occupied";
counts[entity]++;
}
});
}
});
}
});
}
function aStar(startIdx, goalIdx) {
const openSet = new Set([startIdx]);
const cameFrom = {};
const gScore = { [startIdx]: 0 };
const fScore = { [startIdx]: heuristic(startIdx, goalIdx) };
while (openSet.size > 0) {
let current = Array.from(openSet).reduce((a, b) => fScore[a] < fScore[b] ? a : b);
if (current === goalIdx) return reconstructPath(cameFrom, current);
openSet.delete(current);
getNeighbors(current).forEach(neighbor => {
const tentativeGScore = gScore[current] + 1;
if (!gScore[neighbor] || tentativeGScore < gScore[neighbor]) {
cameFrom[neighbor] = current;
gScore[neighbor] = tentativeGScore;
fScore[neighbor] = gScore[neighbor] + heuristic(neighbor, goalIdx);
openSet.add(neighbor);
}
});
}
return [];
}
function heuristic(a, b) {
const rowA = Math.floor(a / cols), colA = a % cols;
const rowB = Math.floor(b / cols), colB = b % cols;
return Math.abs(rowA - rowB) + Math.abs(colA - colB);
}
function reconstructPath(cameFrom, current) {
const path = [current];
while (cameFrom[current] !== undefined) {
current = cameFrom[current];
path.unshift(current);
}
return path;
}
function moveAnimals() {
hexGrid.forEach((hex, index) => {
hex.entities.forEach((entity, i) => {
if (entities.animals.includes(entity)) {
const neighbors = getNeighbors(index);
const mateIdx = neighbors.find(n => hexGrid[n].entities.includes(entity));
if (mateIdx && Math.random() < 0.05) {
const emptyNeighbor = neighbors.find(n => hexGrid[n].type === "empty");
if (emptyNeighbor) {
hexGrid[emptyNeighbor].entities.push(entity);
hexGrid[emptyNeighbor].type = "occupied";
counts[entity]++;
}
} else if (Math.random() < 0.2) {
const path = aStar(index, mateIdx || neighbors[Math.floor(Math.random() * neighbors.length)]);
if (path.length > 1) {
hexGrid[path[1]].entities.push(entity);
hex.entities.splice(i, 1);
if (hex.entities.length === 0) hex.type = "empty";
hexGrid[path[1]].type = "occupied";
}
}
}
});
});
}
function renderMap() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
hexGrid.forEach(hex => drawHex(hex));
}
function updateTimer() {
timer--;
document.getElementById("timer").innerText = `Time Left: ${Math.floor(timer / 60)}:${(timer % 60).toString().padStart(2, '0')}`;
if (timer % 5 === 0) {
pollinate();
moveAnimals();
updateCounts();
}
renderMap();
if (timer <= 0) {
clearInterval(gameLoop);
alert("Game Over!");
}
}
function updateCounts() {
let countText = "Counts: ";
Object.keys(counts).forEach(entity => {
countText += `${entity}: ${counts[entity]} `;
});
document.getElementById("counts").innerText = countText;
}
function populateSidebar() {
["plantSelection", "insectSelection", "animalSelection"].forEach((id, idx) => {
const category = ["plants", "insects", "animals"][idx];
const div = document.getElementById(id);
entities[category].forEach(entity => {
const btn = document.createElement("button");
btn.innerText = entity;
btn.onclick = () => selectEntity(entity);
div.appendChild(btn);
});
});
}
canvas.addEventListener("click", (event) => {
const rect = canvas.getBoundingClientRect();
const mouseX = event.clientX - rect.left;
const mouseY = event.clientY - rect.top;
hexGrid.forEach(hex => {
if (Math.hypot(hex.x - mouseX, hex.y - mouseY) < hexSize) {
if (selectedEntity && resources[selectedEntity] > 0 && hex.type === "empty") {
hex.type = "occupied";
hex.entities.push(selectedEntity);
resources[selectedEntity]--;
counts[selectedEntity]++;
updateCounts();
}
}
});
renderMap();
});
initializeEntities();
generateHexGrid();
populateSidebar();
renderMap();
let gameLoop = setInterval(updateTimer, 1000);
</script>
</body>
</html>