From eaa2c78d8cb25eaa3079428a4150fd23a6792092 Mon Sep 17 00:00:00 2001 From: klangner Date: Mon, 14 Sep 2020 22:54:39 +0200 Subject: [PATCH] Implemented simple rooms. Fixed #14 --- demo/src/lib.rs | 2 + docs/0.bootstrap.js | 12 +++--- docs/bbf7fe2631d06e11148e.module.wasm | Bin 0 -> 61539 bytes docs/bootstrap.js | 11 +---- docs/index.html | 49 +++++++++++++++++++++-- src/common/geometry.rs | 9 ++++- src/dungeon/map.rs | 53 +++++++++++++++++++++++-- src/dungeon/mod.rs | 1 + src/dungeon/random_rooms.rs | 10 +---- src/dungeon/rooms_corridors_nearest.rs | 47 ++++++++++++++++++++++ 10 files changed, 162 insertions(+), 32 deletions(-) create mode 100644 docs/bbf7fe2631d06e11148e.module.wasm create mode 100644 src/dungeon/rooms_corridors_nearest.rs diff --git a/demo/src/lib.rs b/demo/src/lib.rs index be8e1bd..00f8817 100644 --- a/demo/src/lib.rs +++ b/demo/src/lib.rs @@ -8,6 +8,7 @@ use mapgen::dungeon::{ starting_point::{AreaStartingPosition, XStart, YStart}, cull_unreachable::CullUnreachable, distant_exit::DistantExit, + rooms_corridors_nearest::NearestCorridors, }; @@ -47,6 +48,7 @@ impl World { pub fn new_random_rooms(width: u32, height: u32, seed: u32) -> World { let mut rng = StdRng::seed_from_u64(seed as u64); let map = MapBuilder::new(Box::new(RandomRoomsGen::new())) + .with(NearestCorridors::new()) .build_map_with_rng(width as usize, height as usize, &mut rng); let tiles = (0..map.tiles.len()) .map(|i| if map.tiles[i] == TileType::Floor {Cell::Floor} else {Cell::Wall}) diff --git a/docs/0.bootstrap.js b/docs/0.bootstrap.js index e0ae0ba..18d39ea 100644 --- a/docs/0.bootstrap.js +++ b/docs/0.bootstrap.js @@ -4,11 +4,11 @@ /*!*****************************!*\ !*** ../pkg/mapgen_demo.js ***! \*****************************/ -/*! exports provided: World, __wbindgen_object_drop_ref, __wbg_getTime_29addd71c7089c47, __wbg_new0_a3af66503e735141, __wbindgen_throw */ +/*! exports provided: Cell, World, __wbindgen_throw */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./mapgen_demo_bg.wasm */ \"../pkg/mapgen_demo_bg.wasm\");\n/* harmony import */ var _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./mapgen_demo_bg.js */ \"../pkg/mapgen_demo_bg.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"World\", function() { return _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"World\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_object_drop_ref\", function() { return _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbindgen_object_drop_ref\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbg_getTime_29addd71c7089c47\", function() { return _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_getTime_29addd71c7089c47\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbg_new0_a3af66503e735141\", function() { return _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbg_new0_a3af66503e735141\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_throw\", function() { return _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbindgen_throw\"]; });\n\n\n\n\n//# sourceURL=webpack:///../pkg/mapgen_demo.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./mapgen_demo_bg.wasm */ \"../pkg/mapgen_demo_bg.wasm\");\n/* harmony import */ var _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./mapgen_demo_bg.js */ \"../pkg/mapgen_demo_bg.js\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"Cell\", function() { return _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"Cell\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"World\", function() { return _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"World\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_throw\", function() { return _mapgen_demo_bg_js__WEBPACK_IMPORTED_MODULE_1__[\"__wbindgen_throw\"]; });\n\n\n\n\n//# sourceURL=webpack:///../pkg/mapgen_demo.js?"); /***/ }), @@ -16,11 +16,11 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _map /*!********************************!*\ !*** ../pkg/mapgen_demo_bg.js ***! \********************************/ -/*! exports provided: World, __wbindgen_object_drop_ref, __wbg_getTime_29addd71c7089c47, __wbg_new0_a3af66503e735141, __wbindgen_throw */ +/*! exports provided: Cell, World, __wbindgen_throw */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* WEBPACK VAR INJECTION */(function(module) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"World\", function() { return World; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_object_drop_ref\", function() { return __wbindgen_object_drop_ref; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbg_getTime_29addd71c7089c47\", function() { return __wbg_getTime_29addd71c7089c47; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbg_new0_a3af66503e735141\", function() { return __wbg_new0_a3af66503e735141; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_throw\", function() { return __wbindgen_throw; });\n/* harmony import */ var _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./mapgen_demo_bg.wasm */ \"../pkg/mapgen_demo_bg.wasm\");\n\n\nconst heap = new Array(32).fill(undefined);\n\nheap.push(undefined, null, true, false);\n\nfunction getObject(idx) { return heap[idx]; }\n\nlet heap_next = heap.length;\n\nfunction dropObject(idx) {\n if (idx < 36) return;\n heap[idx] = heap_next;\n heap_next = idx;\n}\n\nfunction takeObject(idx) {\n const ret = getObject(idx);\n dropObject(idx);\n return ret;\n}\n\nconst lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder;\n\nlet cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true });\n\ncachedTextDecoder.decode();\n\nlet cachegetUint8Memory0 = null;\nfunction getUint8Memory0() {\n if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"memory\"].buffer) {\n cachegetUint8Memory0 = new Uint8Array(_mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"memory\"].buffer);\n }\n return cachegetUint8Memory0;\n}\n\nfunction getStringFromWasm0(ptr, len) {\n return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));\n}\n\nfunction addHeapObject(obj) {\n if (heap_next === heap.length) heap.push(heap.length + 1);\n const idx = heap_next;\n heap_next = heap[idx];\n\n heap[idx] = obj;\n return idx;\n}\n/**\n*/\nclass World {\n\n static __wrap(ptr) {\n const obj = Object.create(World.prototype);\n obj.ptr = ptr;\n\n return obj;\n }\n\n free() {\n const ptr = this.ptr;\n this.ptr = 0;\n\n _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"__wbg_world_free\"](ptr);\n }\n /**\n * @param {number} width\n * @param {number} height\n * @returns {World}\n */\n static new(width, height) {\n var ret = _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"world_new\"](width, height);\n return World.__wrap(ret);\n }\n /**\n * @returns {number}\n */\n width() {\n var ret = _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"world_width\"](this.ptr);\n return ret >>> 0;\n }\n /**\n * @returns {number}\n */\n height() {\n var ret = _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"world_height\"](this.ptr);\n return ret >>> 0;\n }\n /**\n * @returns {number}\n */\n tiles() {\n var ret = _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"world_tiles\"](this.ptr);\n return ret;\n }\n}\n\nconst __wbindgen_object_drop_ref = function(arg0) {\n takeObject(arg0);\n};\n\nconst __wbg_getTime_29addd71c7089c47 = function(arg0) {\n var ret = getObject(arg0).getTime();\n return ret;\n};\n\nconst __wbg_new0_a3af66503e735141 = function() {\n var ret = new Date();\n return addHeapObject(ret);\n};\n\nconst __wbindgen_throw = function(arg0, arg1) {\n throw new Error(getStringFromWasm0(arg0, arg1));\n};\n\n\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../www/node_modules/webpack/buildin/harmony-module.js */ \"./node_modules/webpack/buildin/harmony-module.js\")(module)))\n\n//# sourceURL=webpack:///../pkg/mapgen_demo_bg.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* WEBPACK VAR INJECTION */(function(module) {/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Cell\", function() { return Cell; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"World\", function() { return World; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"__wbindgen_throw\", function() { return __wbindgen_throw; });\n/* harmony import */ var _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./mapgen_demo_bg.wasm */ \"../pkg/mapgen_demo_bg.wasm\");\n\n\nconst lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder;\n\nlet cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true });\n\ncachedTextDecoder.decode();\n\nlet cachegetUint8Memory0 = null;\nfunction getUint8Memory0() {\n if (cachegetUint8Memory0 === null || cachegetUint8Memory0.buffer !== _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"memory\"].buffer) {\n cachegetUint8Memory0 = new Uint8Array(_mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"memory\"].buffer);\n }\n return cachegetUint8Memory0;\n}\n\nfunction getStringFromWasm0(ptr, len) {\n return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));\n}\n/**\n*/\nconst Cell = Object.freeze({ Floor:0,\"0\":\"Floor\",Wall:1,\"1\":\"Wall\", });\n/**\n*/\nclass World {\n\n static __wrap(ptr) {\n const obj = Object.create(World.prototype);\n obj.ptr = ptr;\n\n return obj;\n }\n\n free() {\n const ptr = this.ptr;\n this.ptr = 0;\n\n _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"__wbg_world_free\"](ptr);\n }\n /**\n * @param {number} width\n * @param {number} height\n * @param {number} seed\n * @returns {World}\n */\n static new_cellular_automata(width, height, seed) {\n var ret = _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"world_new_cellular_automata\"](width, height, seed);\n return World.__wrap(ret);\n }\n /**\n * @param {number} width\n * @param {number} height\n * @param {number} seed\n * @returns {World}\n */\n static new_random_rooms(width, height, seed) {\n var ret = _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"world_new_random_rooms\"](width, height, seed);\n return World.__wrap(ret);\n }\n /**\n * @returns {number}\n */\n width() {\n var ret = _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"world_width\"](this.ptr);\n return ret >>> 0;\n }\n /**\n * @returns {number}\n */\n height() {\n var ret = _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"world_height\"](this.ptr);\n return ret >>> 0;\n }\n /**\n * @returns {number}\n */\n tiles() {\n var ret = _mapgen_demo_bg_wasm__WEBPACK_IMPORTED_MODULE_0__[\"world_tiles\"](this.ptr);\n return ret;\n }\n}\n\nconst __wbindgen_throw = function(arg0, arg1) {\n throw new Error(getStringFromWasm0(arg0, arg1));\n};\n\n\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../www/node_modules/webpack/buildin/harmony-module.js */ \"./node_modules/webpack/buildin/harmony-module.js\")(module)))\n\n//# sourceURL=webpack:///../pkg/mapgen_demo_bg.js?"); /***/ }), @@ -28,7 +28,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* WEBPACK VAR INJECTION */(f /*!**********************************!*\ !*** ../pkg/mapgen_demo_bg.wasm ***! \**********************************/ -/*! exports provided: memory, __wbg_world_free, world_new, world_width, world_height, world_tiles */ +/*! exports provided: memory, __wbg_world_free, world_new_cellular_automata, world_new_random_rooms, world_width, world_height, world_tiles */ /***/ (function(module, exports, __webpack_require__) { eval("\"use strict\";\n// Instantiate WebAssembly module\nvar wasmExports = __webpack_require__.w[module.i];\n__webpack_require__.r(exports);\n// export exports from WebAssembly module\nfor(var name in wasmExports) if(name != \"__webpack_init__\") exports[name] = wasmExports[name];\n// exec imports from WebAssembly module (for esm order)\n/* harmony import */ var m0 = __webpack_require__(/*! ./mapgen_demo_bg.js */ \"../pkg/mapgen_demo_bg.js\");\n\n\n// exec wasm module\nwasmExports[\"__webpack_init__\"]()\n\n//# sourceURL=webpack:///../pkg/mapgen_demo_bg.wasm?"); @@ -43,7 +43,7 @@ eval("\"use strict\";\n// Instantiate WebAssembly module\nvar wasmExports = __we /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var mapgen_demo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! mapgen-demo */ \"../pkg/mapgen_demo.js\");\n/* harmony import */ var mapgen_demo_mapgen_demo_bg__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! mapgen-demo/mapgen_demo_bg */ \"../pkg/mapgen_demo_bg.wasm\");\n\n\n\nconst CELL_SIZE = 12;\nconst GRID_COLOR = \"#CCCCCC\";\nconst DEAD_COLOR = \"#FFFFFF\";\nconst ALIVE_COLOR = \"#000000\";\n\nconst world = mapgen_demo__WEBPACK_IMPORTED_MODULE_0__[\"World\"].new(80, 50);\nconst width = world.width();\nconst height = world.height();\n\n// Give the canvas room for all of our cells and a 1px border\n// around each of them.\nconst canvas = document.getElementById(\"mapgen-canvas\");\ncanvas.height = (CELL_SIZE + 1) * height + 1;\ncanvas.width = (CELL_SIZE + 1) * width + 1;\n\nconst ctx = canvas.getContext('2d');\n\nconst renderLoop = () => {\n // universe.tick();\n\n drawGrid();\n drawCells();\n\n requestAnimationFrame(renderLoop);\n};\n\nconst drawGrid = () => {\n ctx.beginPath();\n ctx.strokeStyle = GRID_COLOR;\n\n // Vertical lines.\n for (let i = 0; i <= width; i++) {\n ctx.moveTo(i * (CELL_SIZE + 1) + 1, 0);\n ctx.lineTo(i * (CELL_SIZE + 1) + 1, (CELL_SIZE + 1) * height + 1);\n }\n\n // Horizontal lines.\n for (let j = 0; j <= height; j++) {\n ctx.moveTo(0, j * (CELL_SIZE + 1) + 1);\n ctx.lineTo((CELL_SIZE + 1) * width + 1, j * (CELL_SIZE + 1) + 1);\n }\n\n ctx.stroke();\n};\n\nconst getIndex = (row, column) => {\n return row * width + column;\n};\n\nconst drawCells = () => {\n const tilesPtr = world.tiles();\n const tiles = new Uint8Array(mapgen_demo_mapgen_demo_bg__WEBPACK_IMPORTED_MODULE_1__[\"memory\"].buffer, tilesPtr, width * height);\n\n ctx.beginPath();\n\n for (let row = 0; row < height; row++) {\n for (let col = 0; col < width; col++) {\n const idx = getIndex(row, col);\n\n ctx.fillStyle = tiles[idx]\n ? DEAD_COLOR\n : ALIVE_COLOR;\n\n ctx.fillRect(\n col * (CELL_SIZE + 1) + 1,\n row * (CELL_SIZE + 1) + 1,\n CELL_SIZE,\n CELL_SIZE\n );\n }\n }\n\n ctx.stroke();\n};\n\ndrawGrid();\ndrawCells();\nrequestAnimationFrame(renderLoop);\n\n//# sourceURL=webpack:///./index.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var mapgen_demo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! mapgen-demo */ \"../pkg/mapgen_demo.js\");\n/* harmony import */ var mapgen_demo_mapgen_demo_bg__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! mapgen-demo/mapgen_demo_bg */ \"../pkg/mapgen_demo_bg.wasm\");\n\n\n\nconst CELL_SIZE = 12;\nconst GRID_COLOR = \"#CCCCCC\";\nconst DEAD_COLOR = \"#FFFFFF\";\nconst ALIVE_COLOR = \"#000000\";\n\nvar world = null;\nconst width = 80;\nconst height = 50;\n\nconst infoDiv = document.getElementById('map-info');\n// Give the canvas room for all of our cells and a 1px border\n// around each of them.\nconst canvas = document.getElementById(\"mapgen-canvas\");\ncanvas.height = (CELL_SIZE + 1) * height + 1;\ncanvas.width = (CELL_SIZE + 1) * width + 1;\n\nconst ctx = canvas.getContext('2d');\n\n// Map generators\nfunction newCellularAutomata() {\n var seed = Date.now();\n world = mapgen_demo__WEBPACK_IMPORTED_MODULE_0__[\"World\"].new_cellular_automata(width, height, seed);\n requestAnimationFrame(renderLoop);\n infoDiv.textContent = \"Cellular Automata with the seed: \" + seed;\n}\n\nfunction newSimpleRooms() {\n var seed = Date.now();\n world = mapgen_demo__WEBPACK_IMPORTED_MODULE_0__[\"World\"].new_random_rooms(width, height, seed);\n requestAnimationFrame(renderLoop);\n infoDiv.textContent = \"Random Rooms with the seed: \" + seed;\n}\n\nconst renderLoop = () => {\n // universe.tick();\n\n drawGrid();\n drawCells();\n\n requestAnimationFrame(renderLoop);\n};\n\nconst drawGrid = () => {\n ctx.beginPath();\n ctx.strokeStyle = GRID_COLOR;\n\n // Vertical lines.\n for (let i = 0; i <= width; i++) {\n ctx.moveTo(i * (CELL_SIZE + 1) + 1, 0);\n ctx.lineTo(i * (CELL_SIZE + 1) + 1, (CELL_SIZE + 1) * height + 1);\n }\n\n // Horizontal lines.\n for (let j = 0; j <= height; j++) {\n ctx.moveTo(0, j * (CELL_SIZE + 1) + 1);\n ctx.lineTo((CELL_SIZE + 1) * width + 1, j * (CELL_SIZE + 1) + 1);\n }\n\n ctx.stroke();\n};\n\nconst getIndex = (row, column) => {\n return row * width + column;\n};\n\nconst drawCells = () => {\n const tilesPtr = world.tiles();\n const tiles = new Uint8Array(mapgen_demo_mapgen_demo_bg__WEBPACK_IMPORTED_MODULE_1__[\"memory\"].buffer, tilesPtr, width * height);\n\n ctx.beginPath();\n\n for (let row = 0; row < height; row++) {\n for (let col = 0; col < width; col++) {\n const idx = getIndex(row, col);\n\n ctx.fillStyle = tiles[idx] == mapgen_demo__WEBPACK_IMPORTED_MODULE_0__[\"Cell\"].Floor\n ? DEAD_COLOR\n : ALIVE_COLOR;\n\n ctx.fillRect(\n col * (CELL_SIZE + 1) + 1,\n row * (CELL_SIZE + 1) + 1,\n CELL_SIZE,\n CELL_SIZE\n );\n }\n }\n\n ctx.stroke();\n};\n\nnewCellularAutomata();\n\n// Connect UI element\ndocument.getElementById('cellular-automata-option').addEventListener('click', newCellularAutomata);\ndocument.getElementById('simple-rooms-option').addEventListener('click', newSimpleRooms);\n\n\n//# sourceURL=webpack:///./index.js?"); /***/ }), diff --git a/docs/bbf7fe2631d06e11148e.module.wasm b/docs/bbf7fe2631d06e11148e.module.wasm new file mode 100644 index 0000000000000000000000000000000000000000..9582c05dbf0cc57b280d9bec0e427af68894d02f GIT binary patch literal 61539 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 Mapgen demo + + + -

Mapgen demo

+
+ - - +
+ + + + diff --git a/src/common/geometry.rs b/src/common/geometry.rs index 9895121..57d8715 100644 --- a/src/common/geometry.rs +++ b/src/common/geometry.rs @@ -14,6 +14,11 @@ impl Point { Point {x, y} } + /// Create new point from i32 coords + pub fn new_i32(x: i32, y: i32) -> Point { + Point::new(x as usize, y as usize) + } + /// Euclidean distance to a given point pub fn distance_to(self, point: &Point) -> f32 { let a = (self.x as f32 - point.x as f32).powf(2.0); @@ -41,8 +46,8 @@ impl Rect { self.x1 <= other.x2 && self.x2 >= other.x1 && self.y1 <= other.y2 && self.y2 >= other.y1 } - pub fn center(&self) -> (i32, i32) { - ((self.x1 + self.x2)/2, (self.y1 + self.y2)/2) + pub fn center(&self) -> Point { + Point::new_i32((self.x1 + self.x2)/2, (self.y1 + self.y2)/2) } } diff --git a/src/dungeon/map.rs b/src/dungeon/map.rs index e0830fc..415fcaf 100644 --- a/src/dungeon/map.rs +++ b/src/dungeon/map.rs @@ -23,7 +23,9 @@ pub struct Map { pub width : usize, pub height : usize, pub starting_point: Option, - pub exit_point: Option + pub exit_point: Option, + pub rooms: Vec, + pub corridors: Vec>, } impl Map { @@ -37,6 +39,8 @@ impl Map { height, starting_point: None, exit_point: None, + rooms: Vec::new(), + corridors: Vec::new() } } @@ -105,12 +109,36 @@ impl Map { /// Create room on the map at given location /// Room is created by setting all tiles in the room to the Floor - pub fn create_room(&mut self, rect: &Rect) { + pub fn add_room(&mut self, rect: Rect) { for x in rect.x1..rect.x2 { for y in rect.y1..rect.y2 { self.set_tile(x as usize, y as usize, TileType::Floor); } } + self.rooms.push(rect); + } + + pub fn add_corridor(&mut self, from: Point, to:Point) { + let mut corridor = Vec::new(); + let mut x = from.x; + let mut y = from.y; + + while x != to.x || y != to.y { + if x < to.x { + x += 1; + } else if x > to.x { + x -= 1; + } else if y < to.y { + y += 1; + } else if y > to.y { + y -= 1; + } + + if self.at(x, y) != TileType::Floor { + corridor.push(Point::new(x, y)); + self.set_tile(x, y, TileType::Floor); + } + } } } @@ -183,7 +211,7 @@ mod tests { #[test] fn test_create_room() { let mut map = Map::new(5, 5); - map.create_room(&Rect::new(1, 1, 3, 3)); + map.add_room(Rect::new(1, 1, 3, 3)); for x in 0..map.width { for y in 0..map.height { if x == 0 || y == 0 || x == 4 || y == 4 { @@ -195,4 +223,23 @@ mod tests { } } + #[test] + fn test_add_corridor() { + let map_str = " + ########## + # # # + ########## + "; + let mut map = Map::from_string(map_str); + let expected_map_str = " + ########## + # # + ########## + "; + let expected_map = Map::from_string(expected_map_str); + + map.add_corridor(Point::new(1, 1), Point::new(8, 1)); + + assert_eq!(map.tiles, expected_map.tiles); + } } \ No newline at end of file diff --git a/src/dungeon/mod.rs b/src/dungeon/mod.rs index b834d88..96ca7a1 100644 --- a/src/dungeon/mod.rs +++ b/src/dungeon/mod.rs @@ -31,6 +31,7 @@ pub mod cellular_automata; pub mod cull_unreachable; pub mod distant_exit; pub mod random_rooms; +pub mod rooms_corridors_nearest; pub mod starting_point; mod dijkstra; diff --git a/src/dungeon/random_rooms.rs b/src/dungeon/random_rooms.rs index 65dc527..0b0e84d 100644 --- a/src/dungeon/random_rooms.rs +++ b/src/dungeon/random_rooms.rs @@ -50,7 +50,6 @@ impl RandomRoomsGen { fn build_rooms(&self, width: usize, height: usize, rng : &mut StdRng) -> Map { let mut map = Map::new(width, height); - let mut rooms : Vec = Vec::new(); // Create room dimensions for _ in 0..self.max_rooms { @@ -59,16 +58,11 @@ impl RandomRoomsGen { let x = random::random_range(rng, 1, width - w); let y = random::random_range(rng, 1, height - h); let new_room = Rect::new(x as i32, y as i32, w as i32, h as i32); - let intersects = rooms.iter().any(|r| new_room.intersect(r)); + let intersects = map.rooms.iter().any(|r| new_room.intersect(r)); if !intersects { - rooms.push(new_room); + map.add_room(new_room); } } - - // Apply rooms to the map - for room in rooms { - map.create_room(&room); - } map } diff --git a/src/dungeon/rooms_corridors_nearest.rs b/src/dungeon/rooms_corridors_nearest.rs new file mode 100644 index 0000000..abdaa46 --- /dev/null +++ b/src/dungeon/rooms_corridors_nearest.rs @@ -0,0 +1,47 @@ +//! Connect nearest rooms on the map with corridors +//! +use rand::prelude::StdRng; +use super::MapModifier; +use super::map::Map; +use std::collections::HashSet; + + +pub struct NearestCorridors {} + +impl MapModifier for NearestCorridors { + fn modify_map(&self, _: &mut StdRng, map: &Map) -> Map { + self.corridors(map) + } +} + +impl NearestCorridors { + + pub fn new() -> Box { + Box::new(NearestCorridors{}) + } + + fn corridors(&self, map: &Map) -> Map { + let mut new_map = map.clone(); + + let mut connected : HashSet = HashSet::new(); + for (i,room) in map.rooms.iter().enumerate() { + let mut room_distance : Vec<(usize, f32)> = Vec::new(); + let room_center = room.center(); + for (j,other_room) in new_map.rooms.iter().enumerate() { + if i != j && !connected.contains(&j) { + let other_center = other_room.center(); + let distance = room_center.distance_to(&other_center); + room_distance.push((j, distance)); + } + } + + if !room_distance.is_empty() { + room_distance.sort_by(|a,b| a.1.partial_cmp(&b.1).unwrap() ); + let dest_center = new_map.rooms[room_distance[0].0].center(); + new_map.add_corridor(room_center, dest_center); + connected.insert(i); + } + } + new_map + } +} \ No newline at end of file