Last active
March 24, 2026 02:42
-
-
Save brettchalupa/7a4899c12fbfe74ff16ae1dc5892eb0e to your computer and use it in GitHub Desktop.
Enigmata's map gen code from v0.1-dev; the code below is released into the public domain
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "map.h" | |
| #include "platform.h" | |
| #include "util.h" | |
| #include <string.h> | |
| static int pointToTileIndex(Map *map, Point p) { return p.y * map->width + p.x; } | |
| static void setTileAtPoint(Map *map, Point p, TileType type) { | |
| map->tiles[pointToTileIndex(map, p)] = type; | |
| } | |
| static void carveRooms(Map *map) { | |
| // carve out rooms | |
| for (int sectorY = 0; sectorY < SECTORS_V; sectorY++) { | |
| for (int sectorX = 0; sectorX < SECTORS_H; sectorX++) { | |
| // skip rooms 10% of the time | |
| if (percentChance(10)) | |
| continue; | |
| int roomW = randInRange(SECTOR_WIDTH - 6, SECTOR_WIDTH - 2); | |
| int roomH = randInRange(SECTOR_HEIGHT - 8, SECTOR_HEIGHT - 4); | |
| int roomX = randInRange(1, SECTOR_WIDTH - roomW - 1); | |
| int roomY = randInRange(1, SECTOR_HEIGHT - roomH - 1); | |
| int sectorOffsetX = sectorX * SECTOR_WIDTH; | |
| int sectorOffsetY = sectorY * SECTOR_HEIGHT; | |
| map->rooms[sectorY * SECTORS_H + sectorX] = (Room){ | |
| .pos = {.x = roomX + sectorOffsetX, .y = roomY + sectorOffsetY}, | |
| .w = roomW, | |
| .h = roomH, | |
| }; | |
| map->roomCount++; | |
| for (int y = roomY; y < roomH + roomY; y++) { | |
| for (int x = roomX; x < roomW + roomX; x++) { | |
| map->tiles[(sectorOffsetY + y) * map->width + (sectorOffsetX + x)] = kTileFloor; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| // carve horizontal from x1 to x2 at row y | |
| static void carveH(Map *map, int x1, int x2, int y) { | |
| int startX = x1 < x2 ? x1 : x2; | |
| int endX = x1 < x2 ? x2 : x1; | |
| for (int x = startX; x <= endX; x++) { | |
| setTileAtPoint(map, (Point){.x = x, .y = y}, kTileFloor); | |
| } | |
| } | |
| // carve vertical from y1 to y2 at column x | |
| static void carveV(Map *map, int x, int y1, int y2) { | |
| int startY = y1 < y2 ? y1 : y2; | |
| int endY = y1 < y2 ? y2 : y1; | |
| for (int y = startY; y <= endY; y++) { | |
| setTileAtPoint(map, (Point){.x = x, .y = y}, kTileFloor); | |
| } | |
| } | |
| static void carveCorridors(Map *map) { | |
| // connect each room to the next existing room to its right | |
| for (int sy = 0; sy < SECTORS_V; sy++) { | |
| for (int sx = 0; sx < SECTORS_H; sx++) { | |
| Room *a = &map->rooms[sy * SECTORS_H + sx]; | |
| if (a->w == 0) | |
| continue; | |
| for (int nx = sx + 1; nx < SECTORS_H; nx++) { | |
| Room *b = &map->rooms[sy * SECTORS_H + nx]; | |
| if (b->w == 0) | |
| continue; | |
| Point pa = roomRandomPoint(a); | |
| Point pb = roomRandomPoint(b); | |
| carveH(map, pa.x, pb.x, pa.y); | |
| carveV(map, pb.x, pa.y, pb.y); | |
| sx = nx - 1; | |
| break; | |
| } | |
| } | |
| } | |
| // connect each room to the next existing room below | |
| for (int sx = 0; sx < SECTORS_H; sx++) { | |
| for (int sy = 0; sy < SECTORS_V; sy++) { | |
| Room *a = &map->rooms[sy * SECTORS_H + sx]; | |
| if (a->w == 0) | |
| continue; | |
| for (int ny = sy + 1; ny < SECTORS_V; ny++) { | |
| Room *b = &map->rooms[ny * SECTORS_H + sx]; | |
| if (b->w == 0) | |
| continue; | |
| Point pa = roomRandomPoint(a); | |
| Point pb = roomRandomPoint(b); | |
| carveV(map, pa.x, pa.y, pb.y); | |
| carveH(map, pa.x, pb.x, pb.y); | |
| sy = ny - 1; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| void generateMap(Map *map) { | |
| map->roomCount = 0; | |
| memset(map->rooms, 0, sizeof(map->rooms)); | |
| map->width = MAX_MAP_WIDTH; | |
| map->height = MAX_MAP_HEIGHT; | |
| // fill with walls | |
| for (int i = 0; i < map->width * map->height; i++) { | |
| map->tiles[i] = kTileWall; | |
| } | |
| carveRooms(map); | |
| carveCorridors(map); | |
| } | |
| void drawMap(Map *map, Point camera, int cellSize) { | |
| int startTileX = camera.x / cellSize; | |
| int startTileY = camera.y / cellSize; | |
| int endTileX = (camera.x + screenWidth()) / cellSize + 1; | |
| int endTileY = (camera.y + screenHeight()) / cellSize + 1; | |
| if (startTileX < 0) | |
| startTileX = 0; | |
| if (startTileY < 0) | |
| startTileY = 0; | |
| if (endTileX >= map->width) | |
| endTileX = map->width - 1; | |
| if (endTileY >= map->height) | |
| endTileY = map->height - 1; | |
| for (int y = startTileY; y <= endTileY; y++) { | |
| for (int x = startTileX; x <= endTileX; x++) { | |
| int i = pointToIndex((Point){x, y}, map->width); | |
| int px = x * cellSize - camera.x; | |
| int py = y * cellSize - camera.y; | |
| drawTile(map->tiles[i], px, py, cellSize); | |
| } | |
| } | |
| } | |
| void setStairsAtPoint(Map *map, Point p) { setTileAtPoint(map, p, kTileStairsDown); } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef MAP_H | |
| #define MAP_H | |
| #include "point.h" | |
| #include "util.h" | |
| #define MAX_MAP_WIDTH 44 | |
| #define MAX_MAP_HEIGHT 33 | |
| #define SECTORS_H 4 | |
| #define SECTORS_V 3 | |
| #define SECTOR_WIDTH (MAX_MAP_WIDTH / SECTORS_H) | |
| #define SECTOR_HEIGHT (MAX_MAP_HEIGHT / SECTORS_V) | |
| typedef enum { | |
| kTileWall = 742, | |
| kTileFloor = 0, // empty | |
| kTileStairsDown = 297, | |
| } TileType; | |
| /** | |
| * A rectangular area within a sector of a map, with its position and width and | |
| * height in grid size, not pixel size. | |
| */ | |
| typedef struct { | |
| Point pos; | |
| int w; | |
| int h; | |
| } Room; | |
| /** | |
| * Generated floor that the player traverses | |
| */ | |
| typedef struct { | |
| int width; | |
| int height; | |
| TileType tiles[MAX_MAP_WIDTH * MAX_MAP_HEIGHT]; | |
| Room rooms[SECTORS_H * SECTORS_V]; | |
| int roomCount; | |
| } Map; | |
| static inline bool isInBounds(Point p, Map *map) { | |
| return p.x >= 0 && p.x < map->width && p.y >= 0 && p.y < map->height; | |
| } | |
| /** Return a random point in the room */ | |
| static inline Point roomRandomPoint(Room *room) { | |
| return (Point){ | |
| .x = room->pos.x + randInRange(0, room->w - 1), | |
| .y = room->pos.y + randInRange(0, room->h - 1), | |
| }; | |
| } | |
| /** Return a the center point of the room */ | |
| static inline Point roomCenter(Room *room) { | |
| return (Point){ | |
| .x = room->pos.x + room->w / 2, | |
| .y = room->pos.y + room->h / 2, | |
| }; | |
| } | |
| static inline bool isTileWalkable(TileType tile) { | |
| return tile == kTileFloor || tile == kTileStairsDown; | |
| } | |
| static inline TileType tileAtPos(Map *map, Point pos) { | |
| return map->tiles[pointToIndex(pos, map->width)]; | |
| } | |
| /** | |
| * Draw the map to the screen with the renderer, setting offset with the camera. | |
| * | |
| * @param cellSize pixel size of each grid cell (tiles are drawn at this size) | |
| */ | |
| void drawMap(Map *map, Point camera, int cellSize); | |
| void generateMap(Map *map); | |
| void setStairsAtPoint(Map *map, Point p); | |
| #endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include "raylib.h" | |
| #define RAYGUI_IMPLEMENTATION | |
| #include "../../../src/map.h" | |
| #include "../../../src/platform.h" | |
| #include "../../vendor/raygui.h" | |
| #include "raylib.h" | |
| #include <time.h> | |
| //------------------------------------------------------------------------------------ | |
| // Program main entry point | |
| //------------------------------------------------------------------------------------ | |
| int main(void) { | |
| // Initialization | |
| //-------------------------------------------------------------------------------------- | |
| SetConfigFlags(FLAG_WINDOW_RESIZABLE); | |
| InitWindow(1280, 720, "mapgen"); | |
| srand(time(NULL)); // NOLINT(bugprone-random-generator-seed) | |
| initRenderer("../../Source/images/kenney-1bit-table-16-16.png", 16, 0, 0); // 0,0 = use window size | |
| Point camera = {.x = 0, .y = 0}; | |
| int cameraSpeed = 16; | |
| int cellSize = 16; | |
| static Map map; | |
| generateMap(&map); | |
| SetTargetFPS(60); | |
| //-------------------------------------------------------------------------------------- | |
| // Main game loop | |
| while (!WindowShouldClose()) // Detect window close button or ESC key | |
| { | |
| // Update | |
| //---------------------------------------------------------------------------------- | |
| if (IsKeyDown(KEY_W)) | |
| camera.y -= cameraSpeed; | |
| if (IsKeyDown(KEY_S)) | |
| camera.y += cameraSpeed; | |
| if (IsKeyDown(KEY_A)) | |
| camera.x -= cameraSpeed; | |
| if (IsKeyDown(KEY_D)) | |
| camera.x += cameraSpeed; | |
| if (IsKeyPressed(KEY_Q)) | |
| cellSize -= 8; | |
| if (IsKeyPressed(KEY_E)) | |
| cellSize += 8; | |
| cellSize = max(cellSize, 8); | |
| cellSize = min(cellSize, 128); | |
| if (IsKeyPressed(KEY_R)) { | |
| char screenshotName[64]; | |
| snprintf(screenshotName, sizeof(screenshotName), "map-%ld.png", (long)time(NULL)); | |
| TakeScreenshot(screenshotName); | |
| } | |
| if (IsKeyPressed(KEY_SPACE)) { | |
| generateMap(&map); | |
| } | |
| //---------------------------------------------------------------------------------- | |
| // Draw | |
| //---------------------------------------------------------------------------------- | |
| BeginDrawing(); | |
| ClearBackground(WHITE); | |
| drawMap(&map, camera, cellSize); | |
| EndDrawing(); | |
| //---------------------------------------------------------------------------------- | |
| } | |
| // De-Initialization | |
| //-------------------------------------------------------------------------------------- | |
| freeRenderer(); | |
| CloseWindow(); // Close window and OpenGL context | |
| //-------------------------------------------------------------------------------------- | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment