From 89a9cf03ff09d82dcb050d27dfaf50f1144587c5 Mon Sep 17 00:00:00 2001 From: slweeb <91897291+slweeb@users.noreply.github.com> Date: Tue, 2 Jul 2024 14:35:58 -0400 Subject: [PATCH] doom.js --- mod-list.html | 2 +- mods/doom.js | 935 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 936 insertions(+), 1 deletion(-) create mode 100644 mods/doom.js diff --git a/mod-list.html b/mod-list.html index 2298a079..0b5c089c 100644 --- a/mod-list.html +++ b/mod-list.html @@ -288,7 +288,7 @@ amogus.jsAdds a small amogus structureAlice citybuilding.jsAdds seeds that create miniature buildings and other city-related itemsSquareScreamYT collab_mod.jsCreated by multiple people, adds random thingsmrapple, ilikepizza, stefanblox -Doom Mod (Unreleased)As seen on TikTok - Not yet available!ggod +doom.jsAs seen on TikTok - Select the Doom element to start, WASDggod elem3.jsAdds all elements and combinations from Elemental 3 [Very Large]Sophie fools+.jsimproves and makes fools.js EXTREMELY annoying.SquareScreamYT funny elements 2022-11-15.jsAdds a few curated randomly-generated elementsAlice diff --git a/mods/doom.js b/mods/doom.js new file mode 100644 index 00000000..1305e647 --- /dev/null +++ b/mods/doom.js @@ -0,0 +1,935 @@ +elements.screen = { + name: "Screen", + color: "#000000", + hidden: true +} +elements.doom = { + color: "#000000", + onSelect: function() { + startDoom() + } +} + +let running = false; + +const offsetX = 0; +const offsetY = 0; +const screenWidth = 166 - (2 * offsetX); +const screenHeight = 82 - (2 * offsetY); +const halfHeight = screenHeight / 2 + offsetY; + +const fov = 50; +const halfFov = fov / 2; + +const showDebugText = true; + +const map = [ + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,0,0,0,0,0,2,2,2,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1], + [1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,3,0,0,0,3,0,0,0,1], + [1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,0,0,0,0,0,2,2,0,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,4,0,0,0,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,4,0,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], + [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] +]; + +const colors = ["#ff0000", "#0000ff", "#ffffff", "#808080", "#ff5000"]; + +const defaults = { + x: 2, + y: 2, + angle: 90 +} + +const colorSettings = { + floor: "#cccccc", + ceiling: "#1e1e1e", +} + +const mapHeight = map.length; +const mapWidth = map[0].length; +const minimapOffset = 5; + +const speed = { + movementSpeed: 0.5, + rotationalSpeed: 5, + verticalRotationalSpeed: 5, +} + +const planeX = 0; +const planeY = 0.66; + +const inc = fov / screenWidth; +const precision_ = 64; +const maxDist = 25; +const accuracy = 1; + + +// const colorSettings = { +// floor: "#d1bd62", +// ceiling: "#f0c743" +// } + +const degToRad = (deg) => deg * (Math.PI / 180); +const radToDeg = (rad) => rad * (180 / Math.PI); +const splitHex = (hex) => hex.slice(1).match(/../g).map(a => Math.floor(parseInt(a, 16))); +const hexify = (rgb) => rgb.map(a => Math.floor(a).toString(16).padStart(2, "0")).join(""); +function colorLerp(color_, color2_, t) { + const color = splitHex(color_); + const color2 = splitHex(color2_); + const r = (1 - t) * color[0] + t * color2[0]; + const g = (1 - t) * color[1] + t * color2[1]; + const b = (1 - t) * color[2] + t * color2[2]; + return hexify([r, g, b]); +} + +function clamp(x, min, max) { + return Math.max(min, Math.min(x, max)); +} + +class Player { + constructor(x, y, angle) { + this.x = x; + this.y = y; + this.angle = angle; + this.verticalOffset = 0; + } + + update(key) { + // if (key.keyCode == 37) { // left + if (key.key == "a") { + this.angle -= speed.rotationalSpeed; + // } else if (key.keyCode == 39) { // right + } else if (key.key == "d") { + this.angle += speed.rotationalSpeed; + } else if (key.key == "b") { // up + this.verticalOffset = clamp(this.verticalOffset + 5, -45, 45); + } else if (key.key == "n") { // down + this.verticalOffset = clamp(this.verticalOffset - 5, -45, 45); + } + if (key.key == "w") { + console.log(this.angle); + const playerCos = Math.cos(degToRad(this.angle)) * speed.movementSpeed; + const playerSin = Math.sin(degToRad(this.angle)) * speed.movementSpeed; + const newX = this.x + playerCos; + const newY = this.y + playerSin; + const oldX = this.x; + const oldY = this.y; + if (map[Math.floor(newY)][Math.floor(oldX)] == 0) { + this.y = newY; + } + if (map[Math.floor(oldY)][Math.floor(newX)] == 0) { + this.x = newX; + } + } else if (key.key == "s") { + const playerCos = Math.cos(degToRad(this.angle)) * speed.movementSpeed; + const playerSin = Math.sin(degToRad(this.angle)) * speed.movementSpeed; + const newX = this.x - playerCos; + const newY = this.y - playerSin; + const oldX = this.x; + const oldY = this.y; + if (map[Math.floor(newY)][Math.floor(oldX)] == 0) { + this.y = newY; + } + if (map[Math.floor(oldY)][Math.floor(newX)] == 0) { + this.x = newX; + } + } else if (key.key == "a" && shiftDown) { + const playerCos = Math.cos(degToRad(this.angle + 90)) * speed.movementSpeed; + const playerSin = Math.sin(degToRad(this.angle + 90)) * speed.movementSpeed; + const newX = this.x - playerCos; + const newY = this.y - playerSin; + const oldX = this.x; + const oldY = this.y; + if (map[Math.floor(newY)][Math.floor(oldX)] == 0) { + this.y = newY; + } + if (map[Math.floor(oldY)][Math.floor(newX)] == 0) { + this.x = newX; + } + } else if (key.key == "d" && shiftDown) { + const playerCos = Math.cos(degToRad(this.angle - 90)) * speed.movementSpeed; + const playerSin = Math.sin(degToRad(this.angle - 90)) * speed.movementSpeed; + const newX = this.x - playerCos; + const newY = this.y - playerSin; + const oldX = this.x; + const oldY = this.y; + if (map[Math.floor(newY)][Math.floor(oldX)] == 0) { + this.y = newY; + } + if (map[Math.floor(oldY)][Math.floor(newX)] == 0) { + this.x = newX; + } + } + } +} + +const player = new Player(defaults.x, defaults.y, defaults.angle); + +// 5x5 +const font = { + a: [ + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 1, + 0, 1, 1, 1, 1, + 1, 0, 0, 0, 1, + 0, 1, 1, 1, 1 + ], + b: [ + 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 0 + ], + c: [ + 0, 1, 1, 1, 1, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 1, 1, 1, 1 + ], + d: [ + 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 0 + ], + e: [ + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1 + ], + f: [ + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0 + ], + g: [ + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, + 1, 0, 1, 1, 1, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 1 + ], + h: [ + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1 + ], + i: [ + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0 + ], + j: [ + 0, 0, 0, 0, 1, + 0, 0, 0, 0, 1, + 0, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 0, 1, 1, 1, 0 + ], + k: [ + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 0, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0 + ], + l: [ + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0 + ], + m: [ + 1, 1, 1, 1, 0, + 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1 + ], + n: [ + 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1 + ], + o: [ + 0, 1, 1, 1, 0, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 0, 1, 1, 1, 0 + ], + p: [ + 1, 1, 1, 1, 0, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0 + ], + q: [ + 0, 1, 1, 1, 1, + 1, 0, 0, 0, 1, + 0, 1, 1, 1, 1, + 0, 0, 0, 0, 1, + 0, 0, 0, 0, 1 + ], + r: [ + 1, 0, 1, 1, 1, + 1, 1, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0 + ], + s: [ + 0, 1, 1, 1, 1, + 1, 0, 0, 0, 0, + 0, 1, 1, 1, 0, + 0, 0, 0, 0, 1, + 1, 1, 1, 1, 0 + ], + t: [ + 1, 1, 1, 1, 1, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0 + ], + u: [ + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 1 + ], + v: [ + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 0, 1, 0, 1, 0, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0 + ], + w: [ + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 0, 1, 0, 1, + 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0 + ], + x: [ + 1, 0, 0, 0, 1, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 1, 0, 0, 0, 1 + ], + y: [ + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0, + 0, 0, 1, 0, 0 + ], + z: [ + 1, 1, 1, 1, 0, + 0, 0, 0, 1, 0, + 0, 1, 1, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 0 + ], + "0": [ + 1, 1, 1, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 0, 0, 1, 0, + 1, 1, 1, 1, 0 + ], + "1": [ + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0 + ], + "2": [ + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1 + ], + "3": [ + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1 + ], + "4": [ + 1, 0, 0, 0, 1, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 1, + 0, 0, 0, 0, 1 + ], + "5": [ + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1 + ], + "6": [ + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 1 + ], + "7": [ + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 1, + 0, 0, 0, 0, 1, + 0, 0, 0, 0, 1, + 0, 0, 0, 0, 1 + ], + "8": [ + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 1 + ], + "9": [ + 1, 1, 1, 1, 1, + 1, 0, 0, 0, 1, + 1, 1, 1, 1, 1, + 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1 + ], + ".": [ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0 + ], + ":": [ + 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0 + ], + "-": [ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 + ], + "+": [ + 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 1, 1, 1, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, + ], + ",": [ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + ], + "[": [ + 1, 1, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 1, 0, 0, 0 + ], + "]": [ + 1, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 1, 1, 0, 0, 0 + ], + "(": [ + 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0 + ], + ")": [ + 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0 + ], + ";": [ + 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0 + ], + "!": [ + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0 + ], + "{": [ + 0, 1, 1, 0, 0, + 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 1, 1, 0, 0 + ], + "}": [ + 1, 1, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 1, 0, 0, 0, + 1, 1, 0, 0, 0 + ], + "_": [ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0 + ], + "°": [ + 1, 1, 1, 0, 0, + 1, 0, 1, 0, 0, + 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 + ], + "|": [ + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0, + 1, 0, 0, 0, 0 + ] +} + +const customWidth = { + i: 1, + l: 4, + z: 4, + "0": 4, + "1": 1, + ".": 1, + ":": 1, + "-": 3, + "+": 3, + ",": 1, + "[": 2, + "]": 2, + "(": 2, + ")": 2, + ";": 1, + "!": 1, + "{": 3, + "}": 3, + "_": 3, + "°": 3, + " ": 3, + "|": 1, +} + +class TextRenderer { + static getCharWidth(char) { + return customWidth[char] ?? 5; + } + + static drawChar(char, x, y, color) { + if (!font[char]) return; + const width = this.getCharWidth(); + for (let i = 0; i < width; i++) { + for (let j = 0; j < 5; j++) { + if (font[char][j * 5 + i] == 1) { + pixelMap[x + offsetX + i][y + offsetY + j].color = color; + } + } + } + } + + static drawText(text, x, y, color) { + let offset = 0; + for (const char of text.toLowerCase().split("")) { + const width = this.getCharWidth(char); + this.drawChar(char, x + offset, y, color); + offset += width + 1; + } + } + + static getStringWidth(text) { + return text.split("").map(a => this.getCharWidth(a)).reduce((a, b) => a + b, 0) + text.length - 1; + } + + static drawCenteredText(text, x1, y, color) { + const x = Math.floor(x1 - (this.getStringWidth(text) / 2)); + this.drawText(text, x, y, color); + } +} + +class ButtonRegistry { + constructor (screen, buttons) { + this.screen = screen; + this.buttons = buttons; + this.currentButton = 0; + if (this.buttons.length > 0) { + this.buttons[this.currentButton].toggleSelection(); + } + } + + next() { + this.buttons[this.currentButton].toggleSelection(); + this.currentButton++; + if (this.currentButton >= this.buttons.length) { + this.currentButton %= this.buttons.length; + } + this.buttons[this.currentButton].toggleSelection(); + } + + prev() { + this.buttons[this.currentButton].toggleSelection(); + this.currentButton--; + if (this.currentButton < 0) { + this.currentButton = this.buttons.length - 1; + } + this.buttons[this.currentButton].toggleSelection(); + } + + current() { + return this.buttons[this.currentButton]; + } +} + +class GameMenu { + constructor (name, screen, width, height, offsets = null) { + this.name = name; + this.screen = screen; + this.width = width; + this.height = height; + this.offsetX = Math.floor((screenWidth - width - (offsets ? offsets.x : 0)) / 2) + (offsets ? offsets.x : 0); + this.offsetY = Math.floor((screenHeight - height - 10 - (offsets ? offsets.y : 0)) / 2) + (offsets ? offsets.y : 0) + 10; + this.buttons = []; + this.buttonRegistry = new ButtonRegistry(this, []); + } + + draw() { + for (const button of this.buttons) { + button.draw(); + } + } + + getOffsetX() { + return offsetX + this.offsetX; + } + + getOffsetY() { + return offsetY + this.offsetY; + } + + onKey(ev) { + if (ev.key == "b") { // up + this.buttonRegistry.prev(); + } else if (ev.key == "n") { // down + this.buttonRegistry.next(); + } else if (ev.key == "Enter") { + this.buttonRegistry.current().click(); + } + } + + addButtons(...buttons) { + this.buttons.push(...buttons); + this.updateButtonRegistry(); + } + + getButtons() { + return this.buttons; + } + + updateButtonRegistry() { + this.buttonRegistry = new ButtonRegistry(this, this.buttons); + } +} + +class GuiButton { + constructor (x, y, width, height, text, color, screen) { + this.x = x + screen.getOffsetX(); + this.y = y + screen.getOffsetY(); + this.width = width; + this.height = height; + this.text = text; + this.color = color; + this.onPressed = () => {}; + this.selected = false; + this.screen = screen; + } + + draw() { + for (let i = this.x; i < this.x + this.width; i++) { + for (let j = this.y; j < this.y + this.height; j++) { + if (this.selected && (i == this.x || j == this.y || i == this.x + this.width - 1 || j == this.y + this.height - 1)) { + pixelMap[i][j] = "#0080000"; + } else pixelMap[i][j] = this.color + } + } + TextRenderer.drawCenteredText(this.text, this.x + (this.width / 2), Math.floor(this.y + (this.height / 2) - 5/2), "#ffffff"); + } + + onClick(cb) { + this.onPressed = cb; + } + + click() { + this.onPressed(); + } + + toggleSelection() { + this.selected = !this.selected; + } +} + +class GuiUtils { + static drawRect(x1, y1, x2, y2, color) { + for (let i = Math.max(Math.min(x1, x2), 0); i < Math.min(Math.max(x1, x2), width); i++) { + for (let j = Math.max(Math.min(y1, y2), 0); j < Math.min(Math.max(y1, y2), height); j++) { + pixelMap[i][j].color = color; + } + } + } + + static drawOutline(x1, y1, x2, y2, color) { + const initI = Math.max(Math.min(x1, x2), 0); + const endI = Math.min(Math.max(x1, x2), width); + const initJ = Math.max(Math.min(y1, y2), 0); + const endJ = Math.min(Math.max(y1, y2), height); + for (let i = initI; i < endI; i++) { + for (let j = initJ; j < endJ; j++) { + if (i == initI || i == endI - 1 || j == initJ || j == endJ - 1) { + pixelMap[i][j].color = color; + } + } + } + } + + static drawVerticalLine(x, y1, y2, color) { + for (let i = Math.max(Math.min(y1, y2), 0); i <= Math.min(Math.max(y1, y2), height); i++) { + if (!pixelMap[x][i]) continue; + pixelMap[x][i].color = color; + } + } +} + +class TestGameMenu extends GameMenu { + constructor (screen, width, height, offsets = null) { + super("test menu screen", screen, width, height, offsets); + const button1 = new GuiButton(1, 1, width - 2, 20, "button", "#005555", this); + button1.onClick(() => { + button1.color = "#ff0000"; + button2.color = "#005555"; + }) + const button2 = new GuiButton(1, 22, width - 2, 20, "button 2", "#005555", this); + button2.onClick(() => { + button2.color = "#ff0000"; + button1.color = "#005555"; + }) + this.addButtons( + button1, + button2 + ) + } + draw() { + for (let i = this.getOffsetX(); i < this.width + this.getOffsetX(); i++) { + for (let j = this.getOffsetY(); j < this.height + this.getOffsetY(); j++) { + pixelMap[i][j].color = "#ffffff"; + } + } + super.draw(); + } +} + +class GameScreen { + clock() { + this.fps = this.currentFrames; + this.currentFrames = 0; + } + clear() { + for (let i = offsetX; i < width - offsetX; i++) { + for (let j = offsetY; j < height - offsetY; j++) { + pixelMap[i][j].color = "#ffffff"; + } + } + } + + draw() { + if (!this.currentFrames) this.currentFrames = 0; + this.currentFrames++; + this.clear(); + this.drawLevel(); + this.drawMinimap(); + if (showDebugText) { + TextRenderer.drawText(`angle: ${Math.floor(player.angle)}°`, 1, 1, "#ffffff"); + TextRenderer.drawText(`pos: ${player.x.toFixed(2)} | ${player.y.toFixed(2)}`, 1, 7, "#ffffff"); + TextRenderer.drawText(`fps: ${this.fps}`, 1, 13, "#ffffff"); + TextRenderer.drawText(`vertangle: ${player.verticalOffset}`, 1, 19, "#ffffff"); + } + if (this.menuScreen) { + this.drawMenu(); + } + } + + drawMenu() { + this.drawOverlay(); + GuiUtils.drawRect(this.menuScreen.getOffsetX(), Math.floor((screenHeight - this.menuScreen.height) / 2) - 2, this.menuScreen.getOffsetX() + this.menuScreen.width, this.menuScreen.getOffsetY(), "#1e1e1e"); + TextRenderer.drawCenteredText(this.menuScreen.name, (this.menuScreen.width / 2) + this.menuScreen.getOffsetX(), Math.floor((screenHeight - this.menuScreen.height) / 2) - 1, "#ffffff"); + this.menuScreen.draw(); + } + + drawOverlay() { + for (let i = offsetX; i < width - offsetX; i++) { + for (let j = offsetY; j < height - offsetY; j++) { + pixelMap[i][j].color = "#" + colorLerp(pixelMap[i][j].color, "#000000", 0.5); + } + } + } + + drawLevel() { + let rayAngle = player.angle - halfFov; + for (let i = 0; i < screenWidth; i += accuracy) { + let rayX = player.x; + let rayY = player.y; + const rayCos = Math.cos(degToRad(rayAngle)) / precision_; + const raySin = Math.sin(degToRad(rayAngle)) / precision_; + let wall = 0; + + while (wall == 0) { + rayX += rayCos; + rayY += raySin; + wall = map[Math.floor(rayY)][Math.floor(rayX)]; + } + + const angle = radToDeg(Math.atan2(rayY, rayX)); + const side = (angle >= 45 && angle <= 135) || (angle >= 275 && angle <= 315); + + const distance = Math.sqrt((player.x - rayX) ** 2 + (player.y - rayY) ** 2) * Math.cos(degToRad(rayAngle - player.angle)); + + const wallHeight = Math.floor(halfHeight / distance); + + let t = Math.min(1, (1 / maxDist) * distance); + + const color = "#" + colorLerp(colors[wall - 1], "#000000", t); + const ceilingColor = colorSettings.ceiling; + const floorColor = colorSettings.floor; + + GuiUtils.drawVerticalLine(offsetX + i, halfHeight - wallHeight - player.verticalOffset, halfHeight + wallHeight - player.verticalOffset, color); + GuiUtils.drawVerticalLine(offsetX + i, offsetY, halfHeight - wallHeight - 1 - player.verticalOffset, ceilingColor); + GuiUtils.drawVerticalLine(offsetX + i, halfHeight + wallHeight + 1 - player.verticalOffset, height - offsetY - 1, floorColor); + + rayAngle += inc; + } + } + + drawMinimap() { + for (let i = 0; i < mapWidth; i++) { + for (let j = 0; j < mapHeight; j++) { + const x = width - offsetX - minimapOffset - mapWidth + i; + const y = offsetY + minimapOffset + j; + if (map[j][i] == 0) { + pixelMap[x][y].color = colorSettings.floor; + } else { + pixelMap[x][y].color = colors[map[j][i] - 1]; + } + if (i == Math.floor(player.x) && j == Math.floor(player.y)) { + pixelMap[x][y].color = "#00ffff"; + } + } + } + } + + onKey(ev) { + // if (ev.key == "Escape") { + // this.menuScreen = this.menuScreen ? null : new TestGameMenu(this, Math.floor(0.75 * screenWidth), Math.floor(0.75 * screenHeight)); + // } + if (!this.menuScreen) { + player.update(ev); + } else { + this.menuScreen.onKey(ev); + } + } +} + +const game = new GameScreen(); + +setInterval(cellTick, (1000/(tps*4))); +setInterval(() => {game.clock()}, 1000); + +function cellTick() { + if (running && !paused) { + game.draw(); + } +} + +function startDoom() { + if (!running) { + videoFrame = 0; + + for (let i = offsetX; i < width - offsetX; i++) { + for (let j = offsetY; j < height - offsetY; j++) { + if (pixelMap[i][j]) deletePixel(i, j); + createPixel("screen", i, j); + } + } + } + running = !running; +} + +window.addEventListener("keydown", (ev) => { + if (ev.key == "u") { + startDoom(); + } else { + game.onKey(ev); + } +}) \ No newline at end of file