From 98f57d50bdca21ea6fb9662e9b8466ad8ee3e009 Mon Sep 17 00:00:00 2001 From: ION606 Date: Sat, 27 Apr 2024 14:46:59 -0700 Subject: [PATCH] first commit --- README.md | 4 + index.html | 17 ++++ scripts/init-old.js | 93 ++++++++++++++++++ scripts/init.js | 225 ++++++++++++++++++++++++++++++++++++++++++++ scripts/player.js | 44 +++++++++ styles/style.css | 62 ++++++++++++ 6 files changed, 445 insertions(+) create mode 100644 README.md create mode 100644 index.html create mode 100644 scripts/init-old.js create mode 100644 scripts/init.js create mode 100644 scripts/player.js create mode 100644 styles/style.css diff --git a/README.md b/README.md new file mode 100644 index 0000000..7866306 --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# What is this? +This is a procedurally-generated game that can run right in your browser! + +Created by ION606 \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..81db774 --- /dev/null +++ b/index.html @@ -0,0 +1,17 @@ + + + + + + ProcGen Mark I + + + + + + +
+ +
+ + \ No newline at end of file diff --git a/scripts/init-old.js b/scripts/init-old.js new file mode 100644 index 0000000..656cf04 --- /dev/null +++ b/scripts/init-old.js @@ -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'; + } +} \ No newline at end of file diff --git a/scripts/init.js b/scripts/init.js new file mode 100644 index 0000000..78b8e95 --- /dev/null +++ b/scripts/init.js @@ -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); +} \ No newline at end of file diff --git a/scripts/player.js b/scripts/player.js new file mode 100644 index 0000000..474a6e2 --- /dev/null +++ b/scripts/player.js @@ -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); + }); + } +} diff --git a/styles/style.css b/styles/style.css new file mode 100644 index 0000000..0b51668 --- /dev/null +++ b/styles/style.css @@ -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; +} \ No newline at end of file