mirror of
https://github.com/ION606/ProcGen.git
synced 2026-05-14 13:56:56 +00:00
first commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
# What is this?
|
||||
This is a procedurally-generated game that can run right in your browser!
|
||||
|
||||
Created by ION606
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ProcGen Mark I</title>
|
||||
<link rel="stylesheet" type="text/css" href="/styles/style.css">
|
||||
<script src="/scripts/init.js"></script>
|
||||
<script src="/scripts/player.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<button class="hidebtn" onclick="reset()">🗑</button>
|
||||
<main class="dispGrid">
|
||||
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,93 @@
|
||||
const MACROS = {
|
||||
TILE_SIZE: 80,
|
||||
COLORS: ['red', 'orange', 'yellow', 'green', 'blue', 'purple', 'white',' black'],
|
||||
}
|
||||
|
||||
class Coordinates {
|
||||
/**
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
*/
|
||||
constructor(x, y) {this.x = x; this.y = y;}
|
||||
}
|
||||
|
||||
const getRandInRange = (boundUpper, boundLower = 0, asFloat = true) => {
|
||||
const ogNum = (Math.random() * (boundUpper - boundLower)) + boundLower;
|
||||
return (asFloat) ? ogNum : Math.floor(ogNum);
|
||||
}
|
||||
|
||||
const inRange = (x, min, max) => (x >= min && x <= max);
|
||||
|
||||
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
if (!localStorage.getItem('seed')) localStorage.setItem('seed', Math.round(Date.now() * Math.random()));
|
||||
MACROS.seed = Number(localStorage.getItem('seed'));
|
||||
|
||||
MACROS.numTiles = [Math.floor((window.innerWidth) / MACROS.TILE_SIZE),Math.floor((window.innerHeight) / MACROS.TILE_SIZE)];
|
||||
|
||||
// create the grid
|
||||
for (let i = 0; i < MACROS.numTiles[1]; i++) {
|
||||
const row = document.createElement('div');
|
||||
row.className = 'gridRow';
|
||||
row.style.columnCount = MACROS.numTiles[0];
|
||||
|
||||
for (let j = 0; j < MACROS.numTiles[0]; j++) {
|
||||
// const bkcol = MACROS.COLORS[getRandInRange(MACROS.COLORS.length, 0, false)];
|
||||
const colBox = document.createElement('div');
|
||||
colBox.className = "colBox";
|
||||
// colBox.innerText = bkcol;
|
||||
colBox.style.backgroundColor = 'black';
|
||||
colBox.style.width = `${MACROS.TILE_SIZE}px`;
|
||||
colBox.style.height = `${MACROS.TILE_SIZE}px`;
|
||||
|
||||
row.appendChild(colBox);
|
||||
}
|
||||
|
||||
document.getElementsByTagName('main')[0].appendChild(row);
|
||||
}
|
||||
|
||||
// setInterval(() => {
|
||||
// const x = genRandInRange(0, window.screenX),
|
||||
// y = genRandInRange(0, window.screenY);
|
||||
|
||||
// console.log(x, y)
|
||||
// }, 1000)
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* RANDOM, NOT OPTIMIZED
|
||||
* @param {[Number, Number]} startCoords
|
||||
* @param {[Number, Number]} endCoords
|
||||
*/
|
||||
function makePath(startCoords, endCoords) {
|
||||
const main = document.getElementsByTagName('main')[0];
|
||||
const w = main.children.length,
|
||||
h = main.children[0].children.length;
|
||||
|
||||
let [x, y] = startCoords;
|
||||
let [ex, ey] = endCoords;
|
||||
|
||||
while (x != ex && y != ey) {
|
||||
const dir = Math.floor(Math.random() * 4);
|
||||
if (dir == 0 && y - 1 >= 0) y -= 1;
|
||||
else if (dir == 1 && y + 1 < MACROS.numTiles[1]) y += 1;
|
||||
else if (dir == 2 && x - 1 >= 0) x -= 1;
|
||||
else if (dir == 3 && x + 1 < MACROS.numTiles[0]) x += 1;
|
||||
|
||||
const currentTile = main.children[y].children[x];
|
||||
currentTile.style.backgroundColor = 'white';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function putTrees() {
|
||||
const main = document.getElementsByTagName('main')[0];
|
||||
|
||||
const numTreesOnScreen = Math.round(getRandInRange(MACROS.numTiles[1])/1.5);
|
||||
for (let i = 0; i < numTreesOnScreen; i++) {
|
||||
const [x, y] = Math.floor(MACROS.numTiles * Math.random())
|
||||
const currentTile = main.children[y].children[x];
|
||||
currentTile.style.backgroundColor = 'white';
|
||||
}
|
||||
}
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
const MACROS = {
|
||||
TILE_SIZE: 30,
|
||||
COLORS: ['red', 'orange', 'yellow', 'green', 'blue', 'purple', 'white', 'black'],
|
||||
ROOM_MIN_SIZE: 3,
|
||||
ROOM_MAX_SIZE: 6,
|
||||
HALLWAY_WIDTH: 1
|
||||
};
|
||||
|
||||
const inRange = (x, min, max) => (x >= min && x <= max);
|
||||
|
||||
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
if (!localStorage.getItem('seed')) {
|
||||
localStorage.setItem('seed', Math.round(Date.now() * Math.random()));
|
||||
}
|
||||
MACROS.seed = Number(localStorage.getItem('seed'));
|
||||
MACROS.numTiles = [Math.floor(window.innerWidth / MACROS.TILE_SIZE), Math.floor(window.innerHeight / MACROS.TILE_SIZE)];
|
||||
|
||||
const r = loadMap();
|
||||
if (r) return;
|
||||
|
||||
const main = document.querySelector('main.dispGrid');
|
||||
|
||||
// create the grid
|
||||
for (let i = 0; i < MACROS.numTiles[1]; i++) {
|
||||
const row = document.createElement('div');
|
||||
row.className = 'gridRow';
|
||||
row.style.columnCount = MACROS.numTiles[0];
|
||||
|
||||
for (let j = 0; j < MACROS.numTiles[0]; j++) {
|
||||
// const bkcol = MACROS.COLORS[getRandInRange(MACROS.COLORS.length, 0, false)];
|
||||
const colBox = document.createElement('div');
|
||||
colBox.className = "colBox";
|
||||
// colBox.innerText = bkcol;
|
||||
colBox.style.width = `${MACROS.TILE_SIZE}px`;
|
||||
colBox.style.height = `${MACROS.TILE_SIZE}px`;
|
||||
|
||||
row.appendChild(colBox);
|
||||
}
|
||||
|
||||
main.appendChild(row);
|
||||
}
|
||||
|
||||
generateMap(); // Call the map generation after grid initialization
|
||||
});
|
||||
|
||||
function generateRooms() {
|
||||
const main = document.querySelector('main.dispGrid');
|
||||
|
||||
// idk make one for every 20 tiles
|
||||
const numRoomsRaw = (MACROS.numTiles[0] / 20) > 1 ? Math.round((MACROS.numTiles[0] / 10)) : 2;
|
||||
const numRooms = getRandInRange(numRoomsRaw, 2, false);
|
||||
let rooms = [];
|
||||
|
||||
for (let i = 0; i < numRooms; i++) {
|
||||
const roomWidth = getRandInRange(MACROS.ROOM_MAX_SIZE, MACROS.ROOM_MIN_SIZE, false),
|
||||
roomHeight = getRandInRange(MACROS.ROOM_MAX_SIZE, MACROS.ROOM_MIN_SIZE, false),
|
||||
x = getRandInRange(MACROS.numTiles[0] - roomWidth, 0, false),
|
||||
y = getRandInRange(MACROS.numTiles[1] - roomHeight, 0, false);
|
||||
|
||||
rooms.push({ x, y, width: roomWidth, height: roomHeight });
|
||||
|
||||
for (let ry = y; ry < y + roomHeight; ry++) {
|
||||
for (let rx = x; rx < x + roomWidth; rx++) {
|
||||
main.children[ry].children[rx].classList.add('room');
|
||||
}
|
||||
}
|
||||
}
|
||||
return rooms;
|
||||
}
|
||||
|
||||
/** will return the coords of the end of the path */
|
||||
function drawLineToRoom(x1, y1, x2, y2) {
|
||||
let xret = x1, yret = y1;
|
||||
const main = document.querySelector('main.dispGrid');
|
||||
// Connect horizontally from room1 to room2
|
||||
while (x1 !== x2) {
|
||||
if (main.children[y1]?.children[x1]) {
|
||||
main.children[y1].children[x1].classList.add('path');
|
||||
xret = x1;
|
||||
}
|
||||
|
||||
x1 += (x2 > x1) ? 1 : -1; // Increment or decrement to move towards x2
|
||||
}
|
||||
|
||||
// Once x1 is aligned with x2, connect vertically
|
||||
while (y1 !== y2) {
|
||||
if (main.children[y1]?.children[x1]) {
|
||||
main.children[y1].children[x1].classList.add('path');
|
||||
yret = y1;
|
||||
}
|
||||
y1 += (y2 > y1) ? 1 : -1; // Increment or decrement to move towards y2
|
||||
}
|
||||
|
||||
return {x: xret, y: yret};
|
||||
}
|
||||
|
||||
function getRandomEdgePoint() {
|
||||
const width = window.innerWidth;
|
||||
const height = window.innerHeight;
|
||||
let x, y;
|
||||
|
||||
// Choose a random edge: 0 = top, 1 = right, 2 = bottom, 3 = left
|
||||
const edge = Math.floor(Math.random() * 4);
|
||||
console.log(edge);
|
||||
|
||||
switch (edge) {
|
||||
case 0: // Top edge
|
||||
x = Math.random() * width;
|
||||
y = 0;
|
||||
break;
|
||||
case 1: // Right edge
|
||||
x = width;
|
||||
y = Math.random() * height;
|
||||
break;
|
||||
case 2: // Bottom edge
|
||||
x = Math.random() * width;
|
||||
y = height;
|
||||
break;
|
||||
case 3: // Left edge
|
||||
x = 0;
|
||||
y = Math.random() * height;
|
||||
break;
|
||||
}
|
||||
|
||||
return { x: Math.round(x), y: Math.round(y) };
|
||||
}
|
||||
|
||||
|
||||
const calculateDistance = (point1, point2) => Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
|
||||
|
||||
function findClosestRoom(edgePoint, rooms) {
|
||||
let closestRoom = null;
|
||||
let minDistance = Infinity;
|
||||
|
||||
rooms.forEach(room => {
|
||||
const roomCenter = {
|
||||
x: room.x + room.width / 2,
|
||||
y: room.y + room.height / 2
|
||||
};
|
||||
|
||||
const distance = calculateDistance(edgePoint, roomCenter);
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
closestRoom = room;
|
||||
}
|
||||
});
|
||||
|
||||
return closestRoom;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function connectRooms(room1, room2) {
|
||||
let x1 = room1.x + Math.floor(room1.width / 2);
|
||||
let y1 = room1.y + Math.floor(room1.height / 2);
|
||||
let x2 = room2.x + Math.floor(room2.width / 2);
|
||||
let y2 = room2.y + Math.floor(room2.height / 2);
|
||||
|
||||
drawLineToRoom(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
|
||||
const saveMap = () => {
|
||||
localStorage.setItem('savedMap', document.querySelector('main.dispGrid').innerHTML);
|
||||
}
|
||||
|
||||
const loadMap = () => {
|
||||
const htmlToLoad = localStorage.getItem('savedMap');
|
||||
if (htmlToLoad) {
|
||||
document.querySelector('main.dispGrid').innerHTML = htmlToLoad;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function reset(player = false) {
|
||||
localStorage.clear();
|
||||
if (player) player.save();
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
|
||||
function generateMap() {
|
||||
const rooms = generateRooms();
|
||||
for (let i = 0; i < rooms.length - 1; i++) {
|
||||
connectRooms(rooms[i], rooms[i + 1]);
|
||||
}
|
||||
|
||||
if (!localStorage.getItem('outerEdges')) {
|
||||
const outerEdges = [];
|
||||
const rToEMax = Math.round(Math.random() * rooms.length);
|
||||
|
||||
for (let i = 0; i < getRandInRange(rToEMax > 2 ? rToEMax : 2, 2, false); i++) {
|
||||
const {x, y} = getRandomEdgePoint();
|
||||
|
||||
// Find the closest room to this edge point
|
||||
const closestRoom = findClosestRoom({x, y}, rooms);
|
||||
|
||||
// Draw a line from the edge point to the center of the closest room
|
||||
outerEdges.push(drawLineToRoom(closestRoom.x, closestRoom.y, x, y));
|
||||
}
|
||||
|
||||
localStorage.setItem('outerEdges', JSON.stringify(outerEdges));
|
||||
}
|
||||
|
||||
const edges = JSON.parse(localStorage.getItem('outerEdges'));
|
||||
const main = document.querySelector('main.dispGrid');
|
||||
for (const edge of edges) {
|
||||
main.children[edge.y].children[edge.x].classList.add('edgePath');
|
||||
}
|
||||
|
||||
const edge = edges[getRandInRange(edges.length - 1, 0, false)];
|
||||
const player = new Player(edge.x, edge.y);
|
||||
player.save();
|
||||
|
||||
saveMap();
|
||||
}
|
||||
|
||||
function getRandInRange(upper, lower = 0, asFloat = true) {
|
||||
const num = Math.random() * (upper - lower) + lower;
|
||||
return asFloat ? num : Math.floor(num);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
class Player {
|
||||
constructor(startx, starty) {
|
||||
this.mainEl = document.querySelector('main.dispGrid');
|
||||
this.x = startx;
|
||||
this.y = starty;
|
||||
this.mainEl.children[this.y].children[this.x].classList.add("player");
|
||||
this.setupEventListeners();
|
||||
}
|
||||
|
||||
save() {
|
||||
const {...object} = this;
|
||||
delete object['x'];
|
||||
delete object['y'];
|
||||
localStorage.setItem('player', JSON.stringify(object));
|
||||
}
|
||||
|
||||
moveTo(newX, newY) {
|
||||
const square = this.mainEl.children[newY]?.children[newX];
|
||||
if (square?.classList?.contains('room')) {
|
||||
// for now, just move through it
|
||||
this.mainEl.children[this.y].children[this.x].classList.remove('player');
|
||||
square.classList.add('player');
|
||||
|
||||
this.x = newX;
|
||||
this.y = newY;
|
||||
}
|
||||
else if (square?.classList?.contains('edgePath')) reset(this);
|
||||
else if (square?.classList?.contains('path')) {
|
||||
this.mainEl.children[this.y].children[this.x].classList.remove('player');
|
||||
square.classList.add('player');
|
||||
this.x = newX;
|
||||
this.y = newY;
|
||||
}
|
||||
}
|
||||
|
||||
setupEventListeners() {
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'w') this.moveTo(this.x, this.y - 1);
|
||||
else if (e.key === 'a') this.moveTo(this.x - 1, this.y);
|
||||
else if (e.key === 's') this.moveTo(this.x, this.y + 1);
|
||||
else if (e.key === 'd') this.moveTo(this.x + 1, this.y);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
body {
|
||||
background-color: black;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
main {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.gridRow {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.colBox {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.dispGrid {
|
||||
display: grid;
|
||||
gap: 0px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.room {
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.path {
|
||||
background-color: grey;
|
||||
}
|
||||
|
||||
.edgePath {
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.player {
|
||||
background-color: red !important;
|
||||
}
|
||||
|
||||
.hidebtn {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 999;
|
||||
font-size: 30px;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
background-color: transparent;
|
||||
color: red;
|
||||
border: none;
|
||||
padding: auto;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.hidebtn:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
Reference in New Issue
Block a user