Skip to content

Instantly share code, notes, and snippets.

Created January 16, 2015 10:16
Show Gist options
  • Save anonymous/1a4a447f4750f3847b60 to your computer and use it in GitHub Desktop.
Save anonymous/1a4a447f4750f3847b60 to your computer and use it in GitHub Desktop.
Dungeon on a Canvas
{
"origin": "dartlab.org",
"url": "http://dartlab.org/#:gistId",
"history": [
"1dec995218ffb0e27cd2"
]
}
<div style="background-color:#FFFFFF;margin:5px;position:absolute;left:5px;width:900px;height:70px; border: 2px solid black; border-radius: 15px;">
<form style="font-size:10pt;">
<div style="position:absolute;top:20px;width:140px;left:10px;">Map Width
<input type="range" min="20" max="200" id="MapWidth" value="45" />
</div>
<div style="position:absolute;top:20px;width:130px;left:150px;">Map Height
<input type="range" min="20" max="100" id="MapHeight" value="40" />
</div>
<div style="position:absolute;top:20px;left:300px;width:150px;">Max Room Width
<input type="range" min="5" max="20" id="RoomWidth" value="8" />
</div>
<div style="position:absolute;top:20px;left:450px;width:140px;">Max Room Height
<input type="range" min="5" max="20" id="RoomHeight" value="8" />
</div>
<div style="position:absolute;top:20px;left:600px;width:140px;">Room Count
<input type="range" min="1" max="50" id="RoomCount" value="8" />
</div>
<div style="position:absolute;top:20px;left:750px;width:140px;">Zoom
<input type="range" min="1" max="8" id="ZoomLevel" value="2" />
</div>
<div style="position:absolute;top:90px;left:10px;width:140px;">
<input type="button" id="RefreshButton" value="Refresh" style="width:120px;"/>
</div>
</form>
</div>
<canvas id="surface" style="color:#000088;position:absolute;top:130px;padding: 3px 5px; border: 3px double silver;background: #008800;">
</canvas>
// Copyright (c) 2015, Davy Mitchell. All rights reserved. Use of this source code
// is governed by a BSD-style license that can be found in the LICENSE file.
import 'dart:html';
import 'dart:async';
import 'dart:math';
InputElement mapWidthRange;
InputElement mapHeightRange;
InputElement roomwidthRange;
InputElement roomheightRange;
InputElement roomCountRange;
InputElement zoomRange;
InputElement refreshButton;
CanvasElement visualMap;
CanvasRenderingContext2D ctx2d;
void main() {
mapWidthRange = querySelector('#MapWidth')..onChange.listen(remakeMap);
mapHeightRange = querySelector('#MapHeight')..onChange.listen(remakeMap);
roomwidthRange = querySelector('#RoomWidth')..onChange.listen(remakeMap);
roomheightRange = querySelector('#RoomHeight')..onChange.listen(remakeMap);
roomCountRange = querySelector('#RoomCount')..onClick.listen(remakeMap);
zoomRange = querySelector('#ZoomLevel')..onClick.listen(remakeMap);
refreshButton = querySelector('#RefreshButton')..onClick.listen(remakeMap);
Future.wait(LoadImages()).then((_) => makeMap());
}
void makeMap() {
int mapwidth = mapWidthRange.valueAsNumber.toInt();
int mapheight = mapHeightRange.valueAsNumber.toInt();
int roomwidth = roomwidthRange.valueAsNumber.toInt();
int roomheight = roomheightRange.valueAsNumber.toInt();
int roomcount = roomCountRange.valueAsNumber.toInt();
int zoomrange = zoomRange.valueAsNumber.toInt() * 8;
PGMap mymap = buildMap(mapwidth, mapheight, roomwidth, roomheight, roomcount);
visualMap = querySelector('#surface');
drawMap(visualMap, mymap, zoomrange);
}
void remakeMap(e) {
makeMap();
}
const int CORRIDOR = 1;
const int LEVELENTRYPOINT = 10;
const int LEVELEXITPOINT = 11;
const int ROOM = 3;
const int VOID = 0;
const int WALLCORNER = 8;
const int WALLE = 5;
const int WALLN = 7;
const int WALLS = 6;
const int WALLW = 4;
const int TREE = 9;
/// Block is the smallest unit of a map.
class Block {
int base = VOID;
Block(this.base);
}
/// Point Class.
class Point {
int x = 0;
int y = 0;
Point(this.x, this.y) {}
}
// Rectangle - defines a rectangular area on the map.
class MapRectangle {
int x = 0;
int y = 0;
int width = 0;
int height = 0;
int x2 = 0;
int y2 = 0;
MapRectangle(this.x, this.y, this.width, this.height) {
update2ndPoints();
}
Point getMidPoint() => (new Point(x + (width / 2).round(), y + (height / 2).round()));
void update2ndPoints() {
x2 = x + width;
y2 = y + height;
}
}
int RND(int maxv) {
maxv = max(1, maxv);
return new Random().nextInt(maxv);
}
class PGMap {
Map<String, Block> Blocks = new Map<String, Block>();
List<MapRectangle> Rooms = new List<MapRectangle>();
int RoomCount = 0;
int CorrCount = 0;
int Width = 0;
int Height = 0;
int MaxRoomWidth = 5;
int MaxRoomHeight = 8;
PGMap(this.Width, this.Height, int RoomWidth, int RoomHeight) {
MaxRoomWidth = RoomWidth;
MaxRoomHeight = RoomHeight;
if (RoomWidth > Width) {
RoomWidth = Width - 6;
}
if (RoomHeight > Height) {
RoomHeight = Height - 6;
}
}
void addCorridor(int x, int y, int d, int l) {
if (d == 3) {
for (int i = y; i < y + l + 1; i++) setBlock(x, i, CORRIDOR);
} else if (d == 1) {
for (int i = (y - l) + 1; i < y + 1; i++) setBlock(x, i, CORRIDOR);
} else if (d == 2) {
for (int i = x; i < (x + l - 1) + 1; i++) setBlock(i, y, CORRIDOR);
} else if (d == 4) {
for (int i = (x - l) + 1; i < x + 1; i++) setBlock(i, y, CORRIDOR);
}
CorrCount += 1;
}
void addRoom(int rx, int ry, int rw, int rh) {
for (int i = rx; i < (rw + rx - 1) + 1; i++) {
for (int j = ry; j < (rh + ry - 1); j++) setBlock(i, j, ROOM);
}
Rooms.add(new MapRectangle(rx, ry, rw, rh));
RoomCount += 1;
}
void addRoomRandom() {
int rw = 3 + RND(MaxRoomWidth - 3);
int rh = 3 + RND(MaxRoomHeight - 3);
int rx = 3 + RND(Width - (rw + 6));
int ry = 3 + RND(Height - (rh + 6));
addRoom(rx, ry, rw, rh);
}
void addRandomObject(int count, int ObjectID, [bool overwrite = false]) {
for (int rc = 0; rc < count; rc++) {
int rx = RND(Width);
int ry = RND(Height);
Block b = getBlock(rx, ry);
if (b.base == VOID) {
b.base = ObjectID;
}
}
}
void buildWall(Block currentTile, Block prevTile, Block nextTile, Block upTile, Block loTile) {
if (prevTile.base == VOID && (currentTile.base == ROOM || currentTile.base == CORRIDOR)) prevTile.base = WALLW;
if (currentTile.base == VOID) {
if (nextTile.base == ROOM || nextTile.base == CORRIDOR) currentTile.base = WALLW; else if (prevTile.base == ROOM || prevTile.base == CORRIDOR) currentTile.base = WALLE; else if (upTile.base == ROOM || upTile.base == CORRIDOR) currentTile.base = WALLS; else if (loTile.base == ROOM || loTile.base == CORRIDOR) currentTile.base = WALLN;
}
}
void buildWallCorners(Block currentTile, Block prevTile, Block nextTile, Block upTile, Block loTile) {
if (currentTile.base == VOID) {
if (isBlockWall(nextTile) && isBlockWall(loTile)) currentTile.base = WALLCORNER; else if (isBlockWall(nextTile) && isBlockWall(upTile)) currentTile.base = WALLCORNER; else if (isBlockWall(prevTile) && isBlockWall(loTile)) currentTile.base = WALLCORNER; else if (isBlockWall(prevTile) && isBlockWall(upTile)) currentTile.base = WALLCORNER;
}
}
void createCorridors() {
int P1, P2;
int Start, End;
MapRectangle S1, S2;
int X, Y;
int ln;
for (int ci = 0; ci < RoomCount - 1; ci++) {
S1 = Rooms[ci];
S2 = Rooms[ci + 1];
P1 = S1.getMidPoint().x;
P2 = S2.getMidPoint().x;
if (P1 > P2) {
Start = P2;
End = P1;
Y = S2.getMidPoint().y;
} else {
Start = P1;
End = P2;
Y = S1.getMidPoint().y;
}
addCorridor(Start, Y, 2, (End - Start) + 1);
ln = End - Start;
P1 = S1.getMidPoint().y;
P2 = S2.getMidPoint().y;
if (S1.getMidPoint().x > S2.getMidPoint().x) X = S1.getMidPoint().x; else X = S2.getMidPoint().x;
if (P1 > P2) {
Start = P2;
End = P1;
} else {
Start = P1;
End = P2;
}
addCorridor(X, Start, 3, (End - Start) + 1);
}
}
void createMap([int maxrooms = 4]) {
for (int i = 0; i < maxrooms; i++) addRoomRandom();
createCorridors();
createWalls();
}
void createWalls() {
traverseMap(buildWall);
traverseMap(buildWallCorners);
}
void generate() {
int base = VOID;
for (int x = 0; x < Width; x++) {
for (int y = 0; y < Height; y++) {
Blocks["$x-$y"] = new Block(base);
}
}
}
Block getBlock(x, y) {
return Blocks["$x-$y"];
}
bool isBlockFree(x, y) {
int blockType = getBlock(x, y).base;
return (blockType == ROOM || blockType == CORRIDOR);
}
bool isBlockWall(Block b) {
return b.base == WALLN || b.base == WALLS || b.base == WALLE || b.base == WALLW;
}
int setBlock(x, y, v, [AllowOverwrite = false]) {
try {
if (!AllowOverwrite && Blocks["$x-$y"].base != VOID) return 1;
Blocks["$x-$y"].base = v;
} catch (o, e) {
return -1;
}
return 0;
}
String show() {
String mapo = "";
for (int y = 0; y < Height; y++) {
for (int x = 0; x < Width; x++) {
if (Blocks["$x-$y"].base == VOID) mapo += " "; else if (isBlockWall(Blocks["$x-$y"])) mapo += "█"; else if (Blocks["$x-$y"].base == WALLCORNER) mapo += "₪"; else if (Blocks["$x-$y"].base == CORRIDOR) mapo += "░"; else if (Blocks["$x-$y"].base == ROOM) mapo += "░"; else mapo += "${Blocks["$x-$y"].base}";
}
mapo += "\r\n";
}
//print(mapo);
return mapo;
}
void traverseMap(processor) {
Block currentTile;
Block nextTile;
Block prevTile;
Block upTile;
Block loTile;
for (int x = 1; x < Width - 2; x++) {
for (int y = 1; y < Height - 2; y++) {
currentTile = Blocks["$x-$y"];
nextTile = Blocks["${x+1}-$y"];
prevTile = Blocks["${x-1}-$y"];
upTile = Blocks["$x-${y+1}"];
loTile = Blocks["$x-${y-1}"];
processor(currentTile, prevTile, nextTile, upTile, loTile);
}
}
}
}
ImageElement wall, grass, floor, corner, tree;
// Start Load of images and waits for them to complete.
LoadImages() {
var baseUrl = "https://cdn.rawgit.com/daftspaniel/dart-procgendungeon/master/parttwo/web/img";
wall = new ImageElement(src: "$baseUrl/stone.png");
grass = new ImageElement(src: "$baseUrl/grass.png");
floor = new ImageElement(src: "$baseUrl/floor.png");
corner = new ImageElement(src: "$baseUrl/corner.png");
tree = new ImageElement(src: "$baseUrl/ftree.png");
return [wall.onLoad.first, floor.onLoad.first, grass.onLoad.first, corner.onLoad.first, tree.onLoad.first];
}
void drawMap(CanvasElement ca, PGMap Amap, int tileSize) {
int width = Amap.Width;
int height = Amap.Height;
int tw = tileSize;
ca.width = width * tw;
ca.height = height * tw;
CanvasRenderingContext2D ctx = ca.getContext("2d");
ctx.imageSmoothingEnabled = false;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int c = Amap.getBlock(x, y).base;
if (c == WALLN || c == WALLS || c == WALLE || c == WALLW) {
ctx.drawImageScaled(wall, x * tw, y * tw, tw, tw);
} else if (c == WALLCORNER) {
ctx.drawImageScaled(corner, x * tw, y * tw, tw, tw);
} else if (c == TREE) {
ctx.drawImageScaled(grass, x * tw, y * tw, tw, tw);
ctx.drawImageScaled(tree, x * tw, (y * tw) - 4, tw, tw);
} else if (c == ROOM || c == CORRIDOR) {
ctx.drawImageScaled(floor, x * tw, y * tw, tw, tw);
} else {
ctx.drawImageScaled(grass, x * tw, y * tw, tw, tw);
}
}
}
}
PGMap buildMap(int mapwidth, int mapheight, int roomwidth, int roomheight, int roomcount) {
PGMap mymap = new PGMap(mapwidth, mapheight, roomwidth, roomheight);
mymap
..generate()
..createMap(roomcount)
..addRandomObject(roomcount * 3, TREE);
return mymap;
}
body {
font-family:sans-serif;font-size:7pt;
background-color:#111111;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment