Skip to content

Instantly share code, notes, and snippets.

@TylerLeite
Last active July 29, 2020 00:50
Show Gist options
  • Save TylerLeite/1db6d8f0723381ab7169c966a93589dc to your computer and use it in GitHub Desktop.
Save TylerLeite/1db6d8f0723381ab7169c966a93589dc to your computer and use it in GitHub Desktop.
generate a bunch of rooms and separate them. then repeat
<html>
<head>
<style>*{margin: 0; padding: 0;}</style>
<script type="text/javascript" src="./explosion.js"></script>
</head>
<body onload="main();">
<canvas id="canvas" style="width:100vw;height:100vh"></canvas>
</body>
</html>
const step = 6
const min_radius = step*4
const max_radius = step*8
const max_rect_width = step*16
const min_aspect_ratio = 0.75
const max_aspect_ratio = 1/min_aspect_ratio
function uniform (r1, r2) {
const r = Math.random()
return r1 + (r2-r1)*r
}
function exponential () {
x = Math.random()
y = (Math.pow(Math.E, x)-1)/(Math.E-1)
return y
}
function Cell (x, y) {
const radius = uniform(min_radius, max_radius)
return {
x: x,
y: y,
radius,
rect: Rect(x, y, radius),
}
}
function randomPointOnCircle (cx, cy, cr) {
const theta = uniform(0, 2*Math.PI)
const dx = cr*Math.cos(theta)
const dy = cr*Math.sin(theta)
return {
x: cx+dx,
y: cy+dy,
}
}
function Rect (x, y, radius) {
const width = exponential()*max_rect_width
const height = width*uniform(min_aspect_ratio, max_aspect_ratio)
const c = randomPointOnCircle(x, y, radius)
const bl = {x: c.x-width/2, y: c.y+height/2}
const br = {x: c.x+width/2, y: c.y+height/2}
const tl = {x: c.x-width/2, y: c.y-height/2}
const tr = {x: c.x+width/2, y: c.y-height/2}
return [tl, tr, br, bl]
}
function drawCell (cell, ctx) {
const rect = cell.rect
ctx.beginPath();
ctx.moveTo(cell.rect[0].x, cell.rect[0].y);
ctx.lineTo(cell.rect[1].x, cell.rect[1].y);
ctx.lineTo(cell.rect[2].x, cell.rect[2].y);
ctx.lineTo(cell.rect[3].x, cell.rect[3].y);
ctx.lineTo(cell.rect[0].x, cell.rect[0].y);
ctx.stroke();
}
function rectsOverlap (r1, r2) {
const top = r2[0].y
const left = r2[0].x
const bottom = r2[2].y
const right = r2[2].x
offset = Math.floor(Math.random()*4)
for (let i = 0; i < 4; i++) {
j = (i+offset)%4
if (r1[j].x >= left && r1[j].x <= right && r1[j].y >= top && r1[j].y <= bottom) {
return j;
}
}
return -1;
}
function moveRect (cell, dx, dy) {
for (let i = 0; i < 4; i++) {
cell.rect[i].x += dx
cell.rect[i].y += dy
}
}
async function generate (n, x, y, cells) {
// generate cells
if (typeof cells === 'undefined') {
cells = []
}
for (let i = 0; i < n; i++) {
cells.push(Cell(x, y))
}
// separate cells
let overlap = true
while (overlap) {
overlap = false
for (let i = 0; i < cells.length; i++) {
for (let j = 0; j < cells.length; j++) {
if (i == j) {continue}
// check if i is overlapping j
const overlapping_corner = rectsOverlap(cells[i].rect, cells[j].rect)
if (overlapping_corner == -1) {
// if not, check the next cell
continue;
} else {
// else move away, then break
if (overlapping_corner == 0) {
moveRect(cells[i], step, step)
moveRect(cells[j], -step, -step)
} else if (overlapping_corner == 1) {
moveRect(cells[i], -step, step)
moveRect(cells[j], step, -step)
} else if (overlapping_corner == 2) {
moveRect(cells[i], -step, -step)
moveRect(cells[j], step, step)
} else if (overlapping_corner == 3) {
moveRect(cells[i], step, -step)
moveRect(cells[j], -step, step)
}
overlap = true
break
}
}
}
drawCells(cells)
await sleep(1000/144)
}
return cells
}
function sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function drawCells (cells) {
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, canvas.width, canvas.height)
for (let i = 0; i < cells.length; i++) {
drawCell(cells[i], ctx)
}
}
function inBounds (w, h, cell) {
if (
cell.rect[0].x > w
|| cell.rect[2].x < 0
|| cell.rect[0].y < 0
|| cell.rect[2].y > h
) {
return false
}
return true
}
async function main () {
const canvas = document.getElementById('canvas')
canvas.width = canvas.getBoundingClientRect().width
canvas.height = canvas.getBoundingClientRect().height
c = []
while (true) {
c = await generate(100, canvas.width/2, canvas.height/2, c)
c = c.filter(inBounds.bind(null, canvas.width, canvas.height))
rooms = []
for (let i = 0; i < c.length; i++) {
const area = (c[i].rect[0].x-c[i].rect[2].x)*(c[i].rect[0].y-c[i].rect[2].y)
console.log(area)
if (Math.abs(area) > max_rect_width*max_rect_width/1024) {
rooms.push(c[i])
}
}
c = rooms
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment