]> git.lizzy.rs Git - dragonblocks.git/blob - engine/map_display.js
Abstract MapDisplay from Map
[dragonblocks.git] / engine / map_display.js
1 /*
2  * map_display.js
3  *
4  * Copyright 2021 Elias Fleckenstein <eliasfleckenstein@web.de>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301, USA.
20  *
21  *
22  */
23
24 dragonblocks.MapDisplay = class
25 {
26         constructor()
27         {
28                 this.map = null;
29                 this.anchor = null;
30
31                 this.scale = dragonblocks.settings.mapDisplay.scale;
32                 this.width = Math.ceil(innerWidth / this.scale);
33                 this.height = Math.ceil(innerHeight / this.scale);
34                 this.left = 0;
35                 this.top = 0;
36
37                 this.element = document.body.insertBefore(document.createElement("div"), document.body.firstChild);
38                 this.element.style.width = this.width * this.scale + "px";
39                 this.element.style.height = this.height * this.scale + "px";
40                 this.element.style.position = "fixed";
41                 this.element.style.top = "0px";
42                 this.element.style.left = "0px";
43                 this.element.style.visibility = "hidden";
44
45                 this.nodes = [];
46                 for (let x = 0; x < this.width; x++) {
47                         this.nodes[x] = [];
48                         for (let y = 0; y < this.height; y++) {
49                                 let node = this.nodes[x][y] = this.element.appendChild(document.createElement("div"));
50                                 node.style.position = "absolute";
51                                 node.style.top = y * this.scale + "px";
52                                 node.style.left = x * this.scale + "px";
53                                 node.style.width = this.scale + "px";
54                                 node.style.height = this.scale + "px";
55                         }
56                 }
57         }
58
59         setActive()
60         {
61                 let self = this;
62
63                 this.interval = setInterval(_ => {
64                         self.autoScroll();
65                 });
66
67                 this.element.style.visibility = "visible";
68         }
69
70         setInactive()
71         {
72                 if (this.interval) {
73                         clearInterval(this.interval);
74                         delete this.interval;
75                 }
76
77                 this.map = null;
78                 this.anchor = null;
79
80                 this.element.style.visibility = "hidden";
81         }
82
83         setMap(map)
84         {
85                 if (this.map)
86                         this.map.setInactive();
87
88                 this.map = map;
89                 this.map.setActive();
90
91                 this.autoScroll() || this.update();
92         }
93
94         setAnchor(anchor)
95         {
96                 this.anchor = anchor;
97                 this.autoScroll();
98         }
99
100         setSkyColor(color)
101         {
102                 this.element.style.backgroundColor = color;
103         }
104
105         getActiveEntityContainer()
106         {
107                 return this.entityContainers[this.map];
108         }
109
110         isInitialized()
111         {
112                 return this.map && this.anchor;
113         }
114
115         withinBounds(x, y)
116         {
117                 return x < this.width && y < this.height && x >= 0 && y >= 0;
118         }
119
120         getNode(x, y)
121         {
122                 return this.withinBounds(x, y) && this.nodes[x][y];
123         }
124
125         updateNode(x, y)
126         {
127                 if (! this.isInitialized())
128                         return;
129
130                 let node = this.getNode(x - this.left, y - this.top);
131
132                 if (! node)
133                         return;
134
135                 let mapNodeDef = this.map.getNode(x, y).toNode();
136
137                 if (mapNodeDef) {
138                         node.style.background = dragonblocks.getTexture(mapNodeDef.texture);
139                         node.style.backgroundSize = "cover";
140                         node.style.zIndex = mapNodeDef.zIndex || "1";
141                 } else {
142                         node.style.background = "black";
143                 }
144         }
145
146         autoScroll()
147         {
148                 if (! this.isInitialized())
149                         return;
150
151                 let oldLeft, oldTop;
152                 oldLeft = this.left;
153                 oldTop = this.top;
154
155                 if (this.map.width >= this.width)
156                         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));
157                 else
158                         this.left = parseInt((this.width - this.map.width) / 2);
159
160                 if (this.map.width >= this.width)
161                         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));
162                 else
163                         this.top = parseInt((this.height - this.map.height) / 2);
164
165                 let changed = oldLeft != this.left || oldTop != this.top;
166
167                 if (changed)
168                         this.update();
169
170                 return changed;
171         }
172
173         update()
174         {
175                 if (! this.isInitialized())
176                         return;
177
178                 this.map.entityContainer.style.left = -this.left * this.scale + "px";
179                 this.map.entityContainer.style.top = -this.top * this.scale + "px";
180
181                 for (let x = 0; x < this.width; x++)
182                         for(let y = 0; y < this.height; y++)
183                                 this.updateNode(x + this.left, y + this.top);
184         }
185 };
186
187 dragonblocks.mapDisplay = new dragonblocks.MapDisplay();
188
189 dragonblocks.registerOnQuit(_ => {
190         dragonblocks.mapDisplay.setInactive();
191 });
192
193 dragonblocks.registerOnStarted(_ => {
194         dragonblocks.mapDisplay.setSkyColor("skyblue");
195         dragonblocks.mapDisplay.setMap(dragonblocks.world.map);
196         dragonblocks.mapDisplay.setAnchor(dragonblocks.player);
197
198         dragonblocks.mapDisplay.setActive();
199 });