From: Elias Fleckenstein Date: Tue, 29 Jun 2021 13:04:53 +0000 (+0200) Subject: Abstract MapDisplay from Map X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=5c6e4bb4f573bd33d6b2b0058d17f4190b90e74b;p=dragonblocks.git Abstract MapDisplay from Map - Support changing the currently rendered map - Implement map switching for entities - Use DOM references for Map and entities - Refactor DBLib --- diff --git a/engine/hudbar.js b/engine/hudbar.js index 354d8d3..3855fe0 100644 --- a/engine/hudbar.js +++ b/engine/hudbar.js @@ -32,7 +32,7 @@ dragonblocks.Hudbar = class this.selectedSlot = 0; - let display = document.body.insertBefore(document.createElement("div"), document.getElementById("dragonblocks.map").nextSibling); + let display = document.body.insertBefore(document.createElement("div"), dragonblocks.mapDisplay.element.nextSibling); display.id = "dragonblocks.hudbar[" + this.id + "]"; display.style.position = "fixed"; display.style.bottom = "5px"; @@ -41,7 +41,7 @@ dragonblocks.Hudbar = class dblib.center(display); - for(let i = 0; i < this.slots; i++){ + for (let i = 0; i < this.slots; i++) { let slotDisplay = display.appendChild(document.createElement("div")); slotDisplay.id = "dragonblocks.hudbar[" + this.id + "].slot[" + i + "]"; slotDisplay.style.position = "absolute"; diff --git a/engine/init.js b/engine/init.js index 24d945a..72fe1d4 100644 --- a/engine/init.js +++ b/engine/init.js @@ -183,6 +183,7 @@ "group", "builtin", "map_node", + "map_display", "map", "item_stack", "inventory", diff --git a/engine/map.js b/engine/map.js index 0a56229..db4211a 100644 --- a/engine/map.js +++ b/engine/map.js @@ -25,13 +25,16 @@ dragonblocks.Map = class { constructor(data) { + this.active = false; + + this.entityContainer = dragonblocks.mapDisplay.element.appendChild(document.createElement("div")); + this.entityContainer.style.position = "absolute"; + this.entityContainer.style.visibility = "hidden"; + if (data) this.deserialize(data); else this.clear(); - - this.initGraphics(); - this.updateGraphics(); } serialize() @@ -67,6 +70,18 @@ dragonblocks.Map = class new dragonblocks.SpawnedEntity(entity); } + setActive() + { + this.active = true; + this.entityContainer.style.visibility = "inherit"; + } + + setInactive() + { + this.active = false; + this.entityContainer.style.visibility = "hidden"; + } + clear() { this.data = []; @@ -109,7 +124,7 @@ dragonblocks.Map = class let nodeDef = node.toNode(); nodeDef.onset && nodeDef.onset(this, x, y); - this.updateNodeGraphics(x, y); + this.active && dragonblocks.mapDisplay.updateNode(x, y); } } @@ -131,80 +146,6 @@ dragonblocks.Map = class } } - getNodeDisplay(x, y) - { - return document.getElementById("dragonblocks.map.node[" + (x - this.displayLeft) + "][" + (y - this.displayTop) + "]"); - } - - getScreenCoordinates(x, y) - { - return [Math.floor(x / dragonblocks.settings.map.scale) + this.displayLeft, Math.floor(y / dragonblocks.settings.map.scale) + this.displayTop]; - } - - updateNodeGraphics(x, y) - { - let nodeDisplay = this.getNodeDisplay(x, y); - - if (! nodeDisplay) - return; - - let nodeDef = this.getNode(x, y).toNode(); - - if (! nodeDef) - return; - - nodeDisplay.style.background = dragonblocks.getTexture(nodeDef.texture); - nodeDisplay.style.backgroundSize = "cover"; - nodeDisplay.style.zIndex = nodeDef.zIndex || "1"; - } - - updateGraphics() - { - if (this.displayLeft < 0) - this.displayLeft = 0; - else if (this.displayLeft + this.displayWidth > this.width) - this.displayLeft = this.width - this.displayWidth; - - if (this.displayTop < 0) - this.displayTop = 0; - else if (this.displayTop + this.displayHeight > this.height) - this.displayTop = this.height - this.displayHeight; - - for (let x = 0; x < this.displayWidth; x++) { - for(let y = 0; y < this.displayHeight; y++) { - this.updateNodeGraphics(x + this.displayLeft, y + this.displayTop); - } - } - } - - initGraphics() - { - this.displayWidth = Math.min(Math.ceil(innerWidth / dragonblocks.settings.map.scale), this.width); - this.displayHeight = Math.min(Math.ceil(innerHeight / dragonblocks.settings.map.scale), this.height); - - let display = document.body.insertBefore(document.createElement("div"), document.body.firstChild); - display.id = "dragonblocks.map"; - display.style.width = this.displayWidth * dragonblocks.settings.map.scale + "px"; - display.style.height = this.displayHeight * dragonblocks.settings.map.scale + "px"; - display.style.position = "fixed"; - display.style.top = "0px"; - display.style.left = "0px"; - display.style.backgroundColor = "skyblue"; - display.style.visibility = "hidden"; - - for (let x = 0; x < this.displayWidth; x++){ - for (let y = 0; y < this.displayHeight; y++){ - let nodeDisplay = display.appendChild(document.createElement("div")); - nodeDisplay.id = "dragonblocks.map.node[" + x + "][" + y + "]"; - nodeDisplay.style.position = "absolute"; - nodeDisplay.style.top = y * dragonblocks.settings.map.scale + "px"; - nodeDisplay.style.left = x * dragonblocks.settings.map.scale + "px"; - nodeDisplay.style.width = dragonblocks.settings.map.scale + "px"; - nodeDisplay.style.height = dragonblocks.settings.map.scale + "px"; - } - } - } - addStructure(name, msg, pos) { this.structures[name] = this.structures[name] || []; @@ -225,11 +166,3 @@ dragonblocks.onActivateCallbacks = []; dragonblocks.registerOnActivate = func => { dragonblocks.onActivateCallbacks.push(func); }; - -dragonblocks.registerOnStarted(_ => { - document.getElementById("dragonblocks.map").style.visibility = "visible"; -}); - -dragonblocks.registerOnQuit(_ => { - document.getElementById("dragonblocks.map").style.visibility = "hidden"; -}); diff --git a/engine/map_display.js b/engine/map_display.js new file mode 100644 index 0000000..474cb8a --- /dev/null +++ b/engine/map_display.js @@ -0,0 +1,199 @@ +/* + * map_display.js + * + * Copyright 2021 Elias Fleckenstein + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + * + */ + +dragonblocks.MapDisplay = class +{ + constructor() + { + this.map = null; + this.anchor = null; + + this.scale = dragonblocks.settings.mapDisplay.scale; + this.width = Math.ceil(innerWidth / this.scale); + this.height = Math.ceil(innerHeight / this.scale); + this.left = 0; + this.top = 0; + + this.element = document.body.insertBefore(document.createElement("div"), document.body.firstChild); + this.element.style.width = this.width * this.scale + "px"; + this.element.style.height = this.height * this.scale + "px"; + this.element.style.position = "fixed"; + this.element.style.top = "0px"; + this.element.style.left = "0px"; + this.element.style.visibility = "hidden"; + + this.nodes = []; + for (let x = 0; x < this.width; x++) { + this.nodes[x] = []; + for (let y = 0; y < this.height; y++) { + let node = this.nodes[x][y] = this.element.appendChild(document.createElement("div")); + node.style.position = "absolute"; + node.style.top = y * this.scale + "px"; + node.style.left = x * this.scale + "px"; + node.style.width = this.scale + "px"; + node.style.height = this.scale + "px"; + } + } + } + + setActive() + { + let self = this; + + this.interval = setInterval(_ => { + self.autoScroll(); + }); + + this.element.style.visibility = "visible"; + } + + setInactive() + { + if (this.interval) { + clearInterval(this.interval); + delete this.interval; + } + + this.map = null; + this.anchor = null; + + this.element.style.visibility = "hidden"; + } + + setMap(map) + { + if (this.map) + this.map.setInactive(); + + this.map = map; + this.map.setActive(); + + this.autoScroll() || this.update(); + } + + setAnchor(anchor) + { + this.anchor = anchor; + this.autoScroll(); + } + + setSkyColor(color) + { + this.element.style.backgroundColor = color; + } + + getActiveEntityContainer() + { + return this.entityContainers[this.map]; + } + + isInitialized() + { + return this.map && this.anchor; + } + + withinBounds(x, y) + { + return x < this.width && y < this.height && x >= 0 && y >= 0; + } + + getNode(x, y) + { + return this.withinBounds(x, y) && this.nodes[x][y]; + } + + updateNode(x, y) + { + if (! this.isInitialized()) + return; + + let node = this.getNode(x - this.left, y - this.top); + + if (! node) + return; + + let mapNodeDef = this.map.getNode(x, y).toNode(); + + if (mapNodeDef) { + node.style.background = dragonblocks.getTexture(mapNodeDef.texture); + node.style.backgroundSize = "cover"; + node.style.zIndex = mapNodeDef.zIndex || "1"; + } else { + node.style.background = "black"; + } + } + + autoScroll() + { + if (! this.isInitialized()) + return; + + let oldLeft, oldTop; + oldLeft = this.left; + oldTop = this.top; + + if (this.map.width >= this.width) + this.left = parseInt(Math.max(Math.min(this.left, this.map.width - this.width, this.anchor.x - 3), 0, this.anchor.x + this.anchor.width + 3 - this.width)); + else + this.left = parseInt((this.width - this.map.width) / 2); + + if (this.map.width >= this.width) + this.top = parseInt(Math.max(Math.min(this.top, this.map.height - this.height, this.anchor.y - 3), 0, this.anchor.y + this.anchor.height + 3 - this.height)); + else + this.top = parseInt((this.height - this.map.height) / 2); + + let changed = oldLeft != this.left || oldTop != this.top; + + if (changed) + this.update(); + + return changed; + } + + update() + { + if (! this.isInitialized()) + return; + + this.map.entityContainer.style.left = -this.left * this.scale + "px"; + this.map.entityContainer.style.top = -this.top * this.scale + "px"; + + for (let x = 0; x < this.width; x++) + for(let y = 0; y < this.height; y++) + this.updateNode(x + this.left, y + this.top); + } +}; + +dragonblocks.mapDisplay = new dragonblocks.MapDisplay(); + +dragonblocks.registerOnQuit(_ => { + dragonblocks.mapDisplay.setInactive(); +}); + +dragonblocks.registerOnStarted(_ => { + dragonblocks.mapDisplay.setSkyColor("skyblue"); + dragonblocks.mapDisplay.setMap(dragonblocks.world.map); + dragonblocks.mapDisplay.setAnchor(dragonblocks.player); + + dragonblocks.mapDisplay.setActive(); +}); diff --git a/engine/map_interaction.js b/engine/map_interaction.js index 8f3fe0d..6220a4e 100644 --- a/engine/map_interaction.js +++ b/engine/map_interaction.js @@ -24,33 +24,33 @@ dragonblocks.MapInteraction = { initMapInteraction() { - let crack = document.getElementById("dragonblocks.map").appendChild(document.createElement("div")); - crack.id = "dragonblocks.crack[" + this.id + "]"; - crack.style.position = "absolute"; - crack.style.visibility = "hidden"; - crack.style.backgroundSize = "cover"; - crack.style.height = dragonblocks.settings.map.scale + "px"; - crack.style.width = dragonblocks.settings.map.scale + "px"; - crack.style.boxShadow = "0 0 0 1px black inset"; - crack.style.zIndex = 2; + this.tmp.crackDisplay = this.map.entityContainer.appendChild(document.createElement("div")); + this.tmp.crackDisplay.style.position = "absolute"; + this.tmp.crackDisplay.style.visibility = "hidden"; + this.tmp.crackDisplay.style.backgroundSize = "cover"; + this.tmp.crackDisplay.style.height = dragonblocks.settings.mapDisplay.scale + "px"; + this.tmp.crackDisplay.style.width = dragonblocks.settings.mapDisplay.scale + "px"; + this.tmp.crackDisplay.style.boxShadow = "0 0 0 1px black inset"; let self = this; - crack.addEventListener("mouseleave", event => { + this.tmp.crackDisplay.addEventListener("mouseleave", event => { self.digStop(); - let [x, y] = self.map.getScreenCoordinates(event.srcElement.offsetLeft, event.srcElement.offsetTop); - self.map.getNodeDisplay(x, y).style.boxShadow = "none"; + dragonblocks.mapDisplay.getNode(event.srcElement.offsetLeft / dragonblocks.settings.mapDisplay.scale - dragonblocks.mapDisplay.left, event.srcElement.offsetTop / dragonblocks.settings.mapDisplay.scale - dragonblocks.mapDisplay.top).style.boxShadow = "none"; }); - crack.addEventListener("mouseover", event => { - let [x, y] = self.map.getScreenCoordinates(event.srcElement.offsetLeft + document.getElementById("dragonblocks.map").offsetLeft, event.srcElement.offsetTop + document.getElementById("dragonblocks.map").offsetTop); - self.map.getNodeDisplay(x, y).style.boxShadow = "0 0 0 1px black inset"; + this.tmp.crackDisplay.addEventListener("mouseover", event => { + dragonblocks.mapDisplay.getNode(event.srcElement.offsetLeft / dragonblocks.settings.mapDisplay.scale - dragonblocks.mapDisplay.left, event.srcElement.offsetTop / dragonblocks.settings.mapDisplay.scale - dragonblocks.mapDisplay.top).style.boxShadow = "0 0 0 1px black inset"; }); }, + updateMapInteractionMap() + { + this.tmp.crackDisplay = this.map.entityContainer.appendChild(this.tmp.crackDisplay); + }, + dig(map, x, y) { - console.log(this); let node = map.getNode(x, y); if (! node) @@ -79,10 +79,9 @@ dragonblocks.MapInteraction = { if (! this.canReach(x, y)) return; - let crack = document.getElementById("dragonblocks.crack[" + this.id + "]") - crack.style.visibility = "visible"; - crack.style.left = (x - this.map.displayLeft) * dragonblocks.settings.map.scale + "px"; - crack.style.top = (y - this.map.displayTop) * dragonblocks.settings.map.scale + "px"; + this.tmp.crackDisplay.style.visibility = "inherit"; + this.tmp.crackDisplay.style.left = x * dragonblocks.settings.mapDisplay.scale + "px"; + this.tmp.crackDisplay.style.top = y * dragonblocks.settings.mapDisplay.scale + "px"; dragonblocks.log("Punched Node at (" + x + ", " + y + ")"); @@ -115,10 +114,9 @@ dragonblocks.MapInteraction = { } else { nodeDef.playSound("dig"); - let crack = document.getElementById("dragonblocks.crack[" + this.id + "]"); - crack.style.background = dragonblocks.getTexture("crack" + Math.floor(node.meta.causedDamage / nodeDef.hardness * 5) + ".png"); - crack.style.backgroundSize = "cover"; - crack.style.zIndex = nodeDef.zIndex || "1"; + this.tmp.crackDisplay.style.background = dragonblocks.getTexture("crack" + Math.floor(node.meta.causedDamage / nodeDef.hardness * 5) + ".png"); + this.tmp.crackDisplay.style.backgroundSize = "cover"; + this.tmp.crackDisplay.style.zIndex = nodeDef.zIndex || "1"; this.tmp.digTimeout = setTimeout(_ => { self.digTick(x, y); @@ -138,13 +136,13 @@ dragonblocks.MapInteraction = { if (this.dig(this.map, x, y)) dragonblocks.handleNodeDrop(this.tmp.mainInventory, nodeDef, this.map, x, y); - document.getElementById("dragonblocks.crack[" + this.id + "]").style.visibility = "hidden"; + this.tmp.crackDisplay.style.visibility = "hidden"; }, digStop() { clearTimeout(this.tmp.digTimeout); - document.getElementById("dragonblocks.crack[" + this.id + "]").style.visibility = "hidden"; + this.tmp.crackDisplay.style.visibility = "hidden"; }, place(map, x, y, node) @@ -167,7 +165,7 @@ dragonblocks.MapInteraction = { build(x, y) { - if(this.canReach(x, y)) { + if (this.canReach(x, y)) { let oldNodeDef = this.map.getNode(x, y).toNode(); oldNodeDef.onclick && oldNodeDef.onclick(this.map, x, y); diff --git a/engine/player.js b/engine/player.js index 4a8d1d1..6b371cb 100644 --- a/engine/player.js +++ b/engine/player.js @@ -130,21 +130,6 @@ dragonblocks.Player = class extends dragonblocks.SpawnedEntity this.tmp.defaultTool = dragonblocks.tools[this.meta.creative ? "dragonblocks:creative_hand" : "dragonblocks:hand"]; this.initMapInteraction(); - // Map Scroll - setInterval(_ => { - if (map.displayLeft + map.displayWidth < self.x + self.width + 3) - map.displayLeft = parseInt(self.x + self.width + 3 - map.displayWidth); - else if (map.displayLeft > self.x - 2) - map.displayLeft = parseInt(self.x - 2); - - if (map.displayTop + map.displayHeight < self.y + self.height + 3) - map.displayTop = parseInt(self.y + self.height + 3 - map.displayHeight); - else if (map.displayTop > self.y - 2) - map.displayTop = parseInt(self.y - 2); - - map.updateGraphics(); - }); - // Controls dragonblocks.keyHandler.down(" ", _ => { self.jump(); @@ -231,12 +216,12 @@ dragonblocks.Player = class extends dragonblocks.SpawnedEntity }); // Map Interaction Controls - for (let x = 0; x < map.displayWidth; x++) { - for (let y = 0; y < map.displayHeight; y++) { - let nodeDisplay = document.getElementById("dragonblocks.map.node[" + x + "][" + y + "]"); + for (let x = 0; x < dragonblocks.mapDisplay.width; x++) { + for (let y = 0; y < dragonblocks.mapDisplay.height; y++) { + let nodeDisplay = dragonblocks.mapDisplay.getNode(x, y); nodeDisplay.addEventListener("mouseover", event => { - if (self.canReach(x + map.displayLeft, y + map.displayTop)) + if (self.canReach(x + dragonblocks.mapDisplay.left, y + dragonblocks.mapDisplay.top)) event.srcElement.style.boxShadow = "0 0 0 1px black inset"; }); @@ -245,7 +230,7 @@ dragonblocks.Player = class extends dragonblocks.SpawnedEntity }); nodeDisplay.addEventListener("mousedown", event => { - let [ix, iy] = [x + map.displayLeft, y + map.displayTop]; + let [ix, iy] = [x + dragonblocks.mapDisplay.left, y + dragonblocks.mapDisplay.top]; switch(event.which) { case 1: @@ -266,6 +251,13 @@ dragonblocks.Player = class extends dragonblocks.SpawnedEntity return dblib.removeTmp([this])[0]; } + setMap(map, x, y) + { + super.setMap(map, x, y); + this.updateMapInteractionMap(); + dragonblocks.mapDisplay.setMap(map); + } + set skin(value) { this.meta.skin = value; diff --git a/engine/skin.js b/engine/skin.js index 9989be6..ea1e1f7 100644 --- a/engine/skin.js +++ b/engine/skin.js @@ -42,10 +42,10 @@ dragonblocks.registerSkin = def => { status.style.top = "5px"; status.style.left = "5px"; - let columns = parseInt(parseInt(gui.display.style.width) / (dragonblocks.settings.map.scale * 1.5)); + let columns = parseInt(parseInt(gui.display.style.width) / (dragonblocks.settings.mapDisplay.scale * 1.5)); let container = gui.create("div"); - container.style.width = parseInt(columns * dragonblocks.settings.map.scale * 1.5) + "px"; + container.style.width = parseInt(columns * dragonblocks.settings.mapDisplay.scale * 1.5) + "px"; container.style.position = "absolute"; container.style.top = "80px"; dblib.center(container); diff --git a/engine/spawned_entity.js b/engine/spawned_entity.js index 94202d0..5bbb96e 100644 --- a/engine/spawned_entity.js +++ b/engine/spawned_entity.js @@ -73,6 +73,13 @@ dragonblocks.SpawnedEntity = class return dragonblocks.entities[this.name]; } + setMap(map, x, y) + { + this.tmp.display = map.entityContainer.appendChild(this.display); + this.tmp.map = map; + this.teleport(x, y); + } + despawn() { let entityDef = this.toEntity(); @@ -86,8 +93,7 @@ dragonblocks.SpawnedEntity = class clearInterval(this.physicInterval); clearInterval(this.tickInterval); - let display = document.getElementById("dragonblocks.entity[" + this.id + "]"); - display && display.remove(); + this.tmp.display && this.tmp.display.remove(); } restorePhysics() @@ -194,24 +200,23 @@ dragonblocks.SpawnedEntity = class addGraphics(obj) { - let display = document.getElementById("dragonblocks.map").appendChild(document.createElement("div")); - display.id = "dragonblocks.entity[" + this.id + "]"; - display.style.position = "absolute"; - display.style.width = this.width * dragonblocks.settings.map.scale + "px"; - display.style.height = this.height * dragonblocks.settings.map.scale + "px"; - display.style.zIndex = "0"; - - display.addEventListener("mouseover", event => { + this.tmp.display = this.map.entityContainer.appendChild(document.createElement("div")); + this.tmp.display.style.position = "absolute"; + this.tmp.display.style.width = this.width * dragonblocks.settings.mapDisplay.scale + "px"; + this.tmp.display.style.height = this.height * dragonblocks.settings.mapDisplay.scale + "px"; + this.tmp.display.style.zIndex = "0"; + + this.tmp.display.addEventListener("mouseover", event => { event.srcElement.style.boxShadow = "0 0 0 1px black inset"; }); - display.addEventListener("mouseleave", event => { + this.tmp.display.addEventListener("mouseleave", event => { event.srcElement.style.boxShadow = "none"; }); let self = this; - display.addEventListener("mousedown", event => { + this.tmp.display.addEventListener("mousedown", event => { let entityDef = self.toEntity(); switch (event.which) { @@ -231,20 +236,17 @@ dragonblocks.SpawnedEntity = class async updateGraphics() { - let display = document.getElementById("dragonblocks.entity[" + this.id + "]"); - - if (! display) + if (! this.tmp.display) return; - display.style.left = (this.x - this.map.displayLeft) * dragonblocks.settings.map.scale + "px"; - display.style.top = (this.y - this.map.displayTop) * dragonblocks.settings.map.scale + "px"; + this.tmp.display.style.left = this.x * dragonblocks.settings.mapDisplay.scale + "px"; + this.tmp.display.style.top = this.y * dragonblocks.settings.mapDisplay.scale + "px"; } updateTexture() { - let display = document.getElementById("dragonblocks.entity[" + this.id + "]"); - display.style.background = dragonblocks.getTexture(this.texture); - display.style.backgroundSize = "cover"; + this.tmp.display.style.background = dragonblocks.getTexture(this.texture); + this.tmp.display.style.backgroundSize = "cover"; } teleport(x, y) diff --git a/engine/world.js b/engine/world.js index 11996e5..2579788 100644 --- a/engine/world.js +++ b/engine/world.js @@ -36,9 +36,10 @@ dragonblocks.World = class this.loadMods(); this.map = new dragonblocks.Map(); - this.player = new dragonblocks.Player(null, this.map); + this.player = new dragonblocks.Player(null, this.map); this.player.setGamemode(properties.gamemode); + dragonblocks.mapgen.generate(properties.mapgen, this.map); } } diff --git a/index.html b/index.html index a4f30d4..7343787 100644 --- a/index.html +++ b/index.html @@ -4,8 +4,7 @@ - - +