Advertisement
czeak6464

Random Generator Bakin

Jan 19th, 2025
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.37 KB | Source Code | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using Yukar.Engine;
  4. using System.IO;
  5.  
  6. namespace Bakin
  7. {
  8.     public static class DungeonConstants
  9.     {
  10.         public const int DEFAULT_FLOOR = 1;
  11.         public const int DEFAULT_WALL = 15;
  12.         public const int DEFAULT_CORRIDOR = 1;
  13.         public const int FLOOR_HEIGHT = 0;
  14.         public const int WALL_HEIGHT = 15;
  15.     }
  16.  
  17.     public class Testing : BakinObject
  18.     {
  19.         private MapScene mapScene;
  20.         private DungeonData currentDungeon;
  21.         private const string SAVE_DIRECTORY = "SavedDungeons";
  22.         private const string FILE_EXTENSION = ".dungeon";
  23.  
  24.         public override void Start()
  25.         {
  26.             mapScene = GameMain.instance.mapScene;
  27.  
  28.             if (GameMain.instance.getScenes() == GameMain.Scenes.TITLE ||
  29.                 GameMain.instance.getScenes() == GameMain.Scenes.LOADING ||
  30.                 mapScene == null)
  31.                 return;
  32.  
  33.             Directory.CreateDirectory(SAVE_DIRECTORY);
  34.         }
  35.  
  36.         [BakinFunction(Description = "1) Generate basic dungeon (23x23)")]
  37.         public void Generate()
  38.         {
  39.             GenerateNewDungeon(23, 23, 4, 8, 5,
  40.                 DungeonConstants.DEFAULT_FLOOR,
  41.                 DungeonConstants.DEFAULT_WALL,
  42.                 DungeonConstants.DEFAULT_CORRIDOR);
  43.         }
  44.  
  45.         [BakinFunction(Description = "2) Save current dungeon")]
  46.         public void Save(string dungeonName)
  47.         {
  48.             SaveDungeon(dungeonName);
  49.         }
  50.  
  51.         [BakinFunction(Description = "3) Load saved dungeon")]
  52.         public void Load(string dungeonName)
  53.         {
  54.             LoadDungeon(dungeonName);
  55.         }
  56.  
  57.         [BakinFunction(Description = "4) Generate custom size dungeon (width_height)")]
  58.         public void GenerateCustomSize(string size)
  59.         {
  60.             string[] dimensions = size.Split('_');
  61.             if (dimensions.Length == 2 && int.TryParse(dimensions[0], out int width) && int.TryParse(dimensions[1], out int height))
  62.             {
  63.                 GenerateNewDungeon(width, height, 3, 6, 100,
  64.                     DungeonConstants.DEFAULT_FLOOR,
  65.                     DungeonConstants.DEFAULT_WALL,
  66.                     DungeonConstants.DEFAULT_CORRIDOR);
  67.             }
  68.         }
  69.  
  70.         [BakinFunction(Description = "5) Generate with custom terrain (floor_wall_corridor)")]
  71.         public void GenerateCustomTerrain(string terrainTypes)
  72.         {
  73.             string[] types = terrainTypes.Split('_');
  74.             if (types.Length == 3 && int.TryParse(types[0], out int floor) &&
  75.                 int.TryParse(types[1], out int wall) && int.TryParse(types[2], out int corridor))
  76.             {
  77.                 GenerateNewDungeon(23, 23, 3, 6, 100, floor, wall, corridor);
  78.             }
  79.         }
  80.  
  81.         [BakinFunction(Description = "0) Clear/Reset current dungeon")]
  82.         public void Clear()
  83.         {
  84.             if (mapScene?.mapDrawer == null) return;
  85.  
  86.             int width = currentDungeon != null ? currentDungeon.Width : 23;
  87.             int height = currentDungeon != null ? currentDungeon.Height : 23;
  88.  
  89.             for (int x = 0; x < width; x++)
  90.             {
  91.                 for (int y = 0; y < height; y++)
  92.                 {
  93.                     mapScene.mapDrawer.setTerrain(x, y, 1, 1, true);
  94.                 }
  95.             }
  96.             mapScene.mapDrawer.updateMapHeightAndWalkableState(true);
  97.             currentDungeon = null;
  98.         }
  99.  
  100.         private void GenerateNewDungeon(int width, int height, int minRoomSize, int maxRoomSize, int maxRooms,
  101.             int floorType, int wallType, int corridorType)
  102.         {
  103.             currentDungeon = new DungeonData(width, height)
  104.             {
  105.                 FloorType = floorType,
  106.                 WallType = wallType,
  107.                 CorridorType = corridorType
  108.             };
  109.  
  110.             for (int x = 0; x < width; x++)
  111.             {
  112.                 for (int y = 0; y < height; y++)
  113.                 {
  114.                     currentDungeon.TerrainData[x, y] = wallType;
  115.                 }
  116.             }
  117.  
  118.             GenerateRooms(minRoomSize, maxRoomSize, maxRooms);
  119.         }
  120.  
  121.         private void SaveDungeon(string saveName)
  122.         {
  123.             if (currentDungeon == null) return;
  124.  
  125.             string filePath = Path.Combine(SAVE_DIRECTORY, saveName + FILE_EXTENSION);
  126.             string data = SerializeDungeon(currentDungeon);
  127.             File.WriteAllText(filePath, data);
  128.         }
  129.  
  130.         private void LoadDungeon(string saveName)
  131.         {
  132.             string filePath = Path.Combine(SAVE_DIRECTORY, saveName + FILE_EXTENSION);
  133.             if (!File.Exists(filePath)) return;
  134.  
  135.             string data = File.ReadAllText(filePath);
  136.             currentDungeon = DeserializeDungeon(data);
  137.             ApplyDungeonToMap();
  138.         }
  139.  
  140.         private string SerializeDungeon(DungeonData dungeon)
  141.         {
  142.             List<string> lines = new List<string>
  143.             {
  144.                 $"Width:{dungeon.Width}",
  145.                 $"Height:{dungeon.Height}",
  146.                 $"Floor:{dungeon.FloorType}",
  147.                 $"Wall:{dungeon.WallType}",
  148.                 $"Corridor:{dungeon.CorridorType}"
  149.             };
  150.  
  151.             for (int y = 0; y < dungeon.Height; y++)
  152.             {
  153.                 string row = "";
  154.                 for (int x = 0; x < dungeon.Width; x++)
  155.                 {
  156.                     row += dungeon.TerrainData[x, y].ToString();
  157.                     if (x < dungeon.Width - 1) row += ",";
  158.                 }
  159.                 lines.Add(row);
  160.             }
  161.  
  162.             return string.Join("\n", lines);
  163.         }
  164.  
  165.         private DungeonData DeserializeDungeon(string data)
  166.         {
  167.             string[] lines = data.Split('\n');
  168.             int width = int.Parse(lines[0].Split(':')[1]);
  169.             int height = int.Parse(lines[1].Split(':')[1]);
  170.  
  171.             DungeonData dungeon = new DungeonData(width, height);
  172.             dungeon.FloorType = int.Parse(lines[2].Split(':')[1]);
  173.             dungeon.WallType = int.Parse(lines[3].Split(':')[1]);
  174.             dungeon.CorridorType = int.Parse(lines[4].Split(':')[1]);
  175.  
  176.             for (int y = 0; y < height; y++)
  177.             {
  178.                 string[] values = lines[y + 5].Split(',');
  179.                 for (int x = 0; x < width; x++)
  180.                 {
  181.                     dungeon.TerrainData[x, y] = int.Parse(values[x]);
  182.                 }
  183.             }
  184.  
  185.             return dungeon;
  186.         }
  187.  
  188.         private void ApplyDungeonToMap()
  189.         {
  190.             if (mapScene?.mapDrawer == null || currentDungeon == null) return;
  191.  
  192.             for (int x = 0; x < currentDungeon.Width; x++)
  193.             {
  194.                 for (int y = 0; y < currentDungeon.Height; y++)
  195.                 {
  196.                     bool isWall = currentDungeon.TerrainData[x, y] == currentDungeon.WallType;
  197.  
  198.                     if (isWall)
  199.                     {
  200.                         mapScene.mapDrawer.setTerrainHeight(x, y, 15);
  201.                         mapScene.mapDrawer.setTerrain(x, y, 15, 15, true);
  202.                     }
  203.                     else
  204.                     {
  205.                         mapScene.mapDrawer.setTerrainHeight(x, y, 0);
  206.                         mapScene.mapDrawer.setTerrain(x, y, 1, 0, true);
  207.                     }
  208.                 }
  209.             }
  210.  
  211.             mapScene.mapDrawer.updateMapHeightAndWalkableState(true);
  212.         }
  213.  
  214.         private void GenerateRooms(int minRoomSize, int maxRoomSize, int maxRooms)
  215.         {
  216.             List<Room> rooms = new List<Room>();
  217.             Random random = new Random();
  218.  
  219.             int attempts = 0;
  220.             while (rooms.Count < maxRooms && attempts < 1000)
  221.             {
  222.                 int roomWidth = random.Next(minRoomSize, maxRoomSize + 1);
  223.                 int roomHeight = random.Next(minRoomSize, maxRoomSize + 1);
  224.                 int roomX = random.Next(2, currentDungeon.Width - roomWidth - 2);
  225.                 int roomY = random.Next(2, currentDungeon.Height - roomHeight - 2);
  226.  
  227.                 Room newRoom = new Room(roomX, roomY, roomWidth, roomHeight);
  228.  
  229.                 bool tooClose = rooms.Exists(r =>
  230.                     Math.Abs(r.CenterX - newRoom.CenterX) < roomWidth + 2 ||
  231.                     Math.Abs(r.CenterY - newRoom.CenterY) < roomHeight + 2);
  232.  
  233.                 if (!tooClose)
  234.                 {
  235.                     rooms.Add(newRoom);
  236.                     for (int x = roomX - 1; x <= roomX + roomWidth; x++)
  237.                     {
  238.                         for (int y = roomY - 1; y <= roomY + roomHeight; y++)
  239.                         {
  240.                             if (x == roomX - 1 || x == roomX + roomWidth ||
  241.                                 y == roomY - 1 || y == roomY + roomHeight)
  242.                             {
  243.                                 currentDungeon.TerrainData[x, y] = currentDungeon.WallType;
  244.                             }
  245.                             else
  246.                             {
  247.                                 currentDungeon.TerrainData[x, y] = currentDungeon.FloorType;
  248.                             }
  249.                         }
  250.                     }
  251.                 }
  252.                 attempts++;
  253.             }
  254.  
  255.             ConnectRooms(rooms);
  256.             ApplyDungeonToMap();
  257.         }
  258.  
  259.         private void ConnectRooms(List<Room> rooms)
  260.         {
  261.             for (int i = 1; i < rooms.Count; i++)
  262.             {
  263.                 int prevRoomCenterX = Clamp(rooms[i - 1].CenterX, 1, currentDungeon.Width - 2);
  264.                 int prevRoomCenterY = Clamp(rooms[i - 1].CenterY, 1, currentDungeon.Height - 2);
  265.                 int currRoomCenterX = Clamp(rooms[i].CenterX, 1, currentDungeon.Width - 2);
  266.                 int currRoomCenterY = Clamp(rooms[i].CenterY, 1, currentDungeon.Height - 2);
  267.  
  268.                 CreateCorridor(prevRoomCenterX, prevRoomCenterY, currRoomCenterX, currRoomCenterY);
  269.             }
  270.         }
  271.  
  272.         private void CreateCorridor(int fromX, int fromY, int toX, int toY)
  273.         {
  274.             int currentX = fromX;
  275.             int currentY = fromY;
  276.  
  277.             bool horizontalFirst = new Random().Next(2) == 0;
  278.  
  279.             if (horizontalFirst)
  280.             {
  281.                 while (currentX != toX)
  282.                 {
  283.                     currentX += Math.Sign(toX - currentX);
  284.                     CreateCorridorTile(currentX, currentY);
  285.                 }
  286.                 while (currentY != toY)
  287.                 {
  288.                     currentY += Math.Sign(toY - currentY);
  289.                     CreateCorridorTile(currentX, currentY);
  290.                 }
  291.             }
  292.             else
  293.             {
  294.                 while (currentY != toY)
  295.                 {
  296.                     currentY += Math.Sign(toY - currentY);
  297.                     CreateCorridorTile(currentX, currentY);
  298.                 }
  299.                 while (currentX != toX)
  300.                 {
  301.                     currentX += Math.Sign(toX - currentX);
  302.                     CreateCorridorTile(currentX, currentY);
  303.                 }
  304.             }
  305.         }
  306.  
  307.         private void CreateCorridorTile(int x, int y)
  308.         {
  309.             if (x > 0 && x < currentDungeon.Width - 1 && y > 0 && y < currentDungeon.Height - 1)
  310.             {
  311.                 currentDungeon.TerrainData[x, y] = currentDungeon.CorridorType;
  312.  
  313.                 if (currentDungeon.TerrainData[x - 1, y] == currentDungeon.WallType)
  314.                     currentDungeon.TerrainData[x - 1, y] = currentDungeon.WallType;
  315.                 if (currentDungeon.TerrainData[x + 1, y] == currentDungeon.WallType)
  316.                     currentDungeon.TerrainData[x + 1, y] = currentDungeon.WallType;
  317.                 if (currentDungeon.TerrainData[x, y - 1] == currentDungeon.WallType)
  318.                     currentDungeon.TerrainData[x, y - 1] = currentDungeon.WallType;
  319.                 if (currentDungeon.TerrainData[x, y + 1] == currentDungeon.WallType)
  320.                     currentDungeon.TerrainData[x, y + 1] = currentDungeon.WallType;
  321.             }
  322.         }
  323.  
  324.         private int Clamp(int value, int min, int max)
  325.         {
  326.             return (value < min) ? min : (value > max) ? max : value;
  327.         }
  328.     }
  329.  
  330.     [Serializable]
  331.     public class DungeonData
  332.     {
  333.         public int Width { get; set; }
  334.         public int Height { get; set; }
  335.         public int[,] TerrainData { get; set; }
  336.         public int FloorType { get; set; }
  337.         public int WallType { get; set; }
  338.         public int CorridorType { get; set; }
  339.  
  340.         public DungeonData(int width, int height)
  341.         {
  342.             Width = width;
  343.             Height = height;
  344.             TerrainData = new int[width, height];
  345.             FloorType = DungeonConstants.DEFAULT_FLOOR;
  346.             WallType = DungeonConstants.DEFAULT_WALL;
  347.             CorridorType = DungeonConstants.DEFAULT_CORRIDOR;
  348.         }
  349.     }
  350.  
  351.     public class Room
  352.     {
  353.         public int X, Y, Width, Height;
  354.  
  355.         public Room(int x, int y, int width, int height)
  356.         {
  357.             X = x;
  358.             Y = y;
  359.             Width = width;
  360.             Height = height;
  361.         }
  362.  
  363.         public int CenterX => X + Width / 2;
  364.         public int CenterY => Y + Height / 2;
  365.  
  366.         public bool Intersects(Room other)
  367.         {
  368.             return X <= other.X + other.Width &&
  369.                    X + Width >= other.X &&
  370.                    Y <= other.Y + other.Height &&
  371.                    Y + Height >= other.Y;
  372.         }
  373.     }
  374. }
  375.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement