protected override void Generate() { Stack <IMazeCell> back_tracker = new Stack <IMazeCell>(); //把起点塞进去 back_tracker.Push(cells[0]); //如果栈空了,表示迷宫完成了。 while (back_tracker.Count > 0) { //寻找栈顶元素 IMazeCell start_node = back_tracker.Peek(); //直接选择出,没访问过,且不连通的点。注意,不连通,但是有可能是已经访问过的,没访问过,一定不连通! EMazeDirection move_dir = start_node.GenRandomNeighbourDirection(ESelectCondition.NoVisited); //如果这个点的周围都已经访问过来,开始回溯,每次遍历回溯一格。直到找到下一个,周围有没访问过的点的节点。 if (move_dir == EMazeDirection.Invalid) { back_tracker.Pop(); continue; } //点周围有没访问过,也没联通的点 start_node.ConnectionTo(move_dir); back_tracker.Push(start_node.GetNeighbour(move_dir)); } }
public override void PostProcess(MazeAlgorithm maze_algorithm) { int size_x = maze_algorithm.size_x; int size_y = maze_algorithm.size_y; for (int iy = 0; iy < size_y; iy++) { for (int ix = 0; ix < size_x; ix++) { IMazeCell cell = maze_algorithm.GetAt(ix, iy); if (cell != null && cell.ConnectionCount == 1 && Random.Range(0.0f, 1.0f) < braidingrate) { for (int i = 0; i < (int)EMazeDirection.DirectionCount; i++) { EMazeDirection dir = (EMazeDirection)i; //尚未联通的点 if (cell.IsConnectedTo(dir) == true) { //只做反向联通,确保不会出现孤点 EMazeDirection inverse_dir = MazeAlgorithm.InvertDirection(dir); IMazeCell invert_cell = cell.GetNeighbour(inverse_dir); if (invert_cell != null) { cell.ConnectionTo(inverse_dir); } } //END OF IF Connected to } //END OF FOR Neighbours } //END OF IF Test Cell } } }
/// <summary> /// From given maze and cell, whose coordinates correlate to a cell in maze, /// its adjacent cells of type wall extracted an returned. /// </summary> /// <param name="maze">Maze as two dimensional array of IMazeCell objects.</param> /// <param name="cell">IMazeCell object.</param> /// <returns>A collection of IMazeCell objects.</returns> private List <IMazeCell> GetAdjacentWallCells(IMazeCell[,] maze, IMazeCell cell) { var neighbours = new List <IMazeCell>(); if (cell.Position.Row - 1 >= 0 && maze[cell.Position.Row - 1, cell.Position.Col].IsWall) { neighbours.Add(maze[cell.Position.Row - 1, cell.Position.Col]); } if (cell.Position.Row + 1 < maze.GetLength(0) && maze[cell.Position.Row + 1, cell.Position.Col].IsWall) { neighbours.Add(maze[cell.Position.Row + 1, cell.Position.Col]); } if (cell.Position.Col - 1 >= 0 && maze[cell.Position.Row, cell.Position.Col - 1].IsWall) { neighbours.Add(maze[cell.Position.Row, cell.Position.Col - 1]); } if (cell.Position.Col + 1 < maze.GetLength(1) && maze[cell.Position.Row, cell.Position.Col + 1].IsWall) { neighbours.Add(maze[cell.Position.Row, cell.Position.Col + 1]); } return(neighbours); }
/// <summary> /// Checks if a cell borders with exactly one path cell, having respectively the rest of its neighbors as walls. /// </summary> /// <param name="maze">Maze as two dimensional array of IMazeCell objects.</param> /// <param name="cell">IMazeCell object.</param> /// <returns>A boolean value, depending on whether the condition is fulfilled.</returns> private bool HasOnlyOneAdjacentPathCell(IMazeCell[,] maze, IMazeCell cell) { int adjacentPathCells = 0; if (cell.Position.Row - 1 >= 0 && !maze[cell.Position.Row - 1, cell.Position.Col].IsWall) { adjacentPathCells++; } if (cell.Position.Row + 1 < maze.GetLength(0) && !maze[cell.Position.Row + 1, cell.Position.Col].IsWall) { adjacentPathCells++; } if (cell.Position.Col - 1 >= 0 && !maze[cell.Position.Row, cell.Position.Col - 1].IsWall) { adjacentPathCells++; } if (cell.Position.Col + 1 < maze.GetLength(1) && !maze[cell.Position.Row, cell.Position.Col + 1].IsWall) { adjacentPathCells++; } return(adjacentPathCells == 1); }
void Kill(int visited, IMazeCell start_point) { if (visited <= cells.Count) { do { EMazeDirection move_dir = start_point.GenRandomNeighbourDirection(ESelectCondition.NoVisited); if (move_dir == EMazeDirection.Invalid) { break; } IMazeCell next = start_point.GetNeighbour(move_dir); start_point.ConnectionTo(move_dir); start_point = next; visited++; }while(true); //finish kill begin hunt. if (visited < cells.Count) { Hunt(visited); } } }
void Hunt(int visited) { IMazeCell hunt_result = null; for (int iy = size_y - 1; iy >= 0; iy--) //for (int iy = 0; iy < size_y;iy++ ) { for (int ix = 0; ix < size_x; ix++) //for (int ix = size_x-1; ix >=0; ix--) { hunt_result = GetAt(ix, iy); //hunt result 必须是一个未访问过的点,并且他要链接一个已经访问过的点(隐含一定不会连接) if (hunt_result.ConnectionCount == 0) { EMazeDirection dir = hunt_result.GenRandomNeighbourDirection(ESelectCondition.Visited); if (dir != EMazeDirection.Invalid) { hunt_result.ConnectionTo(dir); visited++; Kill(visited, hunt_result); break; } } } } }
public IMazeCell[,] InitializeMaze(int HorizontalSize, int VerticalSize) { IMazeCell[,] generatedMaze = new IMazeCell[HorizontalSize, VerticalSize]; for (int i = 0; i < HorizontalSize; i++) { for (int j = 0; j < VerticalSize; j++) { generatedMaze[i, j] = new MazeCell(); generatedMaze[i, j].Value = (int)MazeCellValueEnum.Wall; generatedMaze[i, j].PositionX = i; generatedMaze[i, j].PositionY = j; if (i == 0) { generatedMaze[i, j].Value = (int)MazeCellValueEnum.WallBorder; } if (j == 0) { generatedMaze[i, j].Value = (int)MazeCellValueEnum.WallBorder; } if (i == HorizontalSize - 1) { generatedMaze[i, j].Value = (int)MazeCellValueEnum.WallBorder; } if (j == VerticalSize - 1) { generatedMaze[i, j].Value = (int)MazeCellValueEnum.WallBorder; } } } return(generatedMaze); }
/// <summary> /// 注意:该算法对不规则图形非常不友好,如果一定要应用到不规则图形 /// 需要做很多修改,因此建议直接禁止本算法应用到不规则图形上去。 /// </summary> protected override void Generate() { List <IMazeCell> temp_cell_collection = new List <IMazeCell>(); List <EMazeDirection> filter_dir = new List <EMazeDirection>(); filter_dir.Add(EMazeDirection.North); filter_dir.Add(EMazeDirection.East); for (int iy = 0; iy < size_y; iy++) { for (int ix = 0; ix < size_x; ix++) { IMazeCell cell = GetAt(ix, iy); //尽管如此,还是可以利用fiter做一波优化,去掉重复代码! EMazeDirection move_dir = cell.GenRandomNeighbourDirection(ESelectCondition.None, filter_dir); if (move_dir == EMazeDirection.North) { temp_cell_collection.Add(cell); IMazeCell dig_cell = temp_cell_collection[Random.Range(0, temp_cell_collection.Count)]; dig_cell.ConnectionTo(EMazeDirection.North); temp_cell_collection.Clear(); } else if (move_dir == EMazeDirection.East) { temp_cell_collection.Add(cell); cell.ConnectionTo(EMazeDirection.East); } } } }
/// <summary> /// 返回值可以为Null,null表示邻居为迷宫边界,或是邻居没有被初始化 /// </summary> /// <param name="direction"></param> /// <returns>null means no neighbour or not successefully inited.</returns> public IMazeCell GetNeighbour(EMazeDirection direction) { IMazeCell output = null; neighbours.TryGetValue(direction, out output); return(output); }
protected void Infect(int new_group_id, IMazeCell to) { int old_group_id = to.GroupID; Stack <IMazeCell> infect_stack = new Stack <IMazeCell>(); to.GroupID = new_group_id; infect_stack.Push(to); //if stack is not null. while (infect_stack.Count > 0) { //find stack top IMazeCell top = infect_stack.Pop(); List <IMazeCell> neighbours = top.Neighbours; //for all top`s neighbours. for (int i = 0; i < neighbours.Count; i++) { //if belong to old group. if (neighbours[i].GroupID == old_group_id) { //merge to new group go on to find with it`s neighbours untill no new neighbour is added. neighbours[i].GroupID = new_group_id; infect_stack.Push(neighbours[i]); } } } }
protected override void Generate() { IMazeCell random_start = GetRandomCell(); int visited = 1; while (visited < cells.Count) { EMazeDirection valid = random_start.GenRandomNeighbourDirection(); IMazeCell pending_next = random_start.GetNeighbour(valid); if (pending_next != null) { //言外之意,没被访问过 //means, not visited. if (pending_next.ConnectionCount == 0) { random_start.ConnectionTo(valid); random_start = pending_next; visited++; } else { random_start = pending_next; continue; } } } }
public void BuildMaze <T>(int x_size, int y_size) where T : IMazeCell { this.size_x = x_size; this.size_y = y_size; cells.Capacity = size_x * size_y; int group_id = 0; //FIRST PASS for (int iy = 0; iy < size_y; iy++) { for (int ix = 0; ix < size_x; ix++) { if (maze_mask_cells != null && maze_mask_cells.Contains(SharedUtil.PointHash(ix, iy))) { cells.Add(null); } else { T cell = System.Activator.CreateInstance <T>(); cell.X = ix; cell.Y = iy; cell.GroupID = group_id++; cells.Add(cell); } } } //SECOND PASS for (int iy = 0; iy < size_y; iy++) { for (int ix = 0; ix < size_x; ix++) { IMazeCell cell = GetAt(ix, iy); if (cell != null) { IMazeCell[] neighbours = new IMazeCell[4]; neighbours[(int)EMazeDirection.North] = GetAt(ix, iy + 1); neighbours[(int)EMazeDirection.South] = GetAt(ix, iy - 1); neighbours[(int)EMazeDirection.West] = GetAt(ix - 1, iy); neighbours[(int)EMazeDirection.East] = GetAt(ix + 1, iy); cell.SetNeighbours(neighbours); } } } Generate(); for (int i = 0; i < post_processer.Count; i++) { if (post_processer[i] != null) { post_processer[i].PostProcess(this); } } }
//1-寻找任意点A,作为目标点,标记为Visited。 //2-寻找任意点B,作为起始点。 //3-从B寻找A,找到非闭合路径,将路径挖通,并且标记为Visited //4-遇到闭合路径,从新挖。 //5-随机找B2,重复过程 //6-直到所有的点都被访问过 protected override void Generate() { //注意,一个格子,要么在Unvisited 里面,要么在Visited里面 //所以这里不需要两个数组,实际上,Visited的记录是毫无意义的。 //更重要的是Unvisited里面还剩什么。 //而判断 visited.Contain( x ) 的等价命题是 unvisited.Contain( x ) == false //这样起码可以节省一半的内存空间 List <IMazeCell> unvisited = new List <IMazeCell>(cells); List <IMazeCell> temp_path = new List <IMazeCell>(); IMazeCell first = unvisited[Random.Range(0, unvisited.Count)]; unvisited.Remove(first); IMazeCell random_start = unvisited[Random.Range(0, unvisited.Count)]; while (unvisited.Count > 0) { temp_path.Clear(); temp_path.Add(random_start); while (true) { //如果有强烈需求,可以考虑增加接口,暂时先这样做。 EMazeDirection dir = temp_path[temp_path.Count - 1].GenRandomNeighbourDirection(); IMazeCell next = temp_path[temp_path.Count - 1].GetNeighbour(dir); //没有形成环路 if (unvisited.Contains(next) == false) { //开始联通了 temp_path.Add(next); for (int i = 0; i < temp_path.Count - 1; i++) { unvisited.Remove(temp_path[i]); temp_path[i].ConnectionTo(temp_path[i].LastRandomNeibourDirection); } if (unvisited.Count > 0) { random_start = unvisited[Random.Range(0, unvisited.Count)]; } break; } //形成了环路 else if (temp_path.Contains(next) == true) { break; } temp_path.Add(next); } } }
protected override void Generate() { //Use GroupID as COST !!!! List <IMazeCell> actived = new List <IMazeCell>(cells); //Make sure each cell has different priority. while (actived.Count > 1) { IMazeCell random = actived[Random.Range(0, actived.Count)]; random.GroupID = actived.Count + 1; actived.Remove(random); } List <IMazeCell> candidate = new List <IMazeCell>(actived[0].Neighbours); List <EMazeDirection> candidate_connect_direction = new List <EMazeDirection>((int)EMazeDirection.DirectionCount); //actived now has only one element in it, active[0]. it do not need to have a priority while (actived.Count < cells.Count) { IMazeCell min = candidate[0]; for (int i = 0; i < candidate.Count; i++) { if (min.GroupID > candidate[i].GroupID) { min = candidate[i]; } } candidate.Remove(min); candidate_connect_direction.Clear(); for (int i = 0; i < (int)EMazeDirection.DirectionCount; i++) { EMazeDirection dir = (EMazeDirection)i; IMazeCell neighbour = min.GetNeighbour(dir); if (neighbour != null) { if (actived.Contains(neighbour) == true) { candidate_connect_direction.Add(dir); } else { if (candidate.Contains(neighbour) == false) { candidate.Add(neighbour); } } } } min.ConnectionTo(candidate_connect_direction[Random.Range(0, candidate_connect_direction.Count)]); actived.Add(min); } }
protected override void Generate() { List <IMazeCell> actived = new List <IMazeCell>(); actived.Add(GetRandomCell()); List <EMazeDirection> candidate_connect_direction = new List <EMazeDirection>((int)EMazeDirection.DirectionCount); while (actived.Count > 0) { IMazeCell random = null; switch (shample_type) { case EGrowingTreeShampleType.Rand: random = actived[Random.Range(0, actived.Count)]; break; case EGrowingTreeShampleType.Last: random = actived[actived.Count - 1]; break; case EGrowingTreeShampleType.Rand_Last: random = Random.Range(0, 2) == 0? actived[Random.Range(0, actived.Count)]: actived[actived.Count - 1]; break; } candidate_connect_direction.Clear(); for (int i = 0; i < (int)EMazeDirection.DirectionCount; i++) { EMazeDirection dir = (EMazeDirection)i; IMazeCell neighbour = random.GetNeighbour(dir); if (neighbour != null && neighbour.ConnectionCount == 0) { candidate_connect_direction.Add(dir); } } if (candidate_connect_direction.Count > 0) { EMazeDirection select_dir = candidate_connect_direction[Random.Range(0, candidate_connect_direction.Count)]; actived.Add(random.GetNeighbour(select_dir)); random.ConnectionTo(select_dir); } else { actived.Remove(random); } } }
/// <summary> /// 研究这个算法的时候,遇到了一些坑 /// 主要是我想偷懒,一开始,没用到记录使用过的 连接点的策略 /// 而是试图,用算法算出来 /// 但是,不论通过:A - 统计连接,B-统计GroupID是否一致,都无法正确的算出一个点,是否被用过。 /// 如果 /// /// 1|1 /// 1 1 /// /// 用GroupID来判断。很有可能一个没用过的点,被当成用过的了。错误 /// 用Connection来判断。一个已经用过的点,会反复被当成没用过的来多次计算。 /// 于是,最终还是回到了相对浪费空间的一种算法。那就是 /// /// 用两个Int型数组,记录所有使用过的连接点的 Hash结果。然后下次寻找的时候,发现已经用过的,直接跨过。 /// 事实上我们必须这么做,否则就算你记录每个Group为一个List,也不能保证不犯上面的错误。除非,你记录两套GroupLists /// 一套为水平扫描准备。 /// 一套为垂直扫描准备。 /// 但是这两套,空间消耗都太大,并且反复创建List,GC开销也是蛮大的。所以最终结果,还是用现在的方式。 /// /// 分析一下,这种算法不是使用随机连接某个点的方式计算迷宫的,所以不适合任意形状的迷宫 /// 但是,他特别适合生成 Waving Maze /// </summary> protected override void Generate() { int horizon_merge = size_x - 1; int vertical_merge = size_y - 1; List <int> used_horizon = new List <int>(); List <int> used_vertical = new List <int>(); //先横向融合,再纵向融合,为一个Loop,知道所有的格子都被合在一起。 while (horizon_merge > 0 || vertical_merge > 0) { if (horizon_merge > 0) { //horizon merge,loop every row for (int i = 0; i < size_y; i++) { int rand_num = Random.Range(0, horizon_merge); IMazeCell start_merge = FindRandomMergeStartCell(rand_num, true, i, used_horizon); used_horizon.Add(SharedUtil.PointHash(start_merge.X, start_merge.Y)); if (start_merge.GroupID != start_merge.GetNeighbour(EMazeDirection.East).GroupID) { Infect(start_merge.GroupID, start_merge.GetNeighbour(EMazeDirection.East)); start_merge.ConnectionTo(EMazeDirection.East); } } horizon_merge--; } if (vertical_merge > 0) { for (int i = 0; i < size_x; i++) { int rand_num = Random.Range(0, vertical_merge); IMazeCell start_merge = FindRandomMergeStartCell(rand_num, false, i, used_vertical); used_vertical.Add(SharedUtil.PointHash(start_merge.X, start_merge.Y)); if (start_merge.GroupID != start_merge.GetNeighbour(EMazeDirection.North).GroupID) { Infect(start_merge.GroupID, start_merge.GetNeighbour(EMazeDirection.North)); start_merge.ConnectionTo(EMazeDirection.North); } } vertical_merge--; } } }
public override void PostProcess(MazeAlgorithm maze_algorithm) { int size_x = maze_algorithm.size_x; int size_y = maze_algorithm.size_y; for (int iy = 0; iy < size_y; iy++) { for (int ix = 0; ix < size_x; ix++) { IMazeCell cell = maze_algorithm.GetAt(ix, iy); //Dead Ends if (cell != null && cell.ConnectionCount == 1 && Random.Range(0.0f, 1.0f) < braidingrate) { bool processed = false; for (int i = 0; i < (int)EMazeDirection.Invalid; i++) { EMazeDirection dir = (EMazeDirection)i; //尚未联通的点 if (cell.IsConnectedTo(dir) == true) { //只做反向联通,确保不会出现孤点 EMazeDirection inverse_dir = MazeAlgorithm.InvertDirection(dir); IMazeCell invert_cell = cell.GetNeighbour(inverse_dir); if (invert_cell != null) { cell.ConnectionTo(inverse_dir); processed = true; } } //END OF IF Connected to } //END OF FOR Neighbours if (processed == false) { EMazeDirection connect_dir = cell.GenRandomNeighbourDirection(ESelectCondition.NoConnected); if (connect_dir != EMazeDirection.Invalid) { cell.ConnectionTo(connect_dir); } } } } } }
GameObject CreateMazeCellObject(IMazeCell cell_def) { List <EMazeDirection> connections = new List <EMazeDirection>(); for (int i = 0; i < (int)EMazeDirection.DirectionCount; i++) { if (cell_def.IsConnectedTo((EMazeDirection)i)) { connections.Add((EMazeDirection)i); } } MazePrefab match = null; foreach (var candidate in config.cell_list) { if (candidate.match_direction.Count == connections.Count) { bool full_match = true; foreach (var test_dir in connections) { if (candidate.match_direction.Contains(test_dir) == false) { full_match = false; break; } } if (full_match) { //match match = candidate; break; } } } GameObject result = Object.Instantiate(match.prefab); result.transform.SetParent(map_root); result.transform.localPosition = new Vector3(cell_def.X * config.grid_size, 0, cell_def.Y * config.grid_size); return(result); }
protected override void Generate() { List <IMazeCell> actived = new List <IMazeCell>(cells.Count); IMazeCell first = GetRandomCell(); actived.Add(first); //加入First 的有效Neighbour作为第一波的Candidate List <IMazeCell> candidate = new List <IMazeCell>(first.Neighbours); List <EMazeDirection> candidate_connect_direction = new List <EMazeDirection>((int)EMazeDirection.DirectionCount); //只要所有的格子没有被全部访问。 while (actived.Count < cells.Count) { IMazeCell random = candidate[Random.Range(0, candidate.Count)]; candidate.Remove(random); candidate_connect_direction.Clear(); for (int i = 0; i < (int)EMazeDirection.DirectionCount; i++) { EMazeDirection dir = (EMazeDirection)i; IMazeCell neighbour = random.GetNeighbour(dir); if (neighbour != null) { if (actived.Contains(neighbour) == true) { candidate_connect_direction.Add(dir); } else { if (candidate.Contains(neighbour) == false) { candidate.Add(neighbour); } } } } random.ConnectionTo(candidate_connect_direction[Random.Range(0, candidate_connect_direction.Count)]); actived.Add(random); } }
/// <summary> /// 寻找一个随机的,还没用过的,连接点 /// </summary> /// <param name="rand_num">随机数,随机数越来越小,因为可选择的随机起始点,会随着融合越来越少</param> /// <param name="is_row">true:水平。false:垂直</param> /// <param name="index">is_row:true 传入行索引(y),否则传入列索引(x)</param> /// <param name="used"> is_row:true 传入用过的水平连接点。否则传入用过的垂直连接点。</param> /// <returns>随机的,没用过的连接点</returns> IMazeCell FindRandomMergeStartCell(int rand_num, bool is_row, int index, List <int> used) { IMazeCell start_cell = is_row ? GetAt(0, index) : GetAt(index, 0); EMazeDirection dir = is_row ? EMazeDirection.East : EMazeDirection.North; do { while (used.Contains(SharedUtil.PointHash(start_cell.X, start_cell.Y))) { start_cell = start_cell.GetNeighbour(dir); } if (rand_num == 0) { return(start_cell); } start_cell = start_cell.GetNeighbour(dir); rand_num--; }while (rand_num >= 0); Debug.LogError("Error this should not happen!!"); return(null); }
/// <summary> /// 这个算法同样不能胜任,不规则格子的迷宫。 /// 因为他会产生孤立点。 /// </summary> protected override void Generate() { List <EMazeDirection> dir_filter = new List <EMazeDirection>(); dir_filter.Add(EMazeDirection.North); dir_filter.Add(EMazeDirection.East); for (int iy = 0; iy < size_y; iy++) { for (int ix = 0; ix < size_x; ix++) { IMazeCell cell = GetAt(ix, iy); //算法优化,不能每次都判断是不是在墙角,那种判断对于不规则迷宫是无效的,且麻烦的。 //如果只希望沿着某两个方向扩展,更科学的方式是使用DirectionFilter 这样可以方便的产生更多的选择组合。 EMazeDirection move_to_dir = cell.GenRandomNeighbourDirection(ESelectCondition.None, dir_filter); if (move_to_dir != EMazeDirection.DirectionCount) { cell.ConnectionTo(move_to_dir); } } } }
protected override void Generate() { IMazeCell random_start = GetRandomCell(); List <IMazeCell> unvisited = new List <IMazeCell>(cells); unvisited.Remove(random_start); //前半段,用AldourBroder while (unvisited.Count > cells.Count / 2) { EMazeDirection valid = random_start.GenRandomNeighbourDirection(); IMazeCell pending_next = random_start.GetNeighbour(valid); if (pending_next != null) { //言外之意,没被访问过 //means, not visited. if (pending_next.ConnectionCount == 0) { random_start.ConnectionTo(valid); random_start = pending_next; unvisited.Remove(random_start); } else { random_start = pending_next; continue; } } } //后半段,用Wilson List <IMazeCell> temp_path = new List <IMazeCell>(); random_start = unvisited[Random.Range(0, unvisited.Count)]; while (unvisited.Count > 0) { temp_path.Clear(); temp_path.Add(random_start); while (true) { //如果有强烈需求,可以考虑增加接口,暂时先这样做。 EMazeDirection dir = temp_path[temp_path.Count - 1].GenRandomNeighbourDirection(); IMazeCell next = temp_path[temp_path.Count - 1].GetNeighbour(dir); //没有形成环路 if (unvisited.Contains(next) == false) { //开始联通了 temp_path.Add(next); for (int i = 0; i < temp_path.Count - 1; i++) { unvisited.Remove(temp_path[i]); temp_path[i].ConnectionTo(temp_path[i].LastRandomNeibourDirection); } if (unvisited.Count > 0) { random_start = unvisited[Random.Range(0, unvisited.Count)]; } break; } //形成了环路 else if (temp_path.Contains(next) == true) { break; } temp_path.Add(next); } } }
/// <summary> /// 不是特别完美,和map_data产生了耦合,不过只把他当成内部类,也无妨,只不过,其他类调用的时候,返回的是这个类的成员变量而不是临时变量! /// </summary> /// <returns></returns> public TileMapData GenerateTileMapData() { //重置 TileMapData temp_data = new TileMapData(); config.theme_config.RebuildTileThemeConfig(); int tile_size_x = config.tile_size_x; int tile_size_y = config.tile_size_y; int total_thickness = config.wall_thickness + config.road_thickness; //初始化地图 for (int iy = 0; iy < tile_size_y; iy++) { for (int ix = 0; ix < tile_size_x; ix++) { int key = SharedUtil.PointHash(ix, iy); temp_data[key] = config.theme_config.GetTilePrefabConfigIndex(config.road_name); } } MazeAlgorithm algorithm = (MazeAlgorithm)System.Activator.CreateInstance(System.Type.GetType("TileMazeMaker.Algorithm.Maze." + config.maze_algorithm.ToString())); //处理Mask algorithm.SetMazeMaskCells(config.maze_mask); //设置后期处理 for (int i = 0; i < config.post_process.Count; i++) { if (config.post_process[i] != EMazePostProcess.None) { algorithm.AddPostProcesser(config.post_process[i].ToString()); } } algorithm.BuildMaze <MazeCell>(config.width, config.height); dig_list.Add(DigNorth); dig_list.Add(DigWest); dig_list.Add(DigSouth); dig_list.Add(DigEast); for (int iy = 0; iy < config.height; iy++) { for (int ix = 0; ix < config.width; ix++) { IMazeCell cell = algorithm.GetAt(ix, iy); if (cell != null) { TileRect out_rect = new TileRect( ix * total_thickness, iy * total_thickness, config.road_thickness + 2 * config.wall_thickness, config.road_thickness + 2 * config.wall_thickness); out_rect.SetMapTileType(temp_data, config.theme_config, config.wall_name); TileRect rect = new TileRect( ix * total_thickness + config.wall_thickness, iy * total_thickness + config.wall_thickness, config.road_thickness, config.road_thickness); rect.SetMapTileType(temp_data, config.theme_config, config.road_name); for (int i = 0; i < (int)EMazeDirection.DirectionCount; i++) { if (cell.IsConnectedTo((EMazeDirection)i)) { dig_list[i](temp_data, rect); } } } } } return(temp_data); }
public EMazeDirection GenRandomNeighbourDirection(ESelectCondition condition = ESelectCondition.None, List <EMazeDirection> direction_filter = null) { List <EMazeDirection> candidate = new List <EMazeDirection>(); foreach (var key in neighbours.Keys) { //Debug:注意要判断target是不是visited,而不是自己! IMazeCell target = neighbours[key]; switch (condition) { case ESelectCondition.None: candidate.Add(key); break; case ESelectCondition.NoConnected: if (IsConnectedTo(key) == false) { candidate.Add(key); } break; case ESelectCondition.NoVisited: if (target.ConnectionCount == 0) { candidate.Add(key); } break; case ESelectCondition.Connected: if (IsConnectedTo(key) == true) { candidate.Add(key); } break; case ESelectCondition.Visited: if (target.ConnectionCount > 0) { candidate.Add(key); } break; case ESelectCondition.VisitedConnected: if (IsConnectedTo(key) == true && target.ConnectionCount > 0) { candidate.Add(key); } break; } } //追加Filter 使得 随机筛选只能从指定方向中筛选。 if (direction_filter != null && candidate.Count > 0) { for (int i = candidate.Count - 1; i >= 0; i--) { if (direction_filter.Contains(candidate[i]) == false) { candidate.Remove(candidate[i]); } } } //albour-broder算法需要,因此,得,保存这个值 random_select_direction = candidate.Count == 0 ? EMazeDirection.Invalid : candidate[Random.Range(0, candidate.Count)]; return(random_select_direction); }
protected override void Generate() { foreach (var cell in cells) { cell.GroupID = 0; } int global_group_id = 1; for (int row_id = size_y - 1; row_id >= 0; row_id--) { //init_group_id for (int ix = 0; ix < size_x; ix++) { IMazeCell cell = GetAt(ix, row_id); if (cell.GroupID == 0) { cell.GroupID = global_group_id++; } } if (row_id > 0) { //try merge randomly int pointer = 0; while (pointer < size_x - 1) { if (Random.Range(0, 2) == 0) { IMazeCell from = GetAt(pointer, row_id); IMazeCell to = GetAt(pointer + 1, row_id); if (from.GroupID != to.GroupID) { Infect(from.GroupID, to); from.ConnectionTo(EMazeDirection.East); } } pointer++; } //try grouth to north List <IMazeCell> temp_list = new List <IMazeCell>(); for (int ix = 0; ix < size_x; ix++) { temp_list.Add(GetAt(ix, row_id)); if (ix + 1 == size_x || (ix + 1 < size_x && GetAt(ix, row_id).GroupID != GetAt(ix + 1, row_id).GroupID)) { int rand_times = Random.Range(0, temp_list.Count); if (rand_times == 0) { rand_times = 1; } while (rand_times > 0) { IMazeCell rand = temp_list[Random.Range(0, temp_list.Count)]; rand.ConnectionTo(EMazeDirection.South); rand.GetNeighbour(EMazeDirection.South).GroupID = rand.GroupID; temp_list.Remove(rand); rand_times--; } temp_list.Clear(); } } } else //编筐编篓,全在收口. { //seal all cells for (int ix = 0; ix < size_x - 1; ix++) { IMazeCell from = GetAt(ix, row_id); IMazeCell to = GetAt(ix + 1, row_id); if (from.GroupID != to.GroupID) { from.ConnectionTo(EMazeDirection.East); Infect(from.GroupID, to); } } } } DebugMazeGroupID(); }
/// <summary> /// From given maze and coordinates correlating to a cell in maze, /// its adjacent cells, which are not backtracked yet, are extracted an returned as a collection. /// </summary> /// <param name="maze">Maze as two dimensional array of IMazeCell objects.</param> /// <param name="cell">IMazeCell object.</param> /// <returns>A collection of IMazeCell objects.</returns> private IList <BacktrackerCell> GetUnvisitedNeighbours(BacktrackerCell[,] maze, IMazeCell cell) { var unvisitedNeighbours = new List <BacktrackerCell>(); var row = cell.Position.Row; var col = cell.Position.Col; if (row - 1 >= 1 && !maze[row - 1, col].IsBacktracked) { unvisitedNeighbours.Add(maze[row - 1, col]); } if (row + 1 < maze.GetLength(0) - 1 && !maze[row + 1, col].IsBacktracked) { unvisitedNeighbours.Add(maze[row + 1, col]); } if (col - 1 >= 1 && !maze[row, col - 1].IsBacktracked) { unvisitedNeighbours.Add(maze[row, col - 1]); } if (col + 1 < maze.GetLength(1) - 1 && !maze[row, col + 1].IsBacktracked) { unvisitedNeighbours.Add(maze[row, col + 1]); } return(unvisitedNeighbours); }