예제 #1
0
파일: Generate.cs 프로젝트: hnjm/TileMap2D
        //private static IEnumerator CreateTunnels(IVector2 _entryPt) //UNITY
        private static void CreateTunnels(IVector2 _entryPt)
        {
            var map    = m_Tilemap.m_MapData;
            var points = new List <Point2D>();

            foreach (var room in m_Tilemap.m_Rooms)
            {
                points.Add(new Point2D(room.Anchor.x, room.Anchor.y));
            }

            var dt   = new DelaunayTriangulation(points);
            var tris = dt.Triangulate(); //TODO Creates null on seed 22

            if (tris == null)
            {
                m_Tilemap.m_Tunnels = null;
                //yield break; //UNITY
            }

            var roomGraph = new ioGraph <IVector2>();

            foreach (var tri in tris)
            {
                var p1 = new IVector2((int)tri.a.x, (int)tri.a.y);
                var p2 = new IVector2((int)tri.b.x, (int)tri.b.y);
                var p3 = new IVector2((int)tri.c.x, (int)tri.c.y);

                roomGraph.AddEdge(p1, p2, m_Random.NextDouble() * 100d);
                roomGraph.AddEdge(p2, p1, m_Random.NextDouble() * 100d);
                roomGraph.AddEdge(p2, p3, m_Random.NextDouble() * 100d);
                roomGraph.AddEdge(p3, p2, m_Random.NextDouble() * 100d);
                roomGraph.AddEdge(p1, p3, m_Random.NextDouble() * 100d);
                roomGraph.AddEdge(p3, p1, m_Random.NextDouble() * 100d);
            }

            var roomMST = roomGraph.PrimMST();


            //Get extra room connections beyond mst and add them to the graph

            var extTunnelPct = (Settings.ExtraTunnelMinPct +
                                (Settings.ExtraTunnelMaxPct - Settings.ExtraTunnelMinPct) * m_Random.NextDouble());
            var remEdgeAddCnt = (int)((roomGraph.EdgeCount - roomMST.EdgeCount) * extTunnelPct);

            Msg.LogDebug(TAG_DEBUG, "Room MST:", MsgPriLvl.HIGH);
            Msg.LogDebug(TAG_DEBUG, roomMST.ToString(), MsgPriLvl.HIGH);


            var remAvailEdges = roomGraph.GetNodeConnectionsList();

            foreach (var connection in roomMST.GetNodeConnectionsList())
            {
                if (remAvailEdges.Contains(connection))
                {
                    remAvailEdges.Remove(connection);
                }
                if (remAvailEdges.Contains(connection.Swapped))
                {
                    remAvailEdges.Remove(connection.Swapped);
                }
            }


            if (remEdgeAddCnt > remAvailEdges.Count)
            {
                Msg.LogDebug(TAG_DEBUG,
                             "Additional Edge count (beyond MST) greater than available edges remaining.  Trimming",
                             MsgPriLvl.HIGH);
                remEdgeAddCnt = remAvailEdges.Count;
            }

            for (var i = 0; i < remEdgeAddCnt; ++i)
            {
                var connection = remAvailEdges[m_Random.Next(remAvailEdges.Count)];

                var edge = new ioGraph <IVector2> .ioGraphEdge(1, connection.v2);

                roomMST.AddEdge(connection.v1, edge);
                remAvailEdges.Remove(connection);
            }

            Msg.LogDebug(TAG_DEBUG, "Room MST (with extra conns):", MsgPriLvl.HIGH);
            Msg.LogDebug(TAG_DEBUG, roomMST.ToString(), MsgPriLvl.HIGH);


            Msg.LogDebug(TAG_DEBUG, roomMST.GetEdgeDesc(), MsgPriLvl.LOW);

            //Create tunnel paths
            m_Tilemap.m_Tunnels = new List <TunnelNetwork>();

            var logMsg = "Creating Tunnels";

            Msg.Log(LOGKEY_MESSAGES, LOGKEY_MESSAGES, logMsg, MsgPriLvl.HIGH);
            var edgesDone = 0;

            double debugRoutingTime = 0;
            double debugAStarTime   = 0;

            for (var nodeIdx = 0; nodeIdx < roomMST.NodeCount; ++nodeIdx)
            {
                foreach (var edge in roomMST.GetConnectionsFast(nodeIdx))
                {
                    var fromVector = roomMST.GetNode(nodeIdx);
                    var toVector   = roomMST.GetNode(edge.ToNode);
                    Progress = 0.5d + (edgesDone / (double)roomMST.EdgeCount) / 2d;
                    logMsg   = "Creating Tunnels " + (int)((edgesDone / (float)roomMST.EdgeCount) * 100);
                    //Log(logMsg);
                    Msg.Log(LOGKEY_MESSAGES, LOGKEY_MESSAGES, logMsg, MsgPriLvl.HIGH);

                    var roomsToConnect = new[] { m_Tilemap.m_Rooms.Get(fromVector), m_Tilemap.m_Rooms.Get(toVector) };
                    Msg.LogDebug(TAG_DEBUG, fromVector + " -> " + toVector, MsgPriLvl.MED);

                    if (roomsToConnect[0] == null || roomsToConnect[1] == null)
                    {
                        throw new NullReferenceException(TAG_DEBUG + ":Room not found in roomGroup.");
                    }

                    //Find closest tunnel tie if exists =========================================
                    //If Rooms are already connected  then skip
                    var fromNets = new List <TunnelNetwork>();
                    var toNets   = new List <TunnelNetwork>();

                    var skipConnection = false;
                    foreach (var tNet in m_Tilemap.m_Tunnels)
                    {
                        if (tNet.ConnectsTo(roomsToConnect[0]))
                        {
                            fromNets.Add(tNet);
                        }
                        if (tNet.ConnectsTo(roomsToConnect[1]))
                        {
                            toNets.Add(tNet);
                        }
                    }

                    if (fromNets.Any(toNets.Contains))
                    {
                        skipConnection = true;
                    }

                    if (skipConnection)
                    {
                        Msg.LogDebug(TAG_DEBUG, "Rooms already connected by same Net... Skipping", MsgPriLvl.MED);
                        edgesDone++;
                        continue;
                    }


                    if (Settings.ClosestConnect)
                    {
                        var fromCoordsf = new HashSet <IVector2>();
                        var toCoordsf   = new HashSet <IVector2>();

                        //Get all coords of from and to nets (exluding room doorways)
                        foreach (var net in fromNets)
                        {
                            fromCoordsf.UnionWith(net.GetAllPathCoords(true));
                        }
                        foreach (var net in toNets)
                        {
                            toCoordsf.UnionWith(net.GetAllPathCoords(true));
                        }

                        //Remove room wall coordinates
                        foreach (var room in m_Tilemap.m_Rooms)
                        {
                            fromCoordsf.RemoveWhere(_coord => room.GetWallCoords(true).Contains(_coord));
                            toCoordsf.RemoveWhere(_coord => room.GetWallCoords(true).Contains(_coord));
                        }

                        //Add anchors of rooms to connect
                        fromCoordsf.Add(fromVector);
                        toCoordsf.Add(toVector);

                        //Use Manhattan Distance for distance calc
                        var distance            = AStar2D.ManhattanDistance(fromVector, toVector, 1);
                        var closestTunnelCoords =
                            Support2D.GetNearestCoords(fromCoordsf, toCoordsf, ref distance);
                        if (closestTunnelCoords[0] != null)
                        {
                            if (!closestTunnelCoords[0].Value.Equals(fromVector))
                            {
                                roomsToConnect[0] = null;
                                fromVector        = closestTunnelCoords[0].Value;
                            }
                        }

                        if (closestTunnelCoords[1] != null)
                        {
                            if (!closestTunnelCoords[1].Value.Equals(toVector))
                            {
                                roomsToConnect[1] = null;
                                toVector          = closestTunnelCoords[1].Value;
                            }
                        }
                    }


                    Msg.LogDebug(TAG_DEBUG, "Creating Routing Cost Map.", MsgPriLvl.MED);
                    var routingTimeStamp = DateTime.Now;
                    var costGrid         = CreateRoutingCostMap(roomsToConnect.ToList(), new IVector2(map.Dims.x, map.Dims.y),
                                                                Settings.TunnelBuffer, Settings.TunnelPathMag, Settings.CalcRoutingStrength);
                    debugRoutingTime += (DateTime.Now - routingTimeStamp).TotalSeconds;
                    Msg.LogDebug(TAG_DEBUG,
                                 "Rounting map finished. Took " + (DateTime.Now - routingTimeStamp).TotalSeconds + " seconds.",
                                 MsgPriLvl.MED);

                    //UNITY DEBUG

                    /*
                     * // Unity Draw routing map to texture
                     *
                     *
                     *
                     * //Clear texture to default weight
                     *
                     *
                     * var texture = (Texture2D)TileMap2D.meshRenderer.material.mainTexture;
                     * if (!texture)
                     * {
                     *
                     *  texture = new Texture2D(costGrid.Dims.x, costGrid.Dims.y);
                     *  texture.filterMode = FilterMode.Point;
                     *  TileMap2D.meshRenderer.material.mainTexture = texture;
                     *  if (costGrid.Dims.x > costGrid.Dims.y)
                     *      TileMap2D.instance.transform.localScale = new Vector3(1, 0, costGrid.Dims.y / (float)costGrid.Dims.x);
                     *  else
                     *      TileMap2D.instance.transform.localScale = new Vector3(costGrid.Dims.x / (float)costGrid.Dims.y, 1, 1);
                     * }
                     * if (true)
                     * {
                     *
                     *  var defCost = Settings.CalcRoutingStrength * 2d + 1;
                     *  var weightMax = (defCost + defCost * Settings.TunnelBuffer);
                     *
                     *  var weights = costGrid.Weights;
                     *  for (int y = 0; y < costGrid.Dims.y; ++y)
                     *      for (int x = 0; x < costGrid.Dims.x; ++x)
                     *      {
                     *          double weight = weights[x, y];
                     *          float whiteLevel = (float)(weight / defCost);
                     *          var color = new Color(whiteLevel / 2f, whiteLevel / 2f, whiteLevel / 2f, 1f);
                     *          if (whiteLevel > 1f)
                     *          {
                     *              whiteLevel = (float)(weight - defCost) / (float)(weightMax - defCost);
                     *              whiteLevel = (whiteLevel / 2f + 0.5f);
                     *              color = new Color(whiteLevel, whiteLevel, whiteLevel, 1f);
                     *          }
                     *          texture.SetPixel(x, y, color);
                     *      }
                     *
                     *  var doors = new HashSet<IVector2>();
                     *  foreach (var tNet in m_Tilemap.m_Tunnels)
                     *      foreach (var room in tNet.ConnectedRooms)
                     *          if (room != null) doors.UnionWith(room.Doorways);
                     *
                     *  foreach (var doorway in doors)
                     *      texture.SetPixel(doorway.x, doorway.y, new Color(0f, 0f, 1f, 1f));
                     *
                     *  texture.Apply();
                     *
                     *  yield return null;
                     * }
                     * // --------------------------
                     *///END UNITY BLOCK


                    Msg.LogDebug(TAG_DEBUG, "Running AStar algorithm...", MsgPriLvl.MED);
                    routingTimeStamp = DateTime.Now;
                    var routingStr = Settings.CalcRoutingStrength;
                    var turnCost   = Settings.CalcRoutingStrength * Settings.CalcTurnCost;
                    if (routingStr == 0)
                    {
                        turnCost = Settings.CalcTurnCost;
                    }

                    /*yield return  //UNITY
                     *  TileMap2D.instance.StartCoroutine(AStar2D.AStar(costGrid, fromVector, toVector,
                     *      turnCost, Settings.TunnelPathMag,
                     *      AStar2D.ManhattanDistance));
                     */
                    AStar2D.AStar(costGrid, fromVector, toVector, turnCost, Settings.TunnelPathMag,
                                  AStar2D.ManhattanDistance);
                    debugAStarTime += (DateTime.Now - routingTimeStamp).TotalSeconds;
                    Msg.LogDebug(TAG_DEBUG,
                                 "AStar finished. Took " + (DateTime.Now - routingTimeStamp).TotalSeconds + " seconds.",
                                 MsgPriLvl.MED);

                    var vecPath = AStar2D.AStarPath;

                    if (vecPath == null)
                    {
                        logMsg = "Unable to create path:  " + fromVector + " --> " + toVector;
                        //Log(logMsg);
                        Msg.LogDebug(TAG_DEBUG, logMsg, MsgPriLvl.HIGH);
                        continue;
                    }

                    var path = new TunnelNetwork.IPath(vecPath, roomsToConnect[0], roomsToConnect[1]);
                    TrimTunnelAtRooms(ref path);
                    AddPathToNetwork(path);


                    ++edgesDone;
                }
            }

            //Add Entry Point and connect to closest room

            var connectEntry = true;
            var entryDist    = int.MaxValue;

            //Connect entry point to closest room or tunnel
            foreach (var room in m_Tilemap.m_Rooms)
            {
                if (room.ContainsCoord(_entryPt, true))
                {
                    connectEntry = false;
                    break;
                }
            }

            if (connectEntry)
            {
                var availCoords = new HashSet <IVector2>();
                foreach (var tNet in m_Tilemap.m_Tunnels)
                {
                    availCoords.UnionWith(tNet.GetAllPathCoords(false));
                }

                foreach (var room in m_Tilemap.m_Rooms)
                {
                    availCoords.RemoveWhere(_coord => room.GetWallCoords(true).Contains(_coord));
                }

                availCoords.UnionWith(m_Tilemap.m_Rooms.Anchors);

                double distance      = m_Tilemap.Dims.x + m_Tilemap.Dims.y;
                var    closestCoords = Support2D.GetNearestCoords(new HashSet <IVector2> {
                    _entryPt
                }, availCoords,
                                                                  ref distance);

                var closestRoom = m_Tilemap.m_Rooms.Get(closestCoords[1].Value);
                var excludeList = new List <Room>();
                if (closestRoom != null)
                {
                    excludeList.Add(closestRoom);
                }

                var turnCost        = Settings.CalcRoutingStrength * Settings.CalcTurnCost;
                var entryRouteGraph = CreateRoutingCostMap(excludeList,
                                                           new IVector2(map.Dims.x, map.Dims.y), Settings.RoomBufferMax, Settings.TunnelPathMag,
                                                           Settings.CalcRoutingStrength);

                /*  //UNITY
                 * yield return TileMap2D.instance.StartCoroutine(AStar2D.AStar(entryRouteGraph, _entryPt, closestCoords[1].Value,
                 *  turnCost, Settings.TunnelPathMag,
                 *  AStar2D.ManhattanDistance));
                 * */
                AStar2D.AStar(entryRouteGraph, _entryPt, closestCoords[1].Value,
                              turnCost, Settings.TunnelPathMag,
                              AStar2D.ManhattanDistance);
                var entryConnect = AStar2D.AStarPath;

                //TODO make entry point a room?

                /*var entryRoom = new Room(new Bounds(_entryPt.x - 1, _entryPt.y - 1, _entryPt.x + 1, _entryPt.y + 1),
                 *  Room.ShapeType.Rectangle);
                 * m_Tilemap.m_Rooms.Add(entryRoom);*/

                var entryPath = new TunnelNetwork.IPath(entryConnect, null, closestRoom);
                TrimTunnelAtRooms(ref entryPath);
                AddPathToNetwork(entryPath);
            }

            Msg.LogDebug(TAG_DEBUG, "Total routing graph time: " + debugRoutingTime, MsgPriLvl.HIGH);
            Msg.LogDebug(TAG_DEBUG, "Total AStar time: " + debugAStarTime, MsgPriLvl.HIGH);
        }