public static LayeredTileMap FromReducedTileMapInfo(TMXGlueLib.DataTypes.ReducedTileMapInfo rtmi, string contentManagerName, string tilbToLoad) { var toReturn = new LayeredTileMap(); string oldRelativeDirectory = FileManager.RelativeDirectory; FileManager.RelativeDirectory = FileManager.GetDirectory(tilbToLoad); MapDrawableBatch mdb; for (int i = 0; i < rtmi.Layers.Count; i++) { var reducedLayer = rtmi.Layers[i]; mdb = MapDrawableBatch.FromReducedLayer(reducedLayer, contentManagerName, rtmi.CellWidthInPixels, rtmi.CellHeightInPixels, rtmi.QuadWidth, rtmi.QuadHeight); mdb.AttachTo(toReturn, false); mdb.RelativeZ = reducedLayer.Z; toReturn.mMapLists.Add(mdb); } FileManager.RelativeDirectory = oldRelativeDirectory; return(toReturn); }
public static MapDrawableBatch FromScnx(string sceneFileName, string contentManagerName, bool verifySameTexturePerLayer) { // TODO: This line crashes when the path is already absolute! string absoluteFileName = FileManager.MakeAbsolute(sceneFileName); // TODO: The exception doesn't make sense when the file type is wrong. SpriteEditorScene saveInstance = SpriteEditorScene.FromFile(absoluteFileName); int startingIndex = 0; string oldRelativeDirectory = FileManager.RelativeDirectory; FileManager.RelativeDirectory = FileManager.GetDirectory(absoluteFileName); // get the list of sprites from our map file List <SpriteSave> spriteSaveList = saveInstance.SpriteList; // we use the sprites as defined in the scnx file to create and draw the map. MapDrawableBatch mMapBatch = FromSpriteSaves(spriteSaveList, startingIndex, spriteSaveList.Count, contentManagerName, verifySameTexturePerLayer); FileManager.RelativeDirectory = oldRelativeDirectory; // temp //mMapBatch = new MapDrawableBatch(32, 32, 32f, 64, @"content/tiles"); return(mMapBatch); }
public static LayeredTileMap FromScene(string fileName, string contentManagerName, bool verifySameTexturePerLayer) { Section.GetAndStartContextAndTime("Initial FromScene"); LayeredTileMap toReturn = new LayeredTileMap(); string absoluteFileName = FileManager.MakeAbsolute(fileName); Section.EndContextAndTime(); Section.GetAndStartContextAndTime("FromFile"); SceneSave ses = SceneSave.FromFile(absoluteFileName); Section.EndContextAndTime(); Section.GetAndStartContextAndTime("BreaksNStuff"); string oldRelativeDirectory = FileManager.RelativeDirectory; FileManager.RelativeDirectory = FileManager.GetDirectory(absoluteFileName); var breaks = GetZBreaks(ses.SpriteList); int valueBefore = 0; MapDrawableBatch mdb; int valueAfter; float zValue = 0; Section.EndContextAndTime(); Section.GetAndStartContextAndTime("Create MDBs"); for (int i = 0; i < breaks.Count; i++) { valueAfter = breaks[i]; int count = valueAfter - valueBefore; mdb = MapDrawableBatch.FromSpriteSaves(ses.SpriteList, valueBefore, count, contentManagerName, verifySameTexturePerLayer); mdb.AttachTo(toReturn, false); mdb.RelativeZ = zValue; toReturn.mMapLists.Add(mdb); zValue += toReturn.mZSplit; valueBefore = valueAfter; } valueAfter = ses.SpriteList.Count; if (valueBefore != valueAfter) { int count = valueAfter - valueBefore; mdb = MapDrawableBatch.FromSpriteSaves(ses.SpriteList, valueBefore, count, contentManagerName, verifySameTexturePerLayer); mdb.AttachTo(toReturn, false); mdb.RelativeZ = zValue; toReturn.mMapLists.Add(mdb); } Section.EndContextAndTime(); FileManager.RelativeDirectory = oldRelativeDirectory; return(toReturn); }
public static void RemoveTiles(this MapDrawableBatch layer, Func <List <NamedValue>, bool> predicate, Dictionary <string, List <NamedValue> > Properties) { // Force execution now for performance reasons var filteredInfos = Properties.Values.Where(predicate).ToList(); RemoveTilesFromLayer(filteredInfos, layer); }
/// <summary> /// Creates entities from a single layer for any tile with the EntityToCreate property. /// </summary> /// <param name="mapLayer">The layer to create entities from.</param> /// <param name="layeredTileMap">The map which contains the mapLayer instance.</param> public static void CreateEntitiesFrom(MapDrawableBatch mapLayer, LayeredTileMap layeredTileMap) { var entitiesToRemove = new List<string>(); CreateEntitiesFrom(entitiesToRemove, mapLayer, layeredTileMap.Properties); foreach (var entityToRemove in entitiesToRemove) { string remove = entityToRemove; mapLayer.RemoveTiles(t => t.Any(item => item.Name == "EntityToCreate" && item.Value as string == remove), layeredTileMap.Properties); } }
internal static MapDrawableBatch FromReducedLayer(TMXGlueLib.DataTypes.ReducedLayerInfo reducedLayerInfo, string contentManagerName, int tileDimensionWidth, int tileDimensionHeight, float quadWidth, float quadHeight) { string textureName = reducedLayerInfo.Texture; Texture2D texture = FlatRedBallServices.Load <Texture2D>(textureName, contentManagerName); #if DEBUG if (!MathFunctions.IsPowerOfTwo(texture.Width) || !MathFunctions.IsPowerOfTwo(texture.Height)) { throw new Exception("The dimensions of the texture file " + texture.Name + " are not power of 2!"); } #endif MapDrawableBatch toReturn = new MapDrawableBatch(reducedLayerInfo.Quads.Count, tileDimensionWidth, tileDimensionHeight, texture); toReturn.Name = reducedLayerInfo.Name; Vector3 position = new Vector3(); Vector2 tileDimensions = new Vector2(quadWidth, quadHeight); foreach (var quad in reducedLayerInfo.Quads) { position.X = quad.LeftQuadCoordinate; position.Y = quad.BottomQuadCorodinate; position.Z = reducedLayerInfo.Z; var textureValues = new Vector4(); textureValues.X = (float)quad.LeftTexturePixel / (float)texture.Width; // Left textureValues.Y = (float)(quad.LeftTexturePixel + tileDimensionWidth) / (float)texture.Width; // Right textureValues.Z = (float)quad.TopTexturePixel / (float)texture.Height; // Top textureValues.W = (float)(quad.TopTexturePixel + tileDimensionHeight) / (float)texture.Height; // Bottom const bool pad = true; if (pad) { const float amountToAdd = .0000001f; textureValues.X += amountToAdd; // Left textureValues.Y -= amountToAdd; // Right textureValues.Z += amountToAdd; // Top textureValues.W -= amountToAdd; // Bottom } int tileIndex = toReturn.AddTile(position, tileDimensions, //quad.LeftTexturePixel, quad.TopTexturePixel, quad.LeftTexturePixel + tileDimensionWidth, quad.TopTexturePixel + tileDimensionHeight); textureValues); toReturn.RegisterName(quad.Name, tileIndex); } return(toReturn); }
private static void CreateEntitiesFrom(List<string> entitiesToRemove, MapDrawableBatch layer, Dictionary<string, List<NamedValue>> propertiesDictionary) { var flatRedBallLayer = SpriteManager.Layers.FirstOrDefault(item => item.Batches.Contains(layer)); var dictionary = layer.NamedTileOrderedIndexes; // layer needs its position updated: layer.ForceUpdateDependencies(); foreach (var propertyList in propertiesDictionary.Values) { if (propertyList.Any(item2 => item2.Name == "EntityToCreate")) { var tileName = propertyList.FirstOrDefault(item => item.Name.ToLowerInvariant() == "name").Value as string; var entityType = propertyList.FirstOrDefault(item => item.Name == "EntityToCreate").Value as string; if (!string.IsNullOrEmpty(entityType) && dictionary.ContainsKey(tileName)) { IEntityFactory factory = GetFactory(entityType); if (factory == null) { string message = $"The factory for entity {entityType} could not be found. To create instances of this entity, " + "set its 'CreatedByOtherEntities' property to true in Glue."; throw new Exception(message); } else { entitiesToRemove.Add(entityType); var indexList = dictionary[tileName]; foreach (var tileIndex in indexList) { var entity = factory.CreateNew(flatRedBallLayer) as PositionedObject; ApplyPropertiesTo(entity, layer, tileIndex, propertyList); } } } } } }
private static void ApplyPropertiesTo(PositionedObject entity, MapDrawableBatch layer, int tileIndex, List<NamedValue> propertiesToAssign) { int vertexIndex = tileIndex * 4; var dimension = layer.Vertices[vertexIndex + 1].Position.X - layer.Vertices[vertexIndex].Position.X; float dimensionHalf = dimension / 2.0f; float left; float bottom; layer.GetBottomLeftWorldCoordinateForOrderedTile(tileIndex, out left, out bottom); if (entity != null) { entity.X = left + dimensionHalf; entity.Y = bottom + dimensionHalf; entity.Z = layer.Z; } var entityType = entity.GetType(); var lateBinder = Instructions.Reflection.LateBinder.GetInstance(entityType); foreach (var property in propertiesToAssign) { try { var valueToSet = property.Value; valueToSet = SetValueAccordingToType(valueToSet, property.Name, property.Type, entityType); lateBinder.SetValue(entity, property.Name, valueToSet); } catch (Exception e) { // Since this code indiscriminately tries to set properties, it may set properties which don't // actually exist. Therefore, we tolerate failures. } } }
public static LayeredTileMap FromReducedTileMapInfo(TMXGlueLib.DataTypes.ReducedTileMapInfo rtmi, string contentManagerName, string tilbToLoad) { var toReturn = new LayeredTileMap(); string oldRelativeDirectory = FileManager.RelativeDirectory; FileManager.RelativeDirectory = FileManager.GetDirectory(tilbToLoad); MapDrawableBatch mdb; if (rtmi.NumberCellsWide != 0) { toReturn.mNumberTilesWide = rtmi.NumberCellsWide; } if (rtmi.NumberCellsTall != 0) { toReturn.mNumberTilesTall = rtmi.NumberCellsTall; } toReturn.mWidthPerTile = rtmi.QuadWidth; toReturn.mHeightPerTile = rtmi.QuadHeight; for (int i = 0; i < rtmi.Layers.Count; i++) { var reducedLayer = rtmi.Layers[i]; mdb = MapDrawableBatch.FromReducedLayer(reducedLayer, rtmi, contentManagerName); mdb.AttachTo(toReturn, false); mdb.RelativeZ = reducedLayer.Z; toReturn.mMapLists.Add(mdb); } FileManager.RelativeDirectory = oldRelativeDirectory; return(toReturn); }
/* This creates a MapDrawableBatch (MDB) from the list of sprites provided to us by the FlatRedBall (FRB) Scene XML (scnx) file. */ public static MapDrawableBatch FromSpriteSaves(List <SpriteSave> spriteSaveList, int startingIndex, int count, string contentManagerName, bool verifySameTexturesPerLayer) { #if DEBUG if (verifySameTexturesPerLayer) { VerifySingleTexture(spriteSaveList, startingIndex, count); } #endif // We got it! We are going to make some assumptions: // First we need the texture. We'll assume all Sprites // use the same texture: // TODO: I (Bryan) really HATE this assumption. But it will work for now. SpriteSave firstSprite = spriteSaveList[startingIndex]; // This is the file name of the texture, but the file name is relative to the .scnx location string textureRelativeToScene = firstSprite.Texture; // so we load the texture Texture2D texture = FlatRedBallServices.Load <Texture2D>(textureRelativeToScene, contentManagerName); if (!MathFunctions.IsPowerOfTwo(texture.Width) || !MathFunctions.IsPowerOfTwo(texture.Height)) { throw new Exception("The dimensions of the texture file " + texture.Name + " are not power of 2!"); } // Assume all the dimensions of the textures are the same. I.e. all tiles use the same texture width and height. // This assumption is safe for Iso and Ortho tile maps. int tileFileDimensionsWidth = 0; int tileFileDimensionsHeight = 0; if (spriteSaveList.Count > startingIndex) { SpriteSave s = spriteSaveList[startingIndex]; // deduce the dimensionality of the tile from the texture coordinates tileFileDimensionsWidth = (int)System.Math.Round((double)((s.RightTextureCoordinate - s.LeftTextureCoordinate) * texture.Width)); tileFileDimensionsHeight = (int)System.Math.Round((double)((s.BottomTextureCoordinate - s.TopTextureCoordinate) * texture.Height)); } // alas, we create the MDB MapDrawableBatch mMapBatch = new MapDrawableBatch(count, tileFileDimensionsWidth, tileFileDimensionsHeight, texture); int lastIndexExclusive = startingIndex + count; for (int i = startingIndex; i < lastIndexExclusive; i++) { SpriteSave spriteSave = spriteSaveList[i]; // We don't want objects within the IDB to have a different Z than the IDB itself // (if possible) because that makes the IDB behave differently when using sorting vs. // the zbuffer. const bool setZTo0 = true; mMapBatch.Paste(spriteSave, setZTo0); } return(mMapBatch); }
public static LayeredTileMap FromTiledMapSave(string tiledMapSaveFile, string contentManager, TiledMapSave tms) { // Ultimately properties are tied to tiles by the tile name. // If a tile has no name but it has properties, those properties // will be lost in the conversion. Therefore, we have to add name properties. tms.MoveTypeToProperties(); #if DEBUG CheckForDuplicateTilesets(tms); #endif tms.NameUnnamedTilesetTiles(); tms.NameUnnamedObjects(); string directory = FlatRedBall.IO.FileManager.GetDirectory(tiledMapSaveFile); var rtmi = ReducedTileMapInfo.FromTiledMapSave( tms, 1, 0, directory, FileReferenceType.Absolute); var toReturn = FromReducedTileMapInfo(rtmi, contentManager, tiledMapSaveFile); AddShapeCollections(toReturn, tms); foreach (var layer in tms.MapLayers) { var matchingLayer = toReturn.MapLayers.FirstOrDefault(item => item.Name == layer.Name); if (matchingLayer != null) { if (layer is MapLayer) { var mapLayer = layer as MapLayer; foreach (var propertyValues in mapLayer.properties) { matchingLayer.Properties.Add(new NamedValue { Name = propertyValues.StrippedName, Value = propertyValues.value, Type = propertyValues.Type }); } matchingLayer.Visible = mapLayer.visible == 1; matchingLayer.Alpha = mapLayer.Opacity; } else if (layer is mapObjectgroup objectLayer) { matchingLayer.Visible = objectLayer.IsVisible; } } } foreach (var tileset in tms.Tilesets) { foreach (var tile in tileset.TileDictionary.Values) { int propertyCountFromTileset = 0; if (tile.properties.Count != 0) { // this needs a name: string name = tile.properties.FirstOrDefault(item => item.StrippedName.ToLowerInvariant() == "name")?.value; // todo - eventually need to copy default values from the Tileset to the tile here AddPropertiesToMap(tms, toReturn.TileProperties, tile.properties, null, name); } } } foreach (var objectLayer in tms.objectgroup) { if (objectLayer.@object != null) { foreach (var objectInstance in objectLayer.@object) { TMXGlueLib.Tileset tileset = null; int propertyCountFromTileset = 0; var objectProperties = objectInstance.properties; List <property> tilesetProperties = null; if (objectInstance.gid != null) { var gidNoFlip = objectInstance.GidNoFlip; tileset = tms.GetTilesetForGid(gidNoFlip.Value); if (tileset.TileDictionary.ContainsKey(gidNoFlip.Value - tileset.Firstgid)) { tilesetProperties = tileset.TileDictionary[gidNoFlip.Value - tileset.Firstgid].properties; propertyCountFromTileset = tilesetProperties.Count; } } if (objectProperties.Count + propertyCountFromTileset != 0) { string name = objectInstance.Name; // if name is null, check the properties: if (string.IsNullOrEmpty(name)) { name = objectProperties.FirstOrDefault(item => item.StrippedNameLower == "name")?.value; } var objectInstanceIsTile = objectInstance.gid != null; if (objectInstanceIsTile) { AddPropertiesToMap(tms, toReturn.TileProperties, objectProperties, tilesetProperties, name); } else { AddPropertiesToMap(tms, toReturn.ShapeProperties, objectProperties, tilesetProperties, name); } } } } } var tmxDirectory = FileManager.GetDirectory(tiledMapSaveFile); // add image layers foreach (var imageLayer in tms.ImageLayers) { var imageLayerFile = tmxDirectory + imageLayer.ImageObject.Source; var texture = FlatRedBallServices.Load <Microsoft.Xna.Framework.Graphics.Texture2D>(imageLayerFile); var newSprite = new Sprite { Texture = texture, Width = imageLayer.ImageObject.Width, Height = imageLayer.ImageObject.Height, X = imageLayer.ImageObject.Width / 2 + imageLayer.OffsetX, Y = -imageLayer.ImageObject.Height / 2 + imageLayer.OffsetY }; var mdb = new MapDrawableBatch(1, texture); mdb.Alpha = imageLayer.Opacity; mdb.AttachTo(toReturn, false); mdb.Paste(newSprite); mdb.Visible = imageLayer.IsVisible; toReturn.mMapLists.Add(mdb); } var animationDictionary = new Dictionary <string, AnimationChain>(); // add animations foreach (var tileset in tms.Tilesets) { string tilesetImageFile = tmxDirectory + tileset.Images[0].Source; if (tileset.SourceDirectory != ".") { tilesetImageFile = tmxDirectory + tileset.SourceDirectory + tileset.Images[0].Source; } var texture = FlatRedBallServices.Load <Microsoft.Xna.Framework.Graphics.Texture2D>(tilesetImageFile, contentManager); foreach (var tile in tileset.Tiles.Where(item => item.Animation != null && item.Animation.Frames.Count != 0)) { var animation = tile.Animation; var animationChain = new AnimationChain(); foreach (var frame in animation.Frames) { var animationFrame = new AnimationFrame(); animationFrame.FrameLength = frame.Duration / 1000.0f; animationFrame.Texture = texture; int tileIdRelative = frame.TileId; int globalTileId = (int)(tileIdRelative + tileset.Firstgid); int leftPixel; int rightPixel; int topPixel; int bottomPixel; TiledMapSave.GetPixelCoordinatesFromGid((uint)globalTileId, tileset, out leftPixel, out topPixel, out rightPixel, out bottomPixel); animationFrame.LeftCoordinate = MapDrawableBatch.CoordinateAdjustment + leftPixel / (float)texture.Width; animationFrame.RightCoordinate = -MapDrawableBatch.CoordinateAdjustment + rightPixel / (float)texture.Width; animationFrame.TopCoordinate = MapDrawableBatch.CoordinateAdjustment + topPixel / (float)texture.Height; animationFrame.BottomCoordinate = -MapDrawableBatch.CoordinateAdjustment + bottomPixel / (float)texture.Height; animationChain.Add(animationFrame); } var property = tile.properties.FirstOrDefault(item => item.StrippedNameLower == "name"); if (property == null) { throw new InvalidOperationException( $"The tile with ID {tile.id} has an animation, but it doesn't have a Name property, which is required for animation."); } else { animationDictionary.Add(property.value, animationChain); } } } toReturn.Animation = new LayeredTileMapAnimation(animationDictionary); AddTileShapeCollections(toReturn, tms, separateOnTileType: true); toReturn.MapProperties = tms.properties .Select(propertySave => new NamedValue { Name = propertySave.name, Value = propertySave.value, Type = propertySave.Type }) .ToList(); return(toReturn); }
private static void CreateEntitiesFrom(List<string> entitiesToRemove, MapDrawableBatch layer, Dictionary<string, List<NamedValue>> properties) { float dimension = float.NaN; float dimensionHalf = 0; var flatRedBallLayer = SpriteManager.Layers.FirstOrDefault(item => item.Batches.Contains(layer)); var dictionary = layer.NamedTileOrderedIndexes; foreach (var property in properties.Values.Where(item => item.Any(item2 => item2.Name == "EntityToCreate"))) { var tileName = property.FirstOrDefault(item => item.Name.ToLowerInvariant() == "name").Value as string; var entityType = property.FirstOrDefault(item => item.Name == "EntityToCreate").Value as string; if (!string.IsNullOrEmpty(entityType) && dictionary.ContainsKey(tileName)) { #if WINDOWS_8 var assembly = typeof(TileEntityInstantiator).GetTypeInfo().Assembly; var types = assembly.DefinedTypes; var filteredTypes = types.Where(t => t.ImplementedInterfaces.Contains(typeof(IEntityFactory)) && t.DeclaredConstructors.Any(c=>c.GetParameters().Count() == 0)); #else var assembly = Assembly.GetExecutingAssembly(); var types = assembly.GetTypes(); var filteredTypes = types.Where(t => t.GetInterfaces().Contains(typeof(IEntityFactory)) && t.GetConstructor(Type.EmptyTypes) != null); #endif var factories = filteredTypes .Select( t => { #if WINDOWS_8 var propertyInfo = t.DeclaredProperties.First(item => item.Name == "Self"); #else var propertyInfo = t.GetProperty("Self"); #endif var value = propertyInfo.GetValue(null, null); return value as IEntityFactory; }).ToList(); foreach (var factory in factories) { var type = factory.GetType(); var methodInfo = type.GetMethod("CreateNew", new[] { typeof(Layer) }); var returntypeString = methodInfo.ReturnType.Name; if (entityType.EndsWith("\\" + returntypeString)) { entitiesToRemove.Add(entityType); var indexList = dictionary[tileName]; foreach (var tileIndex in indexList) { float left; float bottom; layer.GetBottomLeftWorldCoordinateForOrderedTile(tileIndex, out left, out bottom); if (float.IsNaN(dimension)) { int vertexIndex = tileIndex * 4; dimension = layer.Vertices[vertexIndex + 1].Position.X - layer.Vertices[vertexIndex].Position.X; dimensionHalf = dimension / 2.0f; } var entity = factory.CreateNew(flatRedBallLayer) as PositionedObject; if (entity != null) { entity.X = left + dimensionHalf; entity.Y = bottom + dimensionHalf; } } } } } } }
private static void RemoveTilesFromLayer(List<List<NamedValue>> filteredInfos, MapDrawableBatch layer) { List<int> indexes = new List<int>(); foreach (var itemThatPasses in filteredInfos) { string tileName = itemThatPasses .FirstOrDefault(item => item.Name.ToLowerInvariant() == "name") .Value as string; if (layer.NamedTileOrderedIndexes.ContainsKey(tileName)) { var intsOnThisLayer = layer.NamedTileOrderedIndexes[tileName]; indexes.AddRange(intsOnThisLayer); } } layer.RemoveQuads(indexes); }
private static void RemoveTilesFromLayer(List <List <NamedValue> > filteredInfos, MapDrawableBatch layer) { List <int> indexes = new List <int>(); foreach (var itemThatPasses in filteredInfos) { string tileName = itemThatPasses .FirstOrDefault(item => item.Name.ToLowerInvariant() == "name") .Value as string; if (layer.NamedTileOrderedIndexes.ContainsKey(tileName)) { var intsOnThisLayer = layer.NamedTileOrderedIndexes[tileName]; indexes.AddRange(intsOnThisLayer); } } layer.RemoveQuads(indexes); }
internal static MapDrawableBatch FromReducedLayer(TMXGlueLib.DataTypes.ReducedLayerInfo reducedLayerInfo, string contentManagerName, int tileDimensionWidth, int tileDimensionHeight, float quadWidth, float quadHeight) { string textureName = reducedLayerInfo.Texture; Texture2D texture = FlatRedBallServices.Load<Texture2D>(textureName, contentManagerName); #if DEBUG if (!MathFunctions.IsPowerOfTwo(texture.Width) || !MathFunctions.IsPowerOfTwo(texture.Height)) { throw new Exception("The dimensions of the texture file " + texture.Name + " are not power of 2!"); } #endif MapDrawableBatch toReturn = new MapDrawableBatch(reducedLayerInfo.Quads.Count, tileDimensionWidth, tileDimensionHeight, texture); Vector3 position = new Vector3(); Vector2 tileDimensions = new Vector2(quadWidth, quadHeight); foreach (var quad in reducedLayerInfo.Quads) { position.X = quad.LeftQuadCoordinate; position.Y = quad.BottomQuadCorodinate; var textureValues = new Vector4(); textureValues.X = (float)quad.LeftTexturePixel / (float)texture.Width; // Left textureValues.Y = (float)(quad.LeftTexturePixel + tileDimensionWidth) / (float)texture.Width; // Right textureValues.Z = (float)quad.TopTexturePixel / (float)texture.Height; // Top textureValues.W = (float)(quad.TopTexturePixel + tileDimensionHeight) / (float)texture.Height; // Bottom const bool pad = true; if (pad) { const float amountToAdd = .0000001f; textureValues.X += amountToAdd; // Left textureValues.Y -= amountToAdd; // Right textureValues.Z += amountToAdd; // Top textureValues.W -= amountToAdd; // Bottom } int tileIndex = toReturn.AddTile(position, tileDimensions, //quad.LeftTexturePixel, quad.TopTexturePixel, quad.LeftTexturePixel + tileDimensionWidth, quad.TopTexturePixel + tileDimensionHeight); textureValues); toReturn.RegisterName(quad.Name, tileIndex); } return toReturn; }
/* This creates a MapDrawableBatch (MDB) from the list of sprites provided to us by the FlatRedBall (FRB) Scene XML (scnx) file. */ public static MapDrawableBatch FromSpriteSaves(List<SpriteSave> spriteSaveList, int startingIndex, int count, string contentManagerName, bool verifySameTexturesPerLayer) { #if DEBUG if (verifySameTexturesPerLayer) { VerifySingleTexture(spriteSaveList, startingIndex, count); } #endif // We got it! We are going to make some assumptions: // First we need the texture. We'll assume all Sprites // use the same texture: // TODO: I (Bryan) really HATE this assumption. But it will work for now. SpriteSave firstSprite = spriteSaveList[startingIndex]; // This is the file name of the texture, but the file name is relative to the .scnx location string textureRelativeToScene = firstSprite.Texture; // so we load the texture Texture2D texture = FlatRedBallServices.Load<Texture2D>(textureRelativeToScene, contentManagerName); if (!MathFunctions.IsPowerOfTwo(texture.Width) || !MathFunctions.IsPowerOfTwo(texture.Height)) { throw new Exception("The dimensions of the texture file " + texture.Name + " are not power of 2!"); } // Assume all the dimensions of the textures are the same. I.e. all tiles use the same texture width and height. // This assumption is safe for Iso and Ortho tile maps. int tileFileDimensionsWidth = 0; int tileFileDimensionsHeight = 0; if (spriteSaveList.Count > startingIndex) { SpriteSave s = spriteSaveList[startingIndex]; // deduce the dimensionality of the tile from the texture coordinates tileFileDimensionsWidth = (int)System.Math.Round((double)((s.RightTextureCoordinate - s.LeftTextureCoordinate) * texture.Width)); tileFileDimensionsHeight = (int)System.Math.Round((double)((s.BottomTextureCoordinate - s.TopTextureCoordinate) * texture.Height)); } // alas, we create the MDB MapDrawableBatch mMapBatch = new MapDrawableBatch(count, tileFileDimensionsWidth, tileFileDimensionsHeight, texture); int lastIndexExclusive = startingIndex + count; for (int i = startingIndex; i < lastIndexExclusive; i++) { SpriteSave spriteSave = spriteSaveList[i]; // here we have the Sprite's X and Y in absolute coords as well as its texture coords // NOTE: I appended the Z coordinate for the sake of iso maps. This SHOULDN'T have an effect on the ortho maps since I believe the // TMX->SCNX tool sets all z to zero. // The AddTile method expects the bottom-left corner float x = spriteSave.X - spriteSave.ScaleX; float y = spriteSave.Y - spriteSave.ScaleY; float z = spriteSave.Z; float width = 2f * spriteSave.ScaleX; // w float height = 2f * spriteSave.ScaleY; // z float topTextureCoordinate = spriteSave.TopTextureCoordinate; float bottomTextureCoordinate = spriteSave.BottomTextureCoordinate; float leftTextureCoordinate = spriteSave.LeftTextureCoordinate; float rightTextureCoordinate = spriteSave.RightTextureCoordinate; int tileIndex = mMapBatch.mCurrentNumberOfTiles; mMapBatch.RegisterName(spriteSave.Name, tileIndex); // add the textured tile to our map so that we may draw it. mMapBatch.AddTile(new Vector3(x, y, z), new Vector2(width, height), new Vector4(leftTextureCoordinate, rightTextureCoordinate, topTextureCoordinate, bottomTextureCoordinate)); } return mMapBatch; }
/* This creates a MapDrawableBatch (MDB) from the list of sprites provided to us by the FlatRedBall (FRB) Scene XML (scnx) file. */ public static MapDrawableBatch FromSpriteSaves(List<SpriteSave> spriteSaveList, int startingIndex, int count, string contentManagerName, bool verifySameTexturesPerLayer) { #if DEBUG if (verifySameTexturesPerLayer) { VerifySingleTexture(spriteSaveList, startingIndex, count); } #endif // We got it! We are going to make some assumptions: // First we need the texture. We'll assume all Sprites // use the same texture: // TODO: I (Bryan) really HATE this assumption. But it will work for now. SpriteSave firstSprite = spriteSaveList[startingIndex]; // This is the file name of the texture, but the file name is relative to the .scnx location string textureRelativeToScene = firstSprite.Texture; // so we load the texture Texture2D texture = FlatRedBallServices.Load<Texture2D>(textureRelativeToScene, contentManagerName); if (!MathFunctions.IsPowerOfTwo(texture.Width) || !MathFunctions.IsPowerOfTwo(texture.Height)) { throw new Exception("The dimensions of the texture file " + texture.Name + " are not power of 2!"); } // Assume all the dimensions of the textures are the same. I.e. all tiles use the same texture width and height. // This assumption is safe for Iso and Ortho tile maps. int tileFileDimensionsWidth = 0; int tileFileDimensionsHeight = 0; if (spriteSaveList.Count > startingIndex) { SpriteSave s = spriteSaveList[startingIndex]; // deduce the dimensionality of the tile from the texture coordinates tileFileDimensionsWidth = (int)System.Math.Round((double)((s.RightTextureCoordinate - s.LeftTextureCoordinate) * texture.Width)); tileFileDimensionsHeight = (int)System.Math.Round((double)((s.BottomTextureCoordinate - s.TopTextureCoordinate) * texture.Height)); } // alas, we create the MDB MapDrawableBatch mMapBatch = new MapDrawableBatch(count, tileFileDimensionsWidth, tileFileDimensionsHeight, texture); int lastIndexExclusive = startingIndex + count; for (int i = startingIndex; i < lastIndexExclusive; i++) { SpriteSave spriteSave = spriteSaveList[i]; // We don't want objects within the IDB to have a different Z than the IDB itself // (if possible) because that makes the IDB behave differently when using sorting vs. // the zbuffer. const bool setZTo0 = true; mMapBatch.Paste(spriteSave, setZTo0); } return mMapBatch; }
internal static MapDrawableBatch FromReducedLayer(TMXGlueLib.DataTypes.ReducedLayerInfo reducedLayerInfo, TMXGlueLib.DataTypes.ReducedTileMapInfo rtmi, string contentManagerName) { int tileDimensionWidth = rtmi.CellWidthInPixels; int tileDimensionHeight = rtmi.CellHeightInPixels; float quadWidth = rtmi.QuadWidth; float quadHeight = rtmi.QuadHeight; string textureName = reducedLayerInfo.Texture; #if IOS || ANDROID textureName = textureName.ToLowerInvariant(); #endif Texture2D texture = FlatRedBallServices.Load<Texture2D>(textureName, contentManagerName); #if DEBUG if (!MathFunctions.IsPowerOfTwo(texture.Width) || !MathFunctions.IsPowerOfTwo(texture.Height)) { throw new Exception("The dimensions of the texture file " + texture.Name + " are not power of 2!"); } #endif MapDrawableBatch toReturn = new MapDrawableBatch(reducedLayerInfo.Quads.Count, tileDimensionWidth, tileDimensionHeight, texture); toReturn.Name = reducedLayerInfo.Name; Vector3 position = new Vector3(); Vector2 tileDimensions = new Vector2(quadWidth, quadHeight); IEnumerable<TMXGlueLib.DataTypes.ReducedQuadInfo> quads = null; if (rtmi.NumberCellsWide > rtmi.NumberCellsTall) { quads = reducedLayerInfo.Quads.OrderBy(item => item.LeftQuadCoordinate); toReturn.mSortAxis = SortAxis.X; } else { quads = reducedLayerInfo.Quads.OrderBy(item => item.BottomQuadCoordinate); toReturn.mSortAxis = SortAxis.Y; } foreach (var quad in quads) { position.X = quad.LeftQuadCoordinate; position.Y = quad.BottomQuadCoordinate; // The Z of the quad should be relative to this layer, not absolute Z values. // A multi-layer map will offset the individual layer Z values, the quads should have a Z of 0. // position.Z = reducedLayerInfo.Z; var textureValues = new Vector4(); textureValues.X = (float)quad.LeftTexturePixel / (float)texture.Width; // Left textureValues.Y = (float)(quad.LeftTexturePixel + tileDimensionWidth) / (float)texture.Width; // Right textureValues.Z = (float)quad.TopTexturePixel / (float)texture.Height; // Top textureValues.W = (float)(quad.TopTexturePixel + tileDimensionHeight) / (float)texture.Height; // Bottom // pad before doing any rotations/flipping const bool pad = true; if (pad) { const float amountToAdd = .0000001f; textureValues.X += amountToAdd; // Left textureValues.Y -= amountToAdd; // Right textureValues.Z += amountToAdd; // Top textureValues.W -= amountToAdd; // Bottom } if ((quad.FlipFlags & TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedHorizontallyFlag) == TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedHorizontallyFlag) { var temp = textureValues.Y; textureValues.Y = textureValues.X; textureValues.X = temp; } if ((quad.FlipFlags & TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedVerticallyFlag) == TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedVerticallyFlag) { var temp = textureValues.Z; textureValues.Z = textureValues.W; textureValues.W = temp; } int tileIndex = toReturn.AddTile(position, tileDimensions, //quad.LeftTexturePixel, quad.TopTexturePixel, quad.LeftTexturePixel + tileDimensionWidth, quad.TopTexturePixel + tileDimensionHeight); textureValues); if ((quad.FlipFlags & TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedDiagonallyFlag) == TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedDiagonallyFlag) { toReturn.ApplyDiagonalFlip(tileIndex); } toReturn.RegisterName(quad.Name, tileIndex); } return toReturn; }
internal static MapDrawableBatch FromReducedLayer(TMXGlueLib.DataTypes.ReducedLayerInfo reducedLayerInfo, TMXGlueLib.DataTypes.ReducedTileMapInfo rtmi, string contentManagerName) { int tileDimensionWidth = rtmi.CellWidthInPixels; int tileDimensionHeight = rtmi.CellHeightInPixels; float quadWidth = rtmi.QuadWidth; float quadHeight = rtmi.QuadHeight; string textureName = reducedLayerInfo.Texture; #if IOS || ANDROID textureName = textureName.ToLowerInvariant(); #endif Texture2D texture = FlatRedBallServices.Load <Texture2D>(textureName, contentManagerName); #if DEBUG if (!MathFunctions.IsPowerOfTwo(texture.Width) || !MathFunctions.IsPowerOfTwo(texture.Height)) { throw new Exception("The dimensions of the texture file " + texture.Name + " are not power of 2!"); } #endif MapDrawableBatch toReturn = new MapDrawableBatch(reducedLayerInfo.Quads.Count, tileDimensionWidth, tileDimensionHeight, texture); toReturn.Name = reducedLayerInfo.Name; Vector3 position = new Vector3(); Vector2 tileDimensions = new Vector2(quadWidth, quadHeight); IEnumerable <TMXGlueLib.DataTypes.ReducedQuadInfo> quads = null; if (rtmi.NumberCellsWide > rtmi.NumberCellsTall) { quads = reducedLayerInfo.Quads.OrderBy(item => item.LeftQuadCoordinate); toReturn.mSortAxis = SortAxis.X; } else { quads = reducedLayerInfo.Quads.OrderBy(item => item.BottomQuadCoordinate); toReturn.mSortAxis = SortAxis.Y; } foreach (var quad in quads) { position.X = quad.LeftQuadCoordinate; position.Y = quad.BottomQuadCoordinate; // The Z of the quad should be relative to this layer, not absolute Z values. // A multi-layer map will offset the individual layer Z values, the quads should have a Z of 0. // position.Z = reducedLayerInfo.Z; var textureValues = new Vector4(); textureValues.X = (float)quad.LeftTexturePixel / (float)texture.Width; // Left textureValues.Y = (float)(quad.LeftTexturePixel + tileDimensionWidth) / (float)texture.Width; // Right textureValues.Z = (float)quad.TopTexturePixel / (float)texture.Height; // Top textureValues.W = (float)(quad.TopTexturePixel + tileDimensionHeight) / (float)texture.Height; // Bottom // pad before doing any rotations/flipping const bool pad = true; if (pad) { const float amountToAdd = .0000001f; textureValues.X += amountToAdd; // Left textureValues.Y -= amountToAdd; // Right textureValues.Z += amountToAdd; // Top textureValues.W -= amountToAdd; // Bottom } if ((quad.FlipFlags & TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedHorizontallyFlag) == TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedHorizontallyFlag) { var temp = textureValues.Y; textureValues.Y = textureValues.X; textureValues.X = temp; } if ((quad.FlipFlags & TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedVerticallyFlag) == TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedVerticallyFlag) { var temp = textureValues.Z; textureValues.Z = textureValues.W; textureValues.W = temp; } int tileIndex = toReturn.AddTile(position, tileDimensions, //quad.LeftTexturePixel, quad.TopTexturePixel, quad.LeftTexturePixel + tileDimensionWidth, quad.TopTexturePixel + tileDimensionHeight); textureValues); if ((quad.FlipFlags & TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedDiagonallyFlag) == TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedDiagonallyFlag) { toReturn.RotateTextureCoordinatesCounterclockwise(tileIndex); } toReturn.RegisterName(quad.Name, tileIndex); } return(toReturn); }
/* This creates a MapDrawableBatch (MDB) from the list of sprites provided to us by the FlatRedBall (FRB) Scene XML (scnx) file. */ public static MapDrawableBatch FromSpriteSaves(List <SpriteSave> spriteSaveList, int startingIndex, int count, string contentManagerName, bool verifySameTexturesPerLayer) { #if DEBUG if (verifySameTexturesPerLayer) { VerifySingleTexture(spriteSaveList, startingIndex, count); } #endif // We got it! We are going to make some assumptions: // First we need the texture. We'll assume all Sprites // use the same texture: // TODO: I (Bryan) really HATE this assumption. But it will work for now. SpriteSave firstSprite = spriteSaveList[startingIndex]; // This is the file name of the texture, but the file name is relative to the .scnx location string textureRelativeToScene = firstSprite.Texture; // so we load the texture Texture2D texture = FlatRedBallServices.Load <Texture2D>(textureRelativeToScene, contentManagerName); if (!MathFunctions.IsPowerOfTwo(texture.Width) || !MathFunctions.IsPowerOfTwo(texture.Height)) { throw new Exception("The dimensions of the texture file " + texture.Name + " are not power of 2!"); } // Assume all the dimensions of the textures are the same. I.e. all tiles use the same texture width and height. // This assumption is safe for Iso and Ortho tile maps. int tileFileDimensionsWidth = 0; int tileFileDimensionsHeight = 0; if (spriteSaveList.Count > startingIndex) { SpriteSave s = spriteSaveList[startingIndex]; // deduce the dimensionality of the tile from the texture coordinates tileFileDimensionsWidth = (int)System.Math.Round((double)((s.RightTextureCoordinate - s.LeftTextureCoordinate) * texture.Width)); tileFileDimensionsHeight = (int)System.Math.Round((double)((s.BottomTextureCoordinate - s.TopTextureCoordinate) * texture.Height)); } // alas, we create the MDB MapDrawableBatch mMapBatch = new MapDrawableBatch(count, tileFileDimensionsWidth, tileFileDimensionsHeight, texture); int lastIndexExclusive = startingIndex + count; for (int i = startingIndex; i < lastIndexExclusive; i++) { SpriteSave spriteSave = spriteSaveList[i]; // here we have the Sprite's X and Y in absolute coords as well as its texture coords // NOTE: I appended the Z coordinate for the sake of iso maps. This SHOULDN'T have an effect on the ortho maps since I believe the // TMX->SCNX tool sets all z to zero. // The AddTile method expects the bottom-left corner float x = spriteSave.X - spriteSave.ScaleX; float y = spriteSave.Y - spriteSave.ScaleY; float z = spriteSave.Z; float width = 2f * spriteSave.ScaleX; // w float height = 2f * spriteSave.ScaleY; // z float topTextureCoordinate = spriteSave.TopTextureCoordinate; float bottomTextureCoordinate = spriteSave.BottomTextureCoordinate; float leftTextureCoordinate = spriteSave.LeftTextureCoordinate; float rightTextureCoordinate = spriteSave.RightTextureCoordinate; int tileIndex = mMapBatch.mCurrentNumberOfTiles; mMapBatch.RegisterName(spriteSave.Name, tileIndex); // add the textured tile to our map so that we may draw it. mMapBatch.AddTile(new Vector3(x, y, z), new Vector2(width, height), new Vector4(leftTextureCoordinate, rightTextureCoordinate, topTextureCoordinate, bottomTextureCoordinate)); } return(mMapBatch); }
internal static MapDrawableBatch FromReducedLayer(TMXGlueLib.DataTypes.ReducedLayerInfo reducedLayerInfo, LayeredTileMap owner, TMXGlueLib.DataTypes.ReducedTileMapInfo rtmi, string contentManagerName) { int tileDimensionWidth = reducedLayerInfo.TileWidth; int tileDimensionHeight = reducedLayerInfo.TileHeight; float quadWidth = reducedLayerInfo.TileWidth; float quadHeight = reducedLayerInfo.TileHeight; string textureName = reducedLayerInfo.Texture; #if IOS || ANDROID textureName = textureName.ToLowerInvariant(); #endif Texture2D texture = FlatRedBallServices.Load <Texture2D>(textureName, contentManagerName); MapDrawableBatch toReturn = new MapDrawableBatch(reducedLayerInfo.Quads.Count, tileDimensionWidth, tileDimensionHeight, texture); toReturn.Name = reducedLayerInfo.Name; Vector3 position = new Vector3(); Vector2 tileDimensions = new Vector2(quadWidth, quadHeight); IEnumerable <TMXGlueLib.DataTypes.ReducedQuadInfo> quads = null; if (rtmi.NumberCellsWide > rtmi.NumberCellsTall) { quads = reducedLayerInfo.Quads.OrderBy(item => item.LeftQuadCoordinate).ToList(); toReturn.mSortAxis = SortAxis.X; } else { quads = reducedLayerInfo.Quads.OrderBy(item => item.BottomQuadCoordinate).ToList(); toReturn.mSortAxis = SortAxis.Y; } foreach (var quad in quads) { position.X = quad.LeftQuadCoordinate; position.Y = quad.BottomQuadCoordinate; // The Z of the quad should be relative to this layer, not absolute Z values. // A multi-layer map will offset the individual layer Z values, the quads should have a Z of 0. // position.Z = reducedLayerInfo.Z; var textureValues = new Vector4(); // The purpose of CoordinateAdjustment is to bring the texture values "in", to reduce the chance of adjacent // tiles drawing on a given tile quad. If we don't do this, we can get slivers of adjacent colors appearing, causing // lines or grid patterns. // To bring the values "in" we have to consider rotated quads. textureValues.X = CoordinateAdjustment + (float)quad.LeftTexturePixel / (float)texture.Width; // Left textureValues.Y = -CoordinateAdjustment + (float)(quad.LeftTexturePixel + tileDimensionWidth) / (float)texture.Width; // Right textureValues.Z = CoordinateAdjustment + (float)quad.TopTexturePixel / (float)texture.Height; // Top textureValues.W = -CoordinateAdjustment + (float)(quad.TopTexturePixel + tileDimensionHeight) / (float)texture.Height; // Bottom // pad before doing any rotations/flipping const bool pad = true; if (pad) { const float amountToAdd = .0000001f; textureValues.X += amountToAdd; // Left textureValues.Y -= amountToAdd; // Right textureValues.Z += amountToAdd; // Top textureValues.W -= amountToAdd; // Bottom } if ((quad.FlipFlags & TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedHorizontallyFlag) == TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedHorizontallyFlag) { var temp = textureValues.Y; textureValues.Y = textureValues.X; textureValues.X = temp; } if ((quad.FlipFlags & TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedVerticallyFlag) == TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedVerticallyFlag) { var temp = textureValues.Z; textureValues.Z = textureValues.W; textureValues.W = temp; } int tileIndex = toReturn.AddTile(position, tileDimensions, //quad.LeftTexturePixel, quad.TopTexturePixel, quad.LeftTexturePixel + tileDimensionWidth, quad.TopTexturePixel + tileDimensionHeight); textureValues); if ((quad.FlipFlags & TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedDiagonallyFlag) == TMXGlueLib.DataTypes.ReducedQuadInfo.FlippedDiagonallyFlag) { toReturn.ApplyDiagonalFlip(tileIndex); } // This was moved to outside of this conversion, to support shaps //if (quad.QuadSpecificProperties != null) //{ // var listToAdd = quad.QuadSpecificProperties.ToList(); // listToAdd.Add(new NamedValue { Name = "Name", Value = quad.Name }); // owner.Properties.Add(quad.Name, listToAdd); //} if (quad.RotationDegrees != 0) { // Tiled rotates clockwise :( var rotationRadians = -MathHelper.ToRadians(quad.RotationDegrees); Vector3 bottomLeftPos = toReturn.Vertices[tileIndex * 4].Position; Vector3 vertPos = toReturn.Vertices[tileIndex * 4 + 1].Position; MathFunctions.RotatePointAroundPoint(bottomLeftPos, ref vertPos, rotationRadians); toReturn.Vertices[tileIndex * 4 + 1].Position = vertPos; vertPos = toReturn.Vertices[tileIndex * 4 + 2].Position; MathFunctions.RotatePointAroundPoint(bottomLeftPos, ref vertPos, rotationRadians); toReturn.Vertices[tileIndex * 4 + 2].Position = vertPos; vertPos = toReturn.Vertices[tileIndex * 4 + 3].Position; MathFunctions.RotatePointAroundPoint(bottomLeftPos, ref vertPos, rotationRadians); toReturn.Vertices[tileIndex * 4 + 3].Position = vertPos; } toReturn.RegisterName(quad.Name, tileIndex); } return(toReturn); }