zoukankan      html  css  js  c++  java
  • Unity 随机房间地图生成

    无论是在迷宫还是类似于地牢的游戏地图中,利用程序来生成每次都不一样的地图是一件叫人兴奋不已的事。

    这时我们需要解决两个非常重要的随机事件:

    1.在一定范围内随机出各不相同但又不能互相重叠的房间

    2.优美生成连接这些房间的通道

    基本的UML思路图:

    这次我们先讨论如何快速生成符合各种随机要求的房间。

    一般来说,一个房间的高度是一个相对固定的值,可以根据面板上的参数进行必要的调整,而真正参与随机的应该是房间的长,宽和位置。

    建立房间的数据结构,根据需求可以随时补充和添加:

     1 using System.Collections.Generic;
     2 using UnityEngine;
     3 
     4 public class RoomData
     5 {
     6     public int Id;
     7     //房间的Transform等属性
     8     public RoomTran RoomTran;
     9     //该房间的战斗类型
    10     public RoomBattleType BattleType;
    11     //该房间与哪些其余房间互相连接
    12     public List<RoomData> CrossRooms;
    13     //房间内的怪物列表
    14     public List<GameObject> Monsters;
    15     //是否是端点房间
    16     public bool bEndRoom;
    17     //是否是主路径房间
    18     public bool bMainCrossRoom;
    19 }
    20 
    21 public class RoomTran
    22 {
    23     public int Length;
    24     public int Width;
    25     //长宽中心点
    26     public Vector2Int CenterPos;
    27     //高度位置
    28     public float PosY;
    29 }
    30 
    31 public enum RoomBattleType
    32 {
    33     Rest,
    34     NormalBattle,
    35     BossBattle
    36 }

    RoonBuilder属性和控制参数:

     1     //建筑单位方块
     2     public GameObject BuildUnit;
     3 
     4     //房间高度值
     5     public int FixedUnitHeight;
     6     //生成的房间层数
     7     public int LayerCount;
     8     //长宽随机范围
     9     public Vector2Int GenRange;
    10 
    11     //随机类型
    12     public RoomRandType RandType;
    13     //随机的房间形状类型
    14     public RoomShapeType Shape;
    15 
    16     //房间大小的随机列表,用于枚举随机
    17     public List<Vector2Int> RoomRandSizes = new List<Vector2Int>();
    18 
    19     //随机的房间最大面积
    20     public int MaxRoomArea;
    21     //最大随机数量(随机试验次数)
    22     public int MaxRoomCount;
    23 
    24     //最小边长度
    25     private int MinRoomEdge;
    26     //最大长宽比
    27     public int MaxLengthWidthScale = 2;
    28 
    29     //标准方向
    30     Vector3Int Dx = new Vector3Int(1, 0, 0);
    31     Vector3Int Dy = new Vector3Int(0, 1, 0);
    32     Vector3Int Dz = new Vector3Int(0, 0, 1);
    33 
    34     //建筑单位标签
    35     const string S_TAG = "Unit";
    36 
    37     private MapSystem MapManager;

    单房间轮廓生成:

     1     /// <summary>
     2     /// 生成单一房间的轮廓
     3     /// </summary>
     4     /// <param name="centerPos">房间中点位置</param>
     5     /// <param name="length"></param>
     6     /// <param name="width"></param>
     7     /// <param name="parent">父物体</param>
     8     void GenOneRoom(Vector3 centerPos, int length, int width, Transform parent = null)
     9     {
    10         var to = new Vector3(length - 1, FixedUnitHeight - 1, width - 1) * .5f;
    11 
    12         //顶点
    13         var ned = centerPos - to;
    14         var fod = centerPos + to;
    15 
    16         var v3 = new Vector3(ned.x, fod.y, ned.z);
    17         var v4 = new Vector3(ned.x, fod.y, fod.z);
    18         var v5 = new Vector3(ned.x, ned.y, fod.z);
    19 
    20         var v6 = new Vector3(fod.x, ned.y, ned.z);
    21         var v7 = new Vector3(fod.x, ned.y, fod.z);
    22         var v8 = new Vector3(fod.x, fod.y, ned.z);
    23 
    24         //顶点位置(8个)
    25         InsSetPos(ned, parent);
    26         InsSetPos(fod, parent);
    27         InsSetPos(v3, parent);
    28         InsSetPos(v4, parent);
    29         InsSetPos(v5, parent);
    30         InsSetPos(v6, parent);
    31         InsSetPos(v7, parent);
    32         InsSetPos(v8, parent);
    33 
    34         //12条棱(4*3)
    35         //
    36         InsOneEdge(length, ned, Dx, parent);
    37         InsOneEdge(length, v3, Dx, parent);
    38         InsOneEdge(length, v4, Dx, parent);
    39         InsOneEdge(length, v5, Dx, parent);
    40         //
    41         InsOneEdge(FixedUnitHeight, ned, Dy, parent);
    42         InsOneEdge(FixedUnitHeight, v5, Dy, parent);
    43         InsOneEdge(FixedUnitHeight, v6, Dy, parent);
    44         InsOneEdge(FixedUnitHeight, v7, Dy, parent);
    45         //
    46         InsOneEdge(width, ned, Dz, parent);
    47         InsOneEdge(width, v3, Dz, parent);
    48         InsOneEdge(width, v6, Dz, parent);
    49         InsOneEdge(width, v8, Dz, parent);
    50     }
    51 
    52     //生成一条边上的建筑单位但不包含顶点位置
    53     void InsOneEdge(int edge, Vector3 v, Vector3 dir, Transform parent = null)
    54     {
    55         //忽略首尾单位
    56         for (int i = 1; i < edge - 1; i++)
    57         {
    58             InsSetPos(v + i * dir, parent);
    59         }
    60     }
    61 
    62     void InsSetPos(Vector3 pos, Transform parent = null)
    63     {
    64         var ins = Instantiate(BuildUnit);
    65         ins.transform.position = pos;
    66         ins.transform.parent = parent;
    67     }

    这里唯一值得注意的地方是房间顶点位置的单位不要重复生成。(因为想偷懒的话真的很容易重复Orz)。

    随机RoomTran结构:

     1     RoomTran RanRoomTran(Vector3 centerPos)
     2     {
     3         var rt = new RoomTran();
     4 
     5         switch (RandType)
     6         {
     7             case RoomRandType.AllRand:
     8                 int temp;
     9                 var oe = MaxRoomArea / MinRoomEdge;
    10                 switch (Shape)
    11                 {
    12                     case RoomShapeType.LengthMain:
    13                         rt.Length = Random.Range(MinRoomEdge + 1, oe + 1);
    14                         temp = MaxRoomArea / rt.Length;
    15                         if (temp >= rt.Length)
    16                             rt.Width = Random.Range(MinRoomEdge, rt.Length);
    17                         else
    18                             rt.Width = Random.Range(MinRoomEdge, temp + 1);
    19                         break;
    20                     case RoomShapeType.WidthMain:
    21                         rt.Width = Random.Range(MinRoomEdge + 1, oe + 1);
    22                         temp = MaxRoomArea / rt.Width;
    23                         if (temp >= rt.Width)
    24                             rt.Length = Random.Range(MinRoomEdge, rt.Width);
    25                         else
    26                             rt.Length = Random.Range(MinRoomEdge, temp + 1);
    27                         break;
    28                     case RoomShapeType.Coustom:
    29                         rt.Length = Random.Range(MinRoomEdge, oe + 1);
    30                         temp = MaxRoomArea / rt.Length;
    31                         rt.Width = Random.Range(MinRoomEdge, temp + 1);
    32                         break;
    33                 }
    34                 break;
    35             case RoomRandType.EnumRand:
    36                 var rc = RoomRandSizes.Count;
    37                 if (rc == 0)
    38                 {
    39                     //未填写时设定随机默认值
    40                     rt.Length = 3;
    41                     rt.Width = 3;
    42                 }
    43                 else
    44                 {
    45                     var ridx = Random.Range(0,rc);
    46                     var t = RoomRandSizes[ridx];
    47                     if (t.x < 3 || t.y < 3)
    48                     {
    49                         //填写错误时设定随机默认值
    50                         rt.Length = 3;
    51                         rt.Width = 3;
    52                     }
    53                     else
    54                     {
    55                         switch (Shape)
    56                         {
    57                             case RoomShapeType.LengthMain:
    58                                 rt.Length = t.x > t.y ? t.x : t.y;
    59                                 rt.Width = t.x < t.y ? t.x : t.y;
    60                                 break;
    61                             case RoomShapeType.WidthMain:
    62                                 rt.Width = t.x > t.y ? t.x : t.y;
    63                                 rt.Length = t.x < t.y ? t.x : t.y;
    64                                 break;
    65                             case RoomShapeType.Coustom:
    66                                 rt.Length = Random.value < .5f ? t.x : t.y;
    67                                 rt.Width = t.y == rt.Length ? t.x : t.y;
    68                                 break;
    69                         }         
    70                     }
    71                 }
    72                 break;
    73         }
    74    
    75         rt.CenterPos = new Vector2Int(Random.Range((int)(centerPos.x - GenRange.x * .5f), (int)(centerPos.x + GenRange.x * .5f)),
    76             Random.Range((int)(centerPos.z - GenRange.y * .5f), (int)(centerPos.z + GenRange.y * .5f)));
    77 
    78         rt.PosY = centerPos.y;
    79 
    80         var roomCenter = new Vector3(rt.CenterPos.x, rt.PosY, rt.CenterPos.y);
    81 
    82         //射线检测重叠
    83         if (RayRoomCheck(roomCenter, rt.Length, rt.Width))
    84         {
    85             return null;
    86         }
    87         return rt;
    88     }

    用的是射线检测重叠,生成了重叠的房间就会被视作是一次失败的随机试验,之前尝试过直接用物理系统推开失败了,可能是使用有误,如果有知道原因的欢迎与笔者分享,共同进步;

    当然了,你也可以用Unity自带的Bounds.Intersects(Bounds other)方法来判断两个生成的房间盒子是否重叠,但缺点是没有办法控制两个房间边缘的间隔的最小距离,用纯粹的数学方法判断三个轴向的边缘值大小同样也是可行的:

     1     //生成房间前射线检测下范围内有无其他房间
     2     bool RayRoomCheck(Vector3 cp, int length, int width)
     3     {
     4         bool result = false;
     5         //长宽至少留一格间隙,高度与地板格对齐
     6         var to = new Vector3(length + 1, FixedUnitHeight - 1, width + 1) * .5f;
     7         var ned = cp - to;
     8 
     9         var vx2 = ned + new Vector3(0, 0, width + 1) * .5f;
    10         var vx3 = ned + new Vector3(0, 0, width + 1);
    11 
    12         var vx4 = ned + new Vector3(length + 1, 0, width * .5f + .5f);
    13         var vx5 = ned + new Vector3(length + 1, 0, width + 1);
    14 
    15         var vz2 = ned + new Vector3(length + 1, 0, 0) * .5f;
    16         var vz3 = ned + new Vector3(length + 1, 0, 0);
    17 
    18         var vz4 = ned + new Vector3(length * .5f + .5f, 0, width + 1);
    19         var vz5 = ned + new Vector3(length + 1, 0, width + 1);
    20 
    21         result =
    22         //4组射线,每组3条
    23         RayCast(ned, Dx, length + 1, S_TAG) ||
    24         RayCast(vx2, Dx, length + 1, S_TAG) ||
    25         RayCast(vx3, Dx, length + 1, S_TAG) ||
    26 
    27         RayCast(vx4, Dx * -1, length + 1, S_TAG) ||
    28         RayCast(vx5, Dx * -1, length + 1, S_TAG) ||
    29         RayCast(vz3, Dx * -1, length + 1, S_TAG) ||
    30 
    31         RayCast(ned, Dz, width + 1, S_TAG) ||
    32         RayCast(vz2, Dz, width + 1, S_TAG) ||
    33         RayCast(vz3, Dz, width + 1, S_TAG) ||
    34 
    35         RayCast(vz4, Dz * -1, width + 1, S_TAG) ||
    36         RayCast(vz5, Dz * -1, width + 1, S_TAG) ||
    37         RayCast(vx3, Dz * -1, width + 1, S_TAG);
    38 
    39         return result;
    40     }

    这里将射线的起点和终点都延长了一格,是为了避免两个生成的房间贴得太紧,这样至少每个房间与其它房间间隔一个单位格或以上。

    完整的房间结构生成脚本:

      1 using System.Collections;
      2 using System.Collections.Generic;
      3 using UnityEngine;
      4 using UnityEngine.Events;
      5 
      6 public enum RoomRandType
      7 {
      8     //全随机
      9     AllRand,
     10     //枚举大小随机
     11     EnumRand
     12 }
     13 
     14 public enum RoomShapeType
     15 {
     16     //宽>=长
     17     WidthMain,
     18     //长>=宽
     19     LengthMain,
     20     //自定义,无形状要求
     21     Coustom
     22 }
     23 //x-length z-width y-height
     24 
     25 public class RoomBuilder : MonoBehaviour
     26 {
     27     //建筑单位方块
     28     public GameObject BuildUnit;
     29 
     30     //房间高度值
     31     public int FixedUnitHeight;
     32     //生成的房间层数
     33     public int LayerCount;
     34     //长宽随机范围
     35     public Vector2Int GenRange;
     36 
     37     //随机类型
     38     public RoomRandType RandType;
     39     //随机的房间形状类型
     40     public RoomShapeType Shape;
     41 
     42     //房间大小的随机列表,用于枚举随机
     43     public List<Vector2Int> RoomRandSizes = new List<Vector2Int>();
     44 
     45     //随机的房间最大面积
     46     public int MaxRoomArea;
     47     //最大随机数量(随机试验次数)
     48     public int MaxRoomCount;
     49 
     50     //最小边长度
     51     private int MinRoomEdge;
     52     //最大长宽比
     53     public int MaxLengthWidthScale = 2;
     54 
     55     //标准方向
     56     Vector3Int Dx = new Vector3Int(1, 0, 0);
     57     Vector3Int Dy = new Vector3Int(0, 1, 0);
     58     Vector3Int Dz = new Vector3Int(0, 0, 1);
     59 
     60     //建筑单位标签
     61     const string S_TAG = "Unit";
     62 
     63     private MapSystem MapManager;
     64 
     65     void Awake()
     66     {
     67         MapManager = GetComponent<MapSystem>();
     68     }
     69 
     70     public IEnumerator GenRooms(Vector3Int centerPos,UnityAction complete)
     71     {
     72         var temp = (int)Mathf.Sqrt(MaxRoomArea * 1.0f / MaxLengthWidthScale);
     73         MinRoomEdge = temp > 3 ? temp : 3;
     74 
     75         //每层至少1
     76         for (int i = 1; i <= LayerCount; i++)
     77         {
     78             SetGenOneRoom(centerPos, i);
     79             yield return new WaitForSeconds(.1f);
     80         }
     81 
     82         //超过的随机布置
     83         var oc = MaxRoomCount - LayerCount;
     84         if (oc > 0)
     85         {
     86             for (int i = 1; i <= oc; i++)
     87             {
     88                 var r = Random.Range(1, LayerCount + 1);
     89                 SetGenOneRoom(centerPos, r);
     90                 yield return new WaitForSeconds(.1f);
     91             }
     92         }
     93 
     94         //所有房间生成完成后发送一个委托信号,以便后续创建房间数据和计算必要连接
     95         complete();
     96     }
     97 
     98     void SetGenOneRoom(Vector3Int cp, int r)
     99     {
    100         var layerCenter = cp - new Vector3(0, (LayerCount - 2 * r + 1) * .5f * FixedUnitHeight, 0);
    101 
    102         var rt = RanRoomTran(layerCenter);
    103         if (rt != null)
    104         {
    105             var roomCenter = new Vector3(rt.CenterPos.x, rt.PosY, rt.CenterPos.y);
    106 
    107             GameObject temp = new GameObject(r.ToString());
    108             temp.transform.position = roomCenter;
    109             temp.tag = S_TAG;
    110 
    111             //给生成的房间添加碰撞盒子并设置大小
    112             GenOneRoom(roomCenter, rt.Length, rt.Width, temp.transform);
    113             var bc = temp.AddComponent<BoxCollider>();
    114             bc.size = new Vector3(rt.Length, FixedUnitHeight, rt.Width);
    115 
    116             //目前用物理方式似乎难以推开重叠的房间,可能是哪里使用方法有误,改为用用射线检测解决...
    117             //var rb = temp.AddComponent<Rigidbody>();
    118             //rb.useGravity = false;
    119             //rb.drag = Mathf.Infinity;
    120             //rb.constraints = RigidbodyConstraints.FreezePositionY;
    121             //rb.freezeRotation = true;
    122 
    123             //将房间数据存入临时列表
    124             MapManager.GenRooms.Add(rt);
    125             MapManager.UnCrossRooms.Add(rt);
    126         }
    127     }
    128 
    129     RoomTran RanRoomTran(Vector3 centerPos)
    130     {
    131         var rt = new RoomTran();
    132 
    133         switch (RandType)
    134         {
    135             case RoomRandType.AllRand:
    136                 int temp;
    137                 var oe = MaxRoomArea / MinRoomEdge;
    138                 switch (Shape)
    139                 {
    140                     case RoomShapeType.LengthMain:
    141                         rt.Length = Random.Range(MinRoomEdge + 1, oe + 1);
    142                         temp = MaxRoomArea / rt.Length;
    143                         if (temp >= rt.Length)
    144                             rt.Width = Random.Range(MinRoomEdge, rt.Length);
    145                         else
    146                             rt.Width = Random.Range(MinRoomEdge, temp + 1);
    147                         break;
    148                     case RoomShapeType.WidthMain:
    149                         rt.Width = Random.Range(MinRoomEdge + 1, oe + 1);
    150                         temp = MaxRoomArea / rt.Width;
    151                         if (temp >= rt.Width)
    152                             rt.Length = Random.Range(MinRoomEdge, rt.Width);
    153                         else
    154                             rt.Length = Random.Range(MinRoomEdge, temp + 1);
    155                         break;
    156                     case RoomShapeType.Coustom:
    157                         rt.Length = Random.Range(MinRoomEdge, oe + 1);
    158                         temp = MaxRoomArea / rt.Length;
    159                         rt.Width = Random.Range(MinRoomEdge, temp + 1);
    160                         break;
    161                 }
    162                 break;
    163             case RoomRandType.EnumRand:
    164                 var rc = RoomRandSizes.Count;
    165                 if (rc == 0)
    166                 {
    167                     //未填写时设定随机默认值
    168                     rt.Length = 3;
    169                     rt.Width = 3;
    170                 }
    171                 else
    172                 {
    173                     var ridx = Random.Range(0,rc);
    174                     var t = RoomRandSizes[ridx];
    175                     if (t.x < 3 || t.y < 3)
    176                     {
    177                         //填写错误时设定随机默认值
    178                         rt.Length = 3;
    179                         rt.Width = 3;
    180                     }
    181                     else
    182                     {
    183                         switch (Shape)
    184                         {
    185                             case RoomShapeType.LengthMain:
    186                                 rt.Length = t.x > t.y ? t.x : t.y;
    187                                 rt.Width = t.x < t.y ? t.x : t.y;
    188                                 break;
    189                             case RoomShapeType.WidthMain:
    190                                 rt.Width = t.x > t.y ? t.x : t.y;
    191                                 rt.Length = t.x < t.y ? t.x : t.y;
    192                                 break;
    193                             case RoomShapeType.Coustom:
    194                                 rt.Length = Random.value < .5f ? t.x : t.y;
    195                                 rt.Width = t.y == rt.Length ? t.x : t.y;
    196                                 break;
    197                         }         
    198                     }
    199                 }
    200                 break;
    201         }
    202    
    203         rt.CenterPos = new Vector2Int(Random.Range((int)(centerPos.x - GenRange.x * .5f), (int)(centerPos.x + GenRange.x * .5f)),
    204             Random.Range((int)(centerPos.z - GenRange.y * .5f), (int)(centerPos.z + GenRange.y * .5f)));
    205 
    206         rt.PosY = centerPos.y;
    207 
    208         var roomCenter = new Vector3(rt.CenterPos.x, rt.PosY, rt.CenterPos.y);
    209 
    210         //射线检测重叠
    211         if (RayRoomCheck(roomCenter, rt.Length, rt.Width))
    212         {
    213             return null;
    214         }
    215         return rt;
    216     }
    217 
    218     //生成房间前射线检测下范围内有无其他房间
    219     bool RayRoomCheck(Vector3 cp, int length, int width)
    220     {
    221         bool result = false;
    222         //长宽至少留一格间隙,高度与地板格对齐
    223         var to = new Vector3(length + 1, FixedUnitHeight - 1, width + 1) * .5f;
    224         var ned = cp - to;
    225 
    226         var vx2 = ned + new Vector3(0, 0, width + 1) * .5f;
    227         var vx3 = ned + new Vector3(0, 0, width + 1);
    228 
    229         var vx4 = ned + new Vector3(length + 1, 0, width * .5f + .5f);
    230         var vx5 = ned + new Vector3(length + 1, 0, width + 1);
    231 
    232         var vz2 = ned + new Vector3(length + 1, 0, 0) * .5f;
    233         var vz3 = ned + new Vector3(length + 1, 0, 0);
    234 
    235         var vz4 = ned + new Vector3(length * .5f + .5f, 0, width + 1);
    236         var vz5 = ned + new Vector3(length + 1, 0, width + 1);
    237 
    238         result =
    239         //4组射线,每组3条
    240         RayCast(ned, Dx, length + 1, S_TAG) ||
    241         RayCast(vx2, Dx, length + 1, S_TAG) ||
    242         RayCast(vx3, Dx, length + 1, S_TAG) ||
    243 
    244         RayCast(vx4, Dx * -1, length + 1, S_TAG) ||
    245         RayCast(vx5, Dx * -1, length + 1, S_TAG) ||
    246         RayCast(vz3, Dx * -1, length + 1, S_TAG) ||
    247 
    248         RayCast(ned, Dz, width + 1, S_TAG) ||
    249         RayCast(vz2, Dz, width + 1, S_TAG) ||
    250         RayCast(vz3, Dz, width + 1, S_TAG) ||
    251 
    252         RayCast(vz4, Dz * -1, width + 1, S_TAG) ||
    253         RayCast(vz5, Dz * -1, width + 1, S_TAG) ||
    254         RayCast(vx3, Dz * -1, width + 1, S_TAG);
    255 
    256         return result;
    257     }
    258 
    259     bool RayCast(Vector3 ori, Vector3 dir, float mD, string tag)
    260     {
    261         Ray ray = new Ray(ori, dir);
    262         RaycastHit info;
    263         if (Physics.Raycast(ray, out info, mD))
    264         {
    265             if (info.transform.tag == tag)
    266                 return true;
    267         }
    268         return false;
    269     }
    270 
    271     /// <summary>
    272     /// 生成单一房间的轮廓
    273     /// </summary>
    274     /// <param name="centerPos">房间中点位置</param>
    275     /// <param name="length"></param>
    276     /// <param name="width"></param>
    277     /// <param name="parent">父物体</param>
    278     void GenOneRoom(Vector3 centerPos, int length, int width, Transform parent = null)
    279     {
    280         var to = new Vector3(length - 1, FixedUnitHeight - 1, width - 1) * .5f;
    281 
    282         //顶点
    283         var ned = centerPos - to;
    284         var fod = centerPos + to;
    285 
    286         var v3 = new Vector3(ned.x, fod.y, ned.z);
    287         var v4 = new Vector3(ned.x, fod.y, fod.z);
    288         var v5 = new Vector3(ned.x, ned.y, fod.z);
    289 
    290         var v6 = new Vector3(fod.x, ned.y, ned.z);
    291         var v7 = new Vector3(fod.x, ned.y, fod.z);
    292         var v8 = new Vector3(fod.x, fod.y, ned.z);
    293 
    294         //顶点位置(8个)
    295         InsSetPos(ned, parent);
    296         InsSetPos(fod, parent);
    297         InsSetPos(v3, parent);
    298         InsSetPos(v4, parent);
    299         InsSetPos(v5, parent);
    300         InsSetPos(v6, parent);
    301         InsSetPos(v7, parent);
    302         InsSetPos(v8, parent);
    303 
    304         //12条棱(4*3)
    305         //
    306         InsOneEdge(length, ned, Dx, parent);
    307         InsOneEdge(length, v3, Dx, parent);
    308         InsOneEdge(length, v4, Dx, parent);
    309         InsOneEdge(length, v5, Dx, parent);
    310         //
    311         InsOneEdge(FixedUnitHeight, ned, Dy, parent);
    312         InsOneEdge(FixedUnitHeight, v5, Dy, parent);
    313         InsOneEdge(FixedUnitHeight, v6, Dy, parent);
    314         InsOneEdge(FixedUnitHeight, v7, Dy, parent);
    315         //
    316         InsOneEdge(width, ned, Dz, parent);
    317         InsOneEdge(width, v3, Dz, parent);
    318         InsOneEdge(width, v6, Dz, parent);
    319         InsOneEdge(width, v8, Dz, parent);
    320     }
    321 
    322     //生成一条边上的建筑单位但不包含顶点位置
    323     void InsOneEdge(int edge, Vector3 v, Vector3 dir, Transform parent = null)
    324     {
    325         //忽略首尾单位
    326         for (int i = 1; i < edge - 1; i++)
    327         {
    328             InsSetPos(v + i * dir, parent);
    329         }
    330     }
    331 
    332     void InsSetPos(Vector3 pos, Transform parent = null)
    333     {
    334         var ins = Instantiate(BuildUnit);
    335         ins.transform.position = pos;
    336         ins.transform.parent = parent;
    337     }
    338 }

    在MapSystem中可以在房间结构生成完后创建一个默认的数据结构:

     1     public void RandRoomDatas()
     2     {
     3         if (RoomBuilder == null||MapData ==null)
     4             return;
     5 
     6         RoomBuilder.StartCoroutine(RoomBuilder.GenRooms(MapData.MapCenter,()=> 
     7         {
     8             CreatRoomData();
     9             RandRoomCrosses();
    10         }));
    11     }
    12 
    13     void CreatRoomData()
    14     {
    15         for (int i = 1; i < GenRooms.Count + 1; i++)
    16         {
    17             var rd = new RoomData();
    18             rd.Id = i;
    19             rd.RoomTran = GenRooms[i - 1];
    20             rd.BattleType = RoomBattleType.NormalBattle;
    21             if (rd.Id == 1)
    22                 rd.BattleType = RoomBattleType.Rest;
    23             rd.CrossRooms = new List<RoomData>();
    24             rd.Monsters = new List<GameObject>();
    25             rd.bEndRoom = false;
    26             rd.bMainCrossRoom = false;
    27 
    28             MapData.RoomDataDic.Add(rd.Id, rd);
    29         }
    30     }

    效果图:(单层-枚举列表随机)

     单层(全随机-长条形房间随机):

     多层(层数5)(自定义-全随机):

     参考资料:

    https://indienova.com/indie-game-development/rooms-and-mazes-a-procedural-dungeon-generator/?tdsourcetag=s_pctim_aiomsg

    https://mp.weixin.qq.com/s/3yM-mAAXq_fX5tcy82s0uQ

  • 相关阅读:
    TF.VARIABLE和TENSOR的区别(转)
    同步与异步,阻塞与非阻塞的区别
    tensorflow op tf.global_variables_initializer
    iOS viewDidUnload方法
    Objective-C中的@property和@synthesize用法
    UIDatePicker的时间选择器里的时区的问题
    IOS 小技巧积累
    IOS atomic与nonatomic,assign,copy与retain的定义和区别
    XCODE4.6从零开始添加视图
    Xcode无法设置视图的 autosizing control原因
  • 原文地址:https://www.cnblogs.com/koshio0219/p/12604383.html
Copyright © 2011-2022 走看看