private IEnumerable <TiledMapLayerModel> CreateTileLayerModels(TiledMap map, TiledMapTileLayer tileLayer) { var layerModels = new List <TiledMapLayerModel>(); var staticLayerBuilder = new TiledMapStaticLayerModelBuilder(); var animatedLayerBuilder = new TiledMapAnimatedLayerModelBuilder(); foreach (var tileset in map.Tilesets) { var firstGlobalIdentifier = map.GetTilesetFirstGlobalIdentifier(tileset); var lastGlobalIdentifier = tileset.TileCount + firstGlobalIdentifier - 1; var texture = tileset.Texture; foreach (var tile in tileLayer.Tiles.Where(t => firstGlobalIdentifier <= t.GlobalIdentifier && t.GlobalIdentifier <= lastGlobalIdentifier)) { var tileGid = tile.GlobalIdentifier; var localTileIdentifier = tileGid - firstGlobalIdentifier; var position = GetTilePosition(map, tile); var tilesetColumns = tileset.Columns == 0 ? 1 : tileset.Columns; // fixes a problem (what problem exactly?) var sourceRectangle = TiledMapHelper.GetTileSourceRectangle(localTileIdentifier, tileset.TileWidth, tileset.TileHeight, tilesetColumns, tileset.Margin, tileset.Spacing); var flipFlags = tile.Flags; // animated tiles var tilesetTile = tileset.Tiles.FirstOrDefault(x => x.LocalTileIdentifier == localTileIdentifier); if (tilesetTile is TiledMapTilesetAnimatedTile animatedTilesetTile) { animatedLayerBuilder.AddSprite(texture, position, sourceRectangle, flipFlags); animatedLayerBuilder.AnimatedTilesetTiles.Add(animatedTilesetTile); if (animatedLayerBuilder.IsFull) { layerModels.Add(animatedLayerBuilder.Build(_graphicsDevice, texture)); } } else { staticLayerBuilder.AddSprite(texture, position, sourceRectangle, flipFlags); if (staticLayerBuilder.IsFull) { layerModels.Add(staticLayerBuilder.Build(_graphicsDevice, texture)); } } } if (staticLayerBuilder.IsBuildable) { layerModels.Add(staticLayerBuilder.Build(_graphicsDevice, texture)); } if (animatedLayerBuilder.IsBuildable) { layerModels.Add(animatedLayerBuilder.Build(_graphicsDevice, texture)); } } return(layerModels); }
private static IEnumerable <TiledMapLayerModelContent> CreateTileLayerModels(TiledMapContent map, string layerName, IEnumerable <TiledMapTile> tiles) { // the code below builds the geometry (triangles) for every tile // for every unique tileset used by a tile in a layer, we are going to end up with a different model (list of vertices and list of indices pair) // we also could end up with more models if the map is very large // regardless, each model is going to require one draw call to render at runtime var modelsByTileset = new Dictionary <TiledMapTilesetContent, List <TiledMapLayerModelContent> >(); // loop through all the tiles in the proper render order, building the geometry for each tile // by processing the tiles in the correct rendering order we ensure the geometry for the tiles will be rendered correctly later using the painter's algorithm foreach (var tile in tiles) { // get the tileset for this tile var tileGlobalIdentifier = tile.GlobalIdentifier; var tileset = map.Tilesets.FirstOrDefault(x => x.ContainsGlobalIdentifier(tileGlobalIdentifier)); if (tileset == null) { throw new NullReferenceException( $"Could not find tileset for global tile identifier '{tileGlobalIdentifier}'"); } var localTileIdentifier = tileGlobalIdentifier - tileset.FirstGlobalIdentifier; Debug.Assert(tileset != null); // check if this tile is animated var tilesetTile = tileset.Tiles.FirstOrDefault(x => x.LocalIdentifier == localTileIdentifier); var isAnimatedTile = tilesetTile?.Frames != null && tilesetTile.Frames.Count > 0; // check if we already have built a list of models for this tileset TiledMapLayerModelContent model; List <TiledMapLayerModelContent> models; if (modelsByTileset.TryGetValue(tileset, out models)) { // if we found the list of models for this tileset, try to use the last model added // (assuming the the ones before the last are all full) model = models.FindLast(x => x is TiledMapLayerAnimatedModelContent == isAnimatedTile); // since it is possible that the correct type of model was not added yet we might have to create the correct model now if (model == null) { model = isAnimatedTile ? new TiledMapLayerAnimatedModelContent(layerName, tileset) : new TiledMapLayerModelContent(layerName, tileset); models.Add(model); } } else { // if we have not found the list of models for this tileset, we need to create the list and start a new model of the correct type models = new List <TiledMapLayerModelContent>(); model = isAnimatedTile ? new TiledMapLayerAnimatedModelContent(layerName, tileset) : new TiledMapLayerModelContent(layerName, tileset); models.Add(model); modelsByTileset.Add(tileset, models); } // check if the current model is full if (model.Vertices.Count + TiledMapHelper.VerticesPerTile > TiledMapHelper.MaximumVerticesPerModel) { // if the current model is full, we need to start a new one model = isAnimatedTile ? new TiledMapLayerAnimatedModelContent(layerName, tileset) : new TiledMapLayerModelContent(layerName, tileset); models.Add(model); } // if the tile is animated, record the index of animated tile for the tilset so we can get the correct texture coordinates at runtime if (isAnimatedTile) { var animatedModel = (TiledMapLayerAnimatedModelContent)model; animatedModel.AddAnimatedTile(tilesetTile); } // fixes a problem if (tileset.Columns == 0) { tileset.Columns = 1; } // build the geometry for the tile var position = GetTilePosition(map, tile); var sourceRectangle = TiledMapHelper.GetTileSourceRectangle(localTileIdentifier, tileset.TileWidth, tileset.TileHeight, tileset.Columns, tileset.Margin, tileset.Spacing); var flipFlags = tile.Flags; model.AddTileIndices(); model.AddTileVertices(position, sourceRectangle, flipFlags); } // for each tileset used in this layer foreach (var keyValuePair in modelsByTileset) { var models = keyValuePair.Value; // and for each model apart of a tileset foreach (var model in models) { yield return(model); } } }