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 =...