Door placement

This commit is contained in:
2023-09-21 19:29:34 -07:00
parent 01e316d979
commit 354a114e1c
10 changed files with 239 additions and 19 deletions

View File

@ -2,6 +2,7 @@ import 'dart:math' as math;
import 'package:dartterm/algorithms/geometry.dart' as geo;
import 'package:dartterm/algorithms/regionalize.dart';
import 'package:dartterm/algorithms/kruskal.dart';
import 'package:dartterm/bitmap.dart';
import 'package:dartterm/skreek.dart';
@ -222,7 +223,7 @@ class Generator {
Vault _fillMetaRegions(Requirement requirement, Vault vault) {
var geo.Size(:dx, :dy) = vault.size;
var metaregions = regionalize(geo.Rect(0, 0, dx, dy),
var (metaregions, _) = regionalize(geo.Rect(0, 0, dx, dy),
(x, y) => vault.tiles.get(x, y) == VaultTile.meta0);
for (var i in metaregions) {
@ -249,22 +250,25 @@ class Generator {
Vault _finalize(Vault subj) {
var vx = subj.vx, vy = subj.vy;
subj = Vault.blankWith(vx, vy, (x, y) {
var bed = VaultTile.defaultwall;
if (x == 0 || x == vx - 1 || y == 0 || y == vy - 1) {
bed = VaultTile.wall;
}
var tile = mergeVaultTile(bed, subj.tiles.get(x, y)!);
return tile;
}, subj.smooth.clone());
bool canSupportArch(VaultTile? tile) {
var orthoOffsets = [(0, -1), (0, 1), (-1, 0), (1, 0)];
// == build arches ==
bool floorlike(VaultTile? tile) {
return tile == VaultTile.bspfloor ||
tile == VaultTile.floor ||
tile == VaultTile.doorpronefloor ||
tile == VaultTile.exit;
}
var orthoOffsets = [(0, -1), (0, 1), (-1, 0), (1, 0)];
bool walkable(VaultTile? tile) {
return tile == VaultTile.bspfloor ||
tile == VaultTile.floor ||
tile == VaultTile.doorpronefloor ||
tile == VaultTile.exit ||
tile == VaultTile.door;
}
List<(int, int)> newArches = [];
for (int x = 0; x < vx; x++) {
for (int y = 0; y < vy; y++) {
@ -273,7 +277,7 @@ class Generator {
var supporters = 0;
for (var (dx, dy) in orthoOffsets) {
VaultTile? neighbor = subj.tiles.get(x + dx, y + dy);
if (canSupportArch(neighbor)) {
if (floorlike(neighbor)) {
supporters++;
}
}
@ -292,6 +296,88 @@ class Generator {
for (var (ax, ay) in newArches) {
subj.tiles.set(ax, ay, VaultTile.floor);
}
// == build doors ==
var (regions, toRegion) =
regionalize(geo.Rect(0, 0, subj.vx, subj.vy), (x, y) {
return walkable(subj.tiles.get(x, y));
});
double doorPoints(int x, int y) {
return subj.tiles.get(x, y) == VaultTile.doorpronefloor ? 0.5 : 0.0;
}
//
List<Edge<(int, int)>> possibleDoors = [];
for (var x = 0; x < subj.vx; x++) {
for (var y = 0; y < subj.vy; y++) {
double points;
int region0, region1;
if (subj.tiles.get(x, y) != VaultTile.wall) {
continue;
}
var regionL = toRegion[(x - 1, y)];
var regionR = toRegion[(x + 1, y)];
var regionU = toRegion[(x, y - 1)];
var regionD = toRegion[(x, y + 1)];
if (regionL != null &&
regionR != null &&
regionU == null &&
regionD == null) {
(region0, region1) = (regionL, regionR);
points = doorPoints(x - 1, y) + doorPoints(x + 1, y);
} else if (regionL == null &&
regionR == null &&
regionU != null &&
regionD != null) {
(region0, region1) = (regionU, regionD);
points = doorPoints(x, y - 1) + doorPoints(x, y + 1);
} else {
continue;
}
if (region0 == region1) {
continue;
}
int roomSize = math.min(
regions[region0].points.length,
regions[region1].points.length,
);
possibleDoors.add(Edge(region0, region1, (x, y),
doorScore(points, roomSize, _random.nextDouble())));
}
}
var minimalDoors = kruskal(regions.length, possibleDoors);
for (var d in minimalDoors) {
var (x, y) = d.value;
subj.tiles.set(x, y, VaultTile.door);
}
for (var x = 0; x < subj.vx; x++) {
for (var y = 0; y < subj.vy; y++) {
if (subj.tiles.get(x, y) == VaultTile.doorpronefloor) {
subj.tiles.set(x, y, VaultTile.floor);
}
}
}
return subj;
}
}
// components:
// - points for placement
// - size of the underlying room
// - random factor
double doorScore(double pointsForPlacement, int roomSize, double randomFactor) {
assert(pointsForPlacement >= 0.0 && pointsForPlacement <= 1.0);
assert(roomSize >= 0 && roomSize < 100000);
assert(randomFactor >= 0.0 && randomFactor < 1.0);
return pointsForPlacement * 100000 +
(100000 - roomSize).toDouble() +
randomFactor;
}

View File

@ -14,7 +14,8 @@ class Vaults {
static Future<Vaults> load(String name) async {
var basis = await Bitmap.load(name, colorToVaultTile);
var regions = regionalize(basis.rect, (x, y) => basis.get(x, y) != null);
var (regions, _) =
regionalize(basis.rect, (x, y) => basis.get(x, y) != null);
var vs = Vaults();
@ -73,6 +74,8 @@ enum VaultTile {
door,
bspfloor,
floor,
doorpronefloor,
defaultwall, // defaultwall is in generated rooms and is overwritten by anything
archpronewall, // archpronewall cannot overwrite wall or archwall
archwall, // archwall cannot overwrite wall.
@ -98,6 +101,8 @@ VaultTile? colorToVaultTile(int c) {
return VaultTile.archwall;
case 0x7F4000:
return VaultTile.archpronewall;
case 0xBCCFFF:
return VaultTile.doorpronefloor;
case 0xFFFFFF:
case 0xFFFF00:
case 0xFF00FF: