Beispiel #1
0
                       Dictionary <TileGroupKey, int>) UnpackEdgeCols(this TileMapList tileMaps,
                                                                      Dictionary <TileMap, List <EdgeCollection <TileEdge> > > tileMapToAllEdgeColls)
        {
            if (tileMaps is null)
            {
                throw new ArgumentNullException(nameof(tileMaps));
            }
            if (tileMapToAllEdgeColls is null)
            {
                throw new ArgumentNullException(nameof(tileMapToAllEdgeColls));
            }

            var edgeCollMap  = new Dictionary <EdgeCollKey, EdgeCollection <TileEdge> >();
            var holeGroupMap = new Dictionary <HoleGroupKey, int>();
            var tileGroupMap = new Dictionary <TileGroupKey, int>();

            foreach (TileMap tileMap in tileMaps.Values)
            {
                List <EdgeCollection <TileEdge> > allEdgeColls = tileMapToAllEdgeColls[tileMap];
                tileGroupMap.Add(new TileGroupKey(tileMap), allEdgeColls.Count);

                for (int tileGroup = 0; tileGroup < allEdgeColls.Count; tileGroup++)
                {
                    EdgeCollection <TileEdge>         thisGroupsColl = allEdgeColls[tileGroup];
                    List <EdgeCollection <TileEdge> > splitEdgeColl  = _SplitEdgeColl(thisGroupsColl); //should hold perim in index 0 and holes in 1-inf
                    holeGroupMap.Add(new HoleGroupKey(tileMap, tileGroup), splitEdgeColl.Count);

                    for (int holeGroup = 0; holeGroup < splitEdgeColl.Count; holeGroup++)
                    {
                        edgeCollMap.Add(new EdgeCollKey(tileMap, tileGroup, holeGroup), splitEdgeColl[holeGroup]);
                    }
                }
            }
            return(edgeCollMap, holeGroupMap, tileGroupMap);
        }
Beispiel #2
0
        public void LoadWorld(TileMapList tileMaps, ReadonlyEntityPackage entityPackage)
        {
            this._ready                 = false;
            this._tileMaps              = tileMaps ?? throw new ArgumentNullException(nameof(tileMaps), "Attempted to load world with no tilemaps.");
            this._entityPackage         = entityPackage;
            this._entityIDToDrawPackage = new Dictionary <int, EntityDrawPackage>();

            foreach (Entity entity in this._entityPackage.entitiesByID.Values)
            {
                string  spritePath       = entity.fullSprite.Texture.ResourcePath;
                string  spritePathPrefix = spritePath.Substr(0, spritePath.FindLast("."));
                Texture spriteSheet      = spritePathPrefix.OpenSplitSpriteImage();
                GD.PrintS("new img sprite sheet rid: " + spriteSheet.GetRid().GetId());
                List <SplitSpriteInfo> spriteSheetInfo = spritePathPrefix.OpenSplitSpriteJson();

                int entityID = entity.GetRid().GetId();
                GD.PrintS("id: " + entityID);
                var splitSpriteSheet = new SplitSpriteSheet(spriteSheet, spriteSheetInfo);
                GD.PrintS(splitSpriteSheet.GetAnyInfo().First().size);
                var idToSplitNodes = new Dictionary <int, Node2D>();
                List <SplitSpriteSheetValue> splitInfo = splitSpriteSheet.GetAnyInfo();
                foreach (SplitSpriteSheetValue info in splitInfo)
                {
                    var splitNode2D = new Node2D();
                    idToSplitNodes[info.splitIndex] = splitNode2D;
                }
                this._entityIDToDrawPackage.Add(entityID, new EntityDrawPackage(entityID, splitSpriteSheet, idToSplitNodes, entity.fullSprite.Offset));
                entity.fullSprite.Hide();
            }
            this._ready = true;
        }
 /// <summary>
 /// Creates and returns a dictionary that maps a TileMap's StaticBody2D's RID to said TileMap's walls or ledges.
 /// </summary>
 /// <param name="tileMaps">List of TileMaps.</param>
 /// <param name="tileMapToSB2Ds">Map of TileMap to its SB2D, whether its origin was a wall or ledge.</param>
 /// <param name="perimData">Data of all perimeters of all TileMaps.</param>
 /// <param name="ledgeData">Data of all ledges of all TileMaps.</param>
 /// <param name="option">Whether this function is being used to construct segments for walls or ledges.</param>
 /// <returns>A dictionary that maps a TileMap's SB2D RID to said TileMap's walls.</returns>
 public static Dictionary<RID, List<SegmentShape2D>> ConstructSB2DSegments(this TileMapList tileMaps,
                                                                           Dictionary<TileMap, RID> tileMapToSB2Ds,
                                                                           PerimeterData perimData,
                                                                           LedgeData ledgeData,
                                                                           StaticBodyOrigin option)
 {
     if (tileMaps is null) throw new ArgumentNullException(nameof(tileMaps));
     if (tileMapToSB2Ds is null) throw new ArgumentNullException(nameof(tileMapToSB2Ds));
     if (perimData is null) throw new ArgumentNullException(nameof(perimData));
     if (ledgeData is null) throw new ArgumentNullException(nameof(ledgeData));
     
     var sb2dToSegments = new Dictionary<RID, List<SegmentShape2D>>();
     foreach (TileMap tileMap in tileMaps.Values)
     {
         RID wall = tileMapToSB2Ds[tileMap];
         List<SegmentShape2D> segments = (option == StaticBodyOrigin.Wall) ?
                                               _GetWallSegments(tileMaps, tileMap, perimData) :
                                               _GetLedgeSegments(tileMaps, tileMap, ledgeData);
         sb2dToSegments.Add(wall, segments);
         foreach (SegmentShape2D segment in segments)
         {
             Physics2DServer.BodyAddShape(wall, segment.GetRid());
         }
     }
     return sb2dToSegments;
 }
Beispiel #4
0
        /// <summary>
        /// Uses the VisualServer to draw each of an entity's split sprites, by:
        ///     1. Obtaining the Node2D that is designated to play host to a given split sprite
        ///     2. Changing the Node2D's (TileMap) parent if required
        ///     3. Creating an RID for the canvas item (the sprite drawing) and storing it so it can be freed later
        /// </summary>
        /// <param name="tileMaps"></param>
        /// <param name="tileMapZIndex"></param>
        /// <param name="entityPos"></param>
        /// <param name="entityDrawPos">Offsets the sprite upwards. Used for drawing entities falling/jumping.</param>
        public void DrawSplitSprites(TileMapList tileMaps, int tileMapZIndex, Vector2 entityPos, float entityDrawPos /*State goes here*/)
        {
            List <SplitSpriteSheetValue> splitSprites = this._splitSpriteSheet.GetSplitSpriteInfoForAnim("idle", 0); //TODO match to entity anim state

            foreach (SplitSpriteSheetValue splitSprite in splitSprites)
            {
                Node2D  splitNode2D = this._idToSplitNodes[splitSprite.splitIndex];
                TileMap tileMap     = tileMaps[tileMapZIndex + splitSprite.zIndex];
                if (splitNode2D.GetParent() != tileMap)
                {
                    if (splitNode2D.GetParent() != null)
                    {
                        splitNode2D.GetParent().RemoveChild(splitNode2D);
                    }
                    tileMap.AddChild(splitNode2D);
                }

                RID splitSpriteRID = VisualServer.CanvasItemCreate();
                this._drawnSprites.Add(splitSpriteRID);
                VisualServer.CanvasItemSetParent(splitSpriteRID, splitNode2D.GetCanvasItem());

                VisualServer.CanvasItemAddTextureRectRegion(splitSpriteRID,
                                                            new Rect2(Vector2.Zero, splitSprite.size),
                                                            this._splitSpriteSheet.GetSpriteSheetRID(),
                                                            new Rect2(splitSprite.sheetPos, splitSprite.size),
                                                            new Color(1, 1, 1, 1),
                                                            false,
                                                            this._splitSpriteSheet.GetSpriteSheetRID());

                VisualServer.CanvasItemSetTransform(splitSpriteRID, new Transform2D(0, this._relativePos - new Vector2(Globals.TileWidth / 2, Globals.TileHeight / 2) + new Vector2(0, entityDrawPos)));

                splitNode2D.Position = entityPos + splitSprite.splitPos + new Vector2(Globals.TileWidth / 2, Globals.TileHeight / 2);
            }
        }
Beispiel #5
0
        /// <summary>
        /// Load a world by setting this class to track its Entities.
        /// TODO figure out whether deferred-queue is enough to ensure this loads after every other world-reliant function is finished so nothing funny happens like we load a world before an Area2D exit callback finishes and crashes the game
        /// TODO if yes, PULL latch in this func to prevent async funcs and entities moving, AND have the async funcs use a stack of tokens or something that this func needs to wait for it to be empty before continuing
        /// </summary>
        /// <param name="tileMaps">A list of all TileMaps in the world.</param>
        public void LoadWorld(TileMapList tileMaps, ReadonlyEntityPackage entityPackage)
        {
            this._floorConstructedToken  = this._toPhysicsHub.Subscribe <FloorsConstructedMessage>((msg) => this._HandleFloorsConstructed(msg));
            this._areaMonitorsSetupToken = this._toPhysicsHub.Subscribe <AreaMonitorsSetupMessage>((msg) => this._waitPhysicsSteps = 1);
            this._area2DCallbackToken    = this._toPhysicsHub.Subscribe <Area2DCallbackMessage>((msg) => this._HandleArea2DCallback(msg));

            this._entityPackage         = entityPackage;
            this._entityIDToZPigeonhole = new Dictionary <int, EntityZPigeonhole>();
            this._tileMaps         = tileMaps ?? throw new ArgumentNullException(nameof(tileMaps), "Attempted to load world with no tilemaps.");
            this._ready            = false;
            this._waitPhysicsSteps = 0;
        }
Beispiel #6
0
                       LedgeData ledgeData) BuildTileNodes(IEnumerable <Node> worldChildren)
        {
            if (worldChildren is null)
            {
                throw new ArgumentNullException(nameof(worldChildren));
            }

            TileMapList tileMaps  = _FillTilemapsArray(worldChildren);
            var         perimData = new PerimeterData(tileMaps);
            var         ledgeData = new LedgeData(perimData, tileMaps);

            return(tileMaps, perimData, ledgeData);
        }
Beispiel #7
0
                       Dictionary <LedgeGroupKey, int> ledgeGroupMap) SuperimposeLedges(
            this TileMapList tileMaps,
            Dictionary <LedgeCollKey, EdgeCollection <TileEdge> > ledgeCollMap,
            Dictionary <LedgeGroupKey, int> ledgeGroupMap,
            Dictionary <HoleGroupKey, int> holeGroupMap,
            Dictionary <TileGroupKey, int> tileGroupMap)
        {
            if (tileMaps is null)
            {
                throw new ArgumentNullException(nameof(tileMaps));
            }
            if (ledgeGroupMap is null)
            {
                throw new ArgumentNullException(nameof(ledgeGroupMap));
            }
            if (holeGroupMap is null)
            {
                throw new ArgumentNullException(nameof(holeGroupMap));
            }
            if (tileGroupMap is null)
            {
                throw new ArgumentNullException(nameof(tileGroupMap));
            }

            var ledgeCollMapClone  = new Dictionary <LedgeCollKey, EdgeCollection <TileEdge> >(ledgeCollMap);
            var ledgeGroupMapClone = new Dictionary <LedgeGroupKey, int>(ledgeGroupMap);

            foreach (TileMap baseTileMap in tileMaps.Values)
            {
                for (int t = baseTileMap.ZIndex + 1; t < tileMaps.Count; t++)
                {
                    TileMap superTileMap = tileMaps[t];
                    TileMap preTileMap   = tileMaps[t - 1]; //needed because superimposition is done in sequence, from T to T+1 then T+2, etc. We don't jump from T to T+10

                    int maxTileGroups = tileGroupMap[new TileGroupKey(baseTileMap)];
                    for (int tileGroup = 0; tileGroup < maxTileGroups; tileGroup++)
                    {
                        int maxHoleGroups = holeGroupMap[new HoleGroupKey(baseTileMap, tileGroup)];
                        for (int holeGroup = 0; holeGroup < maxHoleGroups; holeGroup++)
                        {
                            (ledgeCollMapClone, ledgeGroupMapClone) = _SuperimposeHoleGroup(ledgeCollMapClone, ledgeGroupMapClone,
                                                                                            baseTileMap, superTileMap, preTileMap,
                                                                                            tileGroup, holeGroup);
                        }
                    }
                }
            }

            return(ledgeCollMapClone, ledgeGroupMapClone);
        }
        /// <summary>
        /// Called when a new world is loaded.
        /// Takes <paramref name="tileMaps"/> as an input and searches for all the entities within said input to store them in this class's
        /// dictionary of Entities.
        /// </summary>
        /// <param name="tileMaps"></param>
        public void LoadWorld(TileMapList tileMaps)
        {
            this._entitiesByID = new Dictionary <int, Entity>();
            foreach (TileMap tileMap in tileMaps.Values)
            {
                foreach (Entity entity in tileMap.GetChildren().OfType <Entity>())
                {
                    this._entitiesByID.Add(entity.GetRid().GetId(), entity);
                }
            }
            this._entityBirthDeathWatcherHub = new TinyMessengerHub();
            this._onEntityBornToken          = this._entityBirthDeathWatcherHub.Subscribe <EntityBornMessage>(this._OnEntityBorn);
            this._onEntityDiedToken          = this._entityBirthDeathWatcherHub.Subscribe <EntityDeathMessage>(this._OnEntityDied);

            this._entityBirthDeathForwarderHub = new TinyMessengerHub();
        }
        /// <summary>
        /// Constructs a dictionary that maps a TileMap to a Physics2DServer-created StaticBody2D (RID).
        /// Is used for both the walls and ledges dictionaries.
        /// </summary>
        /// <param name="tileMaps">List of TileMaps.</param>
        /// <param name="worldSpace">RID of the World Space.</param>
        /// <returns>A Dictionary that maps TileMaps to an RID of a StaticBody2D.</returns>
        public static Dictionary<TileMap, RID> ConstructTileMapCollisionMap(this TileMapList tileMaps, RID worldSpace)
        {
            if (tileMaps is null) throw new ArgumentNullException(nameof(tileMaps));

            var tileMapToSB2Ds = new Dictionary<TileMap, RID>();
            foreach (TileMap tileMap in tileMaps.Values)
            {
                RID edgeSB2D = Physics2DServer.BodyCreate();
                Physics2DServer.BodySetMode(edgeSB2D, Physics2DServer.BodyMode.Static);
                Physics2DServer.BodySetSpace(edgeSB2D, worldSpace);
                Physics2DServer.BodySetState(edgeSB2D, Physics2DServer.BodyState.Transform, Transform2D.Identity);
                Physics2DServer.BodySetCollisionLayer(edgeSB2D, LayersFuncs.GetLayersValue(Terrain));
                Physics2DServer.BodySetCollisionMask(edgeSB2D, LayersFuncs.GetLayersValue(PlayerEntity, NpcEntity));
                tileMapToSB2Ds.Add(tileMap, edgeSB2D);
            }
            return tileMapToSB2Ds;
        }
        /// <summary>
        /// Creates a FloorArea2D for each TileMap.
        /// </summary>
        /// <param name="tileMaps"></param>
        /// <param name="worldSpace"></param>
        /// <returns></returns>
        public static Dictionary <TileMap, RID> ConstructTileMapFloorMap(this TileMapList tileMaps, RID worldSpace)
        {
            if (tileMaps is null)
            {
                throw new ArgumentNullException(nameof(tileMaps));
            }

            var tileMapToFloorArea2D = new Dictionary <TileMap, RID>();

            foreach (TileMap tileMap in tileMaps.Values)
            {
                RID area2d = Physics2DServer.AreaCreate();
                Physics2DServer.AreaSetSpace(area2d, worldSpace);
                tileMapToFloorArea2D[tileMap] = area2d;
            }
            return(tileMapToFloorArea2D);
        }
        ConstructFloorPartitions(this TileMapList tileMaps, Dictionary <TileMap, RID> tileMapToFloorArea2Ds,
                                 PerimeterData perimData)
        {
            if (tileMaps is null)
            {
                throw new ArgumentNullException(nameof(tileMaps));
            }
            if (tileMapToFloorArea2Ds is null)
            {
                throw new ArgumentNullException(nameof(tileMapToFloorArea2Ds));
            }
            if (perimData is null)
            {
                throw new ArgumentNullException(nameof(perimData));
            }

            var floorArea2DToPolygons = new Dictionary <RID, List <ConvexPolygonShape2D> >();

            foreach (TileMap tileMap in tileMaps.Values)
            {
                RID area2dRID = tileMapToFloorArea2Ds[tileMap];
                floorArea2DToPolygons[area2dRID] = new List <ConvexPolygonShape2D>();
                Physics2DServer.AreaSetCollisionLayer(area2dRID, LayersFuncs.GetLayersValue(Terrain));
                Physics2DServer.AreaSetCollisionMask(area2dRID, LayersFuncs.GetLayersValue(PlayerEntity, NpcEntity));

                int maxTileGroups = perimData.GetMaxTileGroup(tileMap);
                for (int tileGroup = 0; tileGroup < maxTileGroups; tileGroup++)
                {
                    int maxHoleGroups = perimData.GetMaxHoleGroup(tileMap, tileGroup);
                    var allPerims     = new List <Vector2> [maxHoleGroups];
                    for (int holeGroup = 0; holeGroup < maxHoleGroups; holeGroup++)
                    { //put all perims (outer and hole) from one tile group into a single array of lists (gods help me) for partitioning
                        EdgeCollection <TileEdge> edgeColl = perimData.GetEdgeCollection(tileMap, tileGroup, holeGroup);
                        allPerims[holeGroup] = new List <Vector2>(edgeColl.GetSimplifiedPerim());
                    }
                    List <ConvexPolygonShape2D> partitionedRectangles = _PartitionPolygonToRectangles(allPerims);
                    foreach (ConvexPolygonShape2D shape in partitionedRectangles)
                    {
                        Physics2DServer.AreaAddShape(area2dRID, shape.GetRid());
                        GD.PrintS("added shape " + shape.GetRid().GetId() + " to area: " + area2dRID.GetId());
                    }
                    floorArea2DToPolygons[area2dRID].AddRange(partitionedRectangles);
                }
            }
            return(floorArea2DToPolygons);
        }
Beispiel #12
0
        /// <summary>
        /// From some input edge, grab the tile it originated from and check if there is an adjacent tile
        /// in the direction TO the edge on any lower TileMap.
        /// Basically we are checking if it is possible to move from the original tile in the direction
        /// of the edge and fall to a lower tile.
        /// Should no adjacent tile exist, returns the current tile.
        /// </summary>
        /// <param name="tileMaps">List of all tilemaps.</param>
        /// <param name="edge">Edge that is being examined.</param>
        /// <param name="currentLayer">Current layer that edge is on.</param>
        /// <returns>Coords of the highest adjacent tile, or current tile if no adjacent tile exists.</returns>
        private static Vector2 _GetAdjacentLowerTile(TileMapList tileMaps, TileEdge edge, int currentLayer)
        {
            Vector2 currentTile = edge.tileCoords;
            Vector2 adjTile     = currentTile;

            for (int i = currentLayer; i >= 0; i--)
            {
                Vector2 adjCoords    = _GetAdjLowerCoords(edge, currentLayer, i);
                TileMap lowerTileMap = tileMaps[i];

                if (adjCoords != currentTile && lowerTileMap.GetCellv(adjCoords) != TileMap.InvalidCell)
                {
                    adjTile = adjCoords;
                    break; //no need to continue searching we have the highest adj tile
                }
            }
            return(adjTile);
        }
Beispiel #13
0
        /// <summary>
        /// Given a single perimeter, separate it into different ledge groups as appropriate, separate its Edges
        /// into different EdgeCollections, one for each ledge group, then return both as dictionaries.
        /// </summary>
        /// <param name="ledgeCollMap">Dict which maps ledge group to EdgeCollection.</param>
        /// <param name="ledgeGroupMap">Dict which maps superimposed TileMap to ledge group.</param>
        /// The above two are here for copy-and-return purposes (maintaining object immutability).
        /// <param name="tileMaps">List of all TileMaps.</param>
        /// <param name="tileMap">TileMap that ledges are being filled for.</param>
        ///<param name="perimeter">EdgeCollection holding perimeter which will be separated in this func.</param>
        /// <param name="tileGroup">TileGroup that ledges are being filled for.</param>
        /// <param name="holeGroup">HoleGroup that ledges are being filled for.</param>
        /// <returns>Two dictionaries matching the two input dicts but with the new ledge data added to each.</returns>
        private static (Dictionary <LedgeCollKey, EdgeCollection <TileEdge> >, Dictionary <LedgeGroupKey, int>) _FillLedges(
            IDictionary <LedgeCollKey, EdgeCollection <TileEdge> > ledgeCollMap,
            IDictionary <LedgeGroupKey, int> ledgeGroupMap,
            TileMapList tileMaps,
            TileMap tileMap,
            EdgeCollection <TileEdge> perimeter,
            int tileGroup,
            int holeGroup)
        {
            var ledgeCollMapClone  = new Dictionary <LedgeCollKey, EdgeCollection <TileEdge> >(ledgeCollMap);
            var ledgeGroupMapClone = new Dictionary <LedgeGroupKey, int>(ledgeGroupMap);

            var ledges     = new EdgeCollection <TileEdge>();
            int ledgeGroup = 0;

            foreach (TileEdge edge in perimeter)
            {
                Vector2 currentTile  = edge.tileCoords;
                int     currentLayer = tileMap.ZIndex;
                Vector2 adjTile      = _GetAdjacentLowerTile(tileMaps, edge, currentLayer);

                if (adjTile == currentTile)
                { //no adjacent tile exists
                    ledges.Add(edge);
                }
                else if (ledges.Count > 0)
                { //gap in ledges, finish current ledge group and move to next one
                    ledgeCollMapClone.Add(new LedgeCollKey(tileMap, tileGroup, holeGroup, tileMap, ledgeGroup),
                                          new EdgeCollection <TileEdge>(ledges.GetOrderedCollection()));
                    ledgeGroup++;
                    ledges = new EdgeCollection <TileEdge>();
                }
            }

            if (ledges.Count > 0)
            { //store ledges if not done already
                ledgeCollMapClone.Add(new LedgeCollKey(tileMap, tileGroup, holeGroup, tileMap, ledgeGroup),
                                      new EdgeCollection <TileEdge>(ledges.GetOrderedCollection()));
                ledgeGroup++;
            }

            ledgeGroupMapClone.Add(new LedgeGroupKey(tileMap, tileGroup, holeGroup, tileMap), ledgeGroup);
            return(ledgeCollMapClone, ledgeGroupMapClone);
        }
        ///////////////////////////
        ///////////////////////////
        ////PRIVATE FUNCS BELOW////
        ///////////////////////////
        ///////////////////////////

        /// <summary>
        /// For a given TileMap, gets its walls as a list of SegmentShape2Ds by getting perimData's EdgeCollections for the
        /// TileMap directly above the given TileMap.
        /// </summary>
        /// <param name="tileMaps">TileMapList of TileMaps.</param>
        /// <param name="thisTileMap">The TileMap that this function is getting walls for.</param>
        /// <param name="perimData">Data of all perimeters of all TileMaps in the currently loaded world.</param>
        /// <returns>A List of SegmentShape2Ds that contain every segment that make up every wall in thisTileMap.</returns>
        private static List<SegmentShape2D> _GetWallSegments(TileMapList tileMaps, TileMap thisTileMap, PerimeterData perimData)
        {
            var allSegments = new List<SegmentShape2D>();
            if (thisTileMap == tileMaps.Last()) return allSegments; //there are never walls on the highest TileMap

            int nextIndex = thisTileMap.ZIndex + 1;
            TileMap nextTileMap = tileMaps[nextIndex];
            int maxTileGroups = perimData.GetMaxTileGroup(nextTileMap);
            for (int tileGroup = 0; tileGroup < maxTileGroups; tileGroup++)
            {
                int maxHoleGroups = perimData.GetMaxHoleGroup(nextTileMap, tileGroup);
                for (int holeGroup = 0; holeGroup < maxHoleGroups; holeGroup++)
                {
                    EdgeCollection<TileEdge> wallColl = perimData.GetEdgeCollection(nextTileMap, tileGroup, holeGroup);
                    IEnumerable<SegmentShape2D> thisWallSegments = _ShiftSegmentsDown(_EdgeCollToSegments(wallColl));
                    allSegments.AddRange(thisWallSegments);
                }
            }
            return allSegments;
        }
        /// <summary>
        /// Should be called whenever loaded world changes.
        /// Resets all wall and ledge physics bodies and prepares new ones to be filled by TileController.
        /// </summary>
        /// <param name="tileMaps">List of TileMaps which are guaranteed to have a unique Z index.</param>
        /// <param name="perimData">Data of all perimeters of all TileMaps.</param>
        /// <param name="ledgeData">Data of all ledges of all TileMaps.</param>
        /// <param name="worldSpace">Current world space.</param>
        public void LoadWorld(TileMapList tileMaps, PerimeterData perimData, LedgeData ledgeData, RID worldSpace)
        {
            if (tileMaps == null)
            {
                throw new ArgumentNullException(nameof(tileMaps), "Attempted to load world with no tilemaps.");
            }

            this._tileMapToFloorArea2Ds = tileMaps.ConstructTileMapFloorMap(worldSpace);
            this._tileMapToWallSB2Ds    = tileMaps.ConstructTileMapCollisionMap(worldSpace);
            this._tileMapToLedgeSB2Ds   = tileMaps.ConstructTileMapCollisionMap(worldSpace);
            this._floorArea2DToPolygons = tileMaps.ConstructFloorPartitions(this._tileMapToFloorArea2Ds, perimData);
            this._wallSB2DToSegments    = tileMaps.ConstructSB2DSegments(this._tileMapToWallSB2Ds, perimData, ledgeData,
                                                                         CollisionConstructor.StaticBodyOrigin.Wall);
            this._ledgeSB2DToSegments = tileMaps.ConstructSB2DSegments(this._tileMapToLedgeSB2Ds, perimData, ledgeData,
                                                                       CollisionConstructor.StaticBodyOrigin.Ledge);

            this._toEntityHub.Publish(new FloorsConstructedMessage(this, this._tileMapToFloorArea2Ds));
            foreach (TileMap tileMap in tileMaps.Values)
            {
                GD.PrintS("TileMapToFloorArea2Ds RID for tilemap with zIndex " + tileMap.ZIndex + ": " + this._tileMapToFloorArea2Ds[tileMap].GetId());
                //GD.PrintS("TileMapToWallSB2Ds RID for tilemap with zIndex " + tileMap.ZIndex + ": " +  this.tileMapToWallSB2Ds[tileMap].GetId());
                //GD.PrintS("TileMapToLedgeSB2Ds RID for tilemap with zIndex " + tileMap.ZIndex + ": " +  this.tileMapToLedgeSB2Ds[tileMap].GetId());

                RID floorRID = this._tileMapToFloorArea2Ds[tileMap];
                RID wallRID  = this._tileMapToWallSB2Ds[tileMap];
                RID ledgeRID = this._tileMapToLedgeSB2Ds[tileMap];
                GD.PrintS("floorArea2DToPolygons count: " + this._floorArea2DToPolygons[floorRID].Count);
                GD.PrintS("wallSB2DToSegments count: " + this._wallSB2DToSegments[wallRID].Count);
                GD.PrintS("ledgeSB2DToSegments count: " + this._ledgeSB2DToSegments[ledgeRID].Count);

                this._area2DMonitors[floorRID.GetId()] = new Area2DMonitor(floorRID, tileMap.ZIndex, this._floorArea2DToPolygons[floorRID], this._toEntityHub);
                Physics2DServer.AreaSetMonitorCallback(floorRID, this._area2DMonitors[floorRID.GetId()], nameof(Area2DMonitor.OnAreaCallback));
            }
            this._toEntityHub.Publish(new AreaMonitorsSetupMessage(this));
            GD.PrintS("published areamonitor msg");
        }
 /// <summary>
 /// For a given TileMap, gets its ledges as a list of SegmentShape2Ds by iterating through LedgeData for:
 ///     1. The given TileMap's own ledges
 ///     2. Ledges that have been superimposed from every lower TileMap to the given TileMap
 /// </summary>
 /// <param name="tileMaps">List of TileMaps.</param>
 /// <param name="thisTileMap">The TileMap this function is getting ledges for.</param>
 /// <param name="ledgeData">Data of all ledges of all TileMaps.</param>
 /// <returns>A list of SegmentShape2Ds that contain every segment of every ledge that is on thisTileMap.</returns>
 private static List<SegmentShape2D> _GetLedgeSegments(TileMapList tileMaps, TileMap thisTileMap, LedgeData ledgeData)
 {
     var allSegments = new List<SegmentShape2D>();
     for (int zIndex = 0; zIndex <= thisTileMap.ZIndex; zIndex++)
     {
         TileMap baseTileMap = tileMaps[zIndex];
         int maxTileGroups = ledgeData.GetMaxTileGroup(baseTileMap);
         for (int tileGroup = 0; tileGroup < maxTileGroups; tileGroup++)
         {
             int maxHoleGroups = ledgeData.GetMaxHoleGroup(baseTileMap, tileGroup);
             for (int holeGroup = 0; holeGroup < maxHoleGroups; holeGroup++)
             {
                 int maxLedgeGroups = ledgeData.GetMaxLedgeGroup(baseTileMap, tileGroup, holeGroup, thisTileMap);
                 for (int ledgeGroup = 0; ledgeGroup < maxLedgeGroups; ledgeGroup++)
                 {
                     EdgeCollection<TileEdge> ledgeColl = ledgeData.GetLedgeCollection(baseTileMap, tileGroup, holeGroup, thisTileMap, ledgeGroup);
                     IEnumerable<SegmentShape2D> thisLedgeSegments = _EdgeCollToSegments(ledgeColl);
                     allSegments.AddRange(thisLedgeSegments);
                 }
             }
         }
     }
     return allSegments;
 }
Beispiel #17
0
                       Dictionary <HoleGroupKey, int>, Dictionary <TileGroupKey, int>) BuildLedges(this TileMapList tileMaps,
                                                                                                   PerimeterData perimData)
        {
            if (tileMaps is null)
            {
                throw new ArgumentNullException(nameof(tileMaps));
            }
            if (perimData is null)
            {
                throw new ArgumentNullException(nameof(perimData));
            }

            var ledgeCollMap  = new Dictionary <LedgeCollKey, EdgeCollection <TileEdge> >();
            var ledgeGroupMap = new Dictionary <LedgeGroupKey, int>();
            var holeGroupMap  = new Dictionary <HoleGroupKey, int>();
            var tileGroupMap  = new Dictionary <TileGroupKey, int>();

            foreach (TileMap tileMap in tileMaps.Values)
            {
                int maxTileGroups = perimData.GetMaxTileGroup(tileMap);
                tileGroupMap.Add(new TileGroupKey(tileMap), maxTileGroups);
                for (int tileGroup = 0; tileGroup < maxTileGroups; tileGroup++)
                {
                    int maxHoleGroups = perimData.GetMaxHoleGroup(tileMap, tileGroup);
                    holeGroupMap.Add(new HoleGroupKey(tileMap, tileGroup), maxHoleGroups);
                    for (int holeGroup = 0; holeGroup < maxHoleGroups; holeGroup++)
                    {
                        EdgeCollection <TileEdge> thisPerim = perimData.GetEdgeCollection(tileMap, tileGroup, holeGroup);
                        (ledgeCollMap, ledgeGroupMap) = _FillLedges(ledgeCollMap, ledgeGroupMap, tileMaps,
                                                                    tileMap, thisPerim, tileGroup, holeGroup);
                    }
                }
            }

            return(ledgeCollMap, ledgeGroupMap, holeGroupMap, tileGroupMap);
        }
Beispiel #18
0
        /// <summary>
        /// Builds perimeters, packs into a dictionary of tilemaps -> List of EdgeCollections, and returns.
        /// </summary>
        public static Dictionary <TileMap, List <EdgeCollection <TileEdge> > > BuildPerimeter(this TileMapList tileMaps)
        {
            if (tileMaps is null)
            {
                throw new ArgumentNullException(nameof(tileMaps));
            }

            var tileMapToAllEdgeCollections = new Dictionary <TileMap, List <EdgeCollection <TileEdge> > >();

            foreach (TileMap tileMap in tileMaps.Values)
            {
                List <TilePerim> tilePerims = _FillTiles(tileMap);
                Dictionary <int, HashSet <int> > adjMatrix = _InitAdjMatrix(tilePerims);

                //recursive flood fill to find tile groups
                int maxColor = 0;
                foreach (TilePerim tilePerim in tilePerims.Where(tilePerim => tilePerim.color == TilePerim.UNCOLORED))
                {
                    tilePerims = _TileFloodFill(adjMatrix, tilePerims, tilePerim, maxColor);
                    maxColor++; //i could put this on the prev line
                }
                List <EdgeCollection <TileEdge> > allEdgeCollections = _FillEdgeCollections(tilePerims, maxColor);
                tileMapToAllEdgeCollections.Add(tileMap, allEdgeCollections);
            }
            return(tileMapToAllEdgeCollections);
        }
Beispiel #19
0
 public LedgeData(PerimeterData perimData, TileMapList tileMaps)
 {
     (this._ledgeCollMap, this._ledgeGroupMap, this._holeGroupMap, this._tileGroupMap) = tileMaps.BuildLedges(perimData);
     (this._ledgeCollMap, this._ledgeGroupMap) = tileMaps.SuperimposeLedges(this._ledgeCollMap, this._ledgeGroupMap,
                                                                            this._holeGroupMap, this._tileGroupMap);
 }