/// <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; }
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); }
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); }
/// <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"); }
/////////////////////////// /////////////////////////// ////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; }
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); }
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); }