Dungeon Generator
by Richard
HTML
<canvas width="215" height="140" class="map">
</canvas>
<br/>
<label>
Rooms <input type="number" class="roomCount" value="8" />
</label>
<br/>
<button class="reset">
Reset
</button>
<button class="generate">
Generate
</button>
<button class="tick">
Tick
</button>
CSS
body {
background: #1f4068;
color: white;
font-family: monospace;
font-size: 16px;
}
canvas {
border-radius: 4px;
}
label,canvas {
display: block;
}
input {
border: none;
padding: 6px;
font-size: 12px;
font-family: monospace;
border-radius: 4px;
}
button {
border: none;
padding: 7px;
background: #1b1b2f;
color: white;
font-family: monospace;
border-radius: 4px;
}
JavaScript
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
const dirs = []
for (let i = -1; i < 2; i++) {
for (let j = -1; j < 2; j++) {
if (i!==0 || j!== 0) {
dirs.push({x: i, y: j})
}
}
}
let minOverlap = 4
let rooms = []
let roomCount = 8
let checked = {}
function overlapArea(rect1, rect2) {
const x = Math.min(rect1.x2, rect2.x2) - Math.max(rect1.x1, rect2.x1)
const y = Math.min(rect1.y2, rect2.y2) - Math.max(rect1.y1, rect2.y1)
return x * y;
}
function getConnectedIndex(i) {
const bounds = rooms[i].grow()
for (let j = 0; j < roomCount; j++) {
if (i !== j && !checked[j] && intersect(bounds, rooms[j])) {
if (overlapArea(bounds, rooms[j]) >= minOverlap) {
checked[j] = true
return j
}
}
}
return -1
}
function islandExists() {
let count = 0
let index = 0
checked = {}
while (true) {
index = getConnectedIndex(index)
if (index > -1) {
rooms[index].level = count
}
if (index === -1) {
// No adjacent room. Must be island.
return true
} else {
// All rooms are connected
if (++count === roomCount) return false
}
}
}
function rect(x, y, w, h) {
const pos = {
x,
y
}
const size = {
x: w,
y: h
}
let vel = dirs[Math.floor(Math.random() * dirs.length)]
return {
pos,
size,
randVel() {
vel = dirs[Math.floor(Math.random() * dirs.length)]
},
move(m =1) {
pos.x += vel.x * m;
pos.y += vel.y * m;
},
get x1() {
return pos.x
},
get y1() {
return pos.y
},
get x2() {
return pos.x + size.x
},
get y2() {
return pos.y + size.y
},
grow() {
return rect(pos.x - 1, pos.y - 1, size.x + 2, size.y + 2)
},
get s() {
return `(${pos.x}, ${pos.y}, ${size.x}, ${size.y})`
}
}
}
function rand(min, max) {
return min + Math.random() * (max - min)
}
function intersect(r1, r2) {
const noOverlap =...