protected override void OnMouseUnclick(int button) { if (button == 0) // Only handle left clicks, ignore others. { TileMap orig = world.Map; // Save TileMap here. TileMap copy = new TileMap(orig.Width, orig.Height, orig.TileWidth, orig.TileHeight, orig.LayerCount, orig.SubLayerCount); Tile tile; for (int i = 0; i < orig.Width; ++i) { for (int j = 0; j < orig.Height; ++j) { tile = orig[i,j]; if (tile != null) copy[i, j] = tile; } } copy.Minimize(); world.ShiftWorldObjects(-EditorScreen.Offset); XDocument tileDoc = new XDocument(copy.ToXElement()); tileDoc.Save("..\\..\\..\\Content\\"+orig.FileName+".xml"); XDocument worldDoc = new XDocument(world.ToXElement()); worldDoc.Save("..\\..\\..\\Content\\WorldXML\\TestWorld.xml"); world.ShiftWorldObjects(EditorScreen.Offset); } base.OnMouseUnclick(button); }
public TileMapLayer(Screen parentScreen, SpriteBatch spriteBatch, TileMap tm, int layerIndex, float scrollSpeed) : this(parentScreen, spriteBatch, tm, layerIndex) { this.drawEdgesEnabled = false; this.drawBlanksEnabled = false; this.scrollSpeed = scrollSpeed; }
public TileMap LoadTileMap(string imageFileName, string settingsFileName) { Texture2D layer = ScreenManager.Instance.Content.Load<Texture2D>(imageFileName); Color[] allPixels = new Color[(layer.Width * layer.Height)]; layer.GetData<Color>(allPixels); Dictionary<Color, SubTexture> lookupTable = LoadSettingsFile(settingsFileName); TileMap tm = new TileMap(layer.Width, layer.Height, 20, 20, 1, 1); // For now just 1 layer and 1 sublayer. (1 total texture per tile) for (int i = 0; i < allPixels.Length; i++) { int x = i % layer.Width; int y = i / layer.Width; SubTexture[,] textures = new SubTexture[1,1]; textures[0, 0] = lookupTable[allPixels[i]]; Tile t; t = textures[0,0] != null ? new Tile(textures) : null; tm.SetTile(t, x, y); } return tm; }
public TileMapLayer(Screen parentScreen, SpriteBatch spriteBatch, TileMap tm, int layerIndex) : base(parentScreen, spriteBatch, Vector2.Zero) { this.drawEdgesEnabled = false; this.drawBlanksEnabled = false; this.drawDestructablesEnabled = false; this.layerIndex = layerIndex; scrollSpeed = 1.0f; this.tm = tm; }
// TODO: add proper support for parallax layers. This will require a new class that derives from // TileMapLayer and overrides Draw() private void LoadWorldXmlFile(string fileName) { XDocument fileContents = ScreenManager.Instance.Content.Load<XDocument>(fileName); #region LOAD INTERACTIVE MAP LAYERS // Load the interactive TileMap: map = new TileMap(this, fileContents.Root.Attribute("InteractiveMapFileName").Value); for (int i = 0; i < map.Width; ++i) { for (int j = 0; j < map.Height; ++j) { if (map[i, j] != null && map[i, j] is ISpriteCollideable) { spriteCollisionManager.addObjectToRegisteredObjectList((ISpriteCollideable)map[i, j]); } } } IEnumerable<XElement> allMapLayers = fileContents.Descendants("MapLayer"); foreach (XElement mapLayer in allMapLayers) { string LayerName; int LayerIndex, ZIndex; LayerName = mapLayer.Attribute("LayerName").Value; LayerIndex = Int32.Parse(mapLayer.Attribute("LayerIndex").Value); ZIndex = Int32.Parse(mapLayer.Attribute("ZIndex").Value); interactiveLayers[ZIndex] = new TileMapLayer(ParentScreen, batchService.GetSpriteBatch(TileMapLayer.SpriteBatchName), map, LayerIndex); interactiveLayers[ZIndex].DrawOrder = ZIndex; ParentScreen.Components.Add(interactiveLayers[ZIndex]); } #endregion #region LOAD CHARACTERS // Add the player: Vector2 playerPosition = new Vector2(float.Parse(fileContents.Root.Attribute("PlayerPositionX").Value), float.Parse(fileContents.Root.Attribute("PlayerPositionY").Value)); player = new Player(this, spriteBatch, playerPosition); player.UpdateOrder = 3; player.DrawOrder = PLAYER_DRAW_ORDER; ParentScreen.Components.Add(player); spriteCollisionManager.addObjectToRegisteredObjectList(player); foreach (XElement woElement in fileContents.Descendants("o")) { string name = woElement.Attribute("n").Value; Vector2 position = new Vector2(); position.X = float.Parse(woElement.Attribute("x").Value); position.Y = float.Parse(woElement.Attribute("y").Value); ConstructorInfo ci = (from CI in WorldObjectCtorInfos where CI.DeclaringType.Name == name select CI).First<ConstructorInfo>(); AddWorldObject((WorldObject)ci.Invoke(new object[]{this, SpriteBatch, position})); } #endregion #region LOAD PARALLAX LAYERS IEnumerable<XElement> allParallaxMaps = fileContents.Descendants("Parallax"); // A parallaxMap is made up of a tileMap just like the interactive map, // so it can have multiple layers in and of itself. This might not be common // but the functionality is there. foreach (XElement parallaxMap in allParallaxMaps) { IEnumerable<XElement> allParallaxLayers = parallaxMap.Descendants("Layer"); float ScrollSpeed; TileMap tileMap; tileMap = new TileMap(this, parallaxMap.Attribute("MapFileName").Value); otherMaps.Add(tileMap); ScrollSpeed = Single.Parse(parallaxMap.Attribute("ScrollSpeed").Value); foreach (XElement parallaxLayer in allParallaxLayers) { string LayerName; int LayerIndex, ZIndex; LayerName = parallaxLayer.Attribute("LayerName").Value; LayerIndex = Int32.Parse(parallaxLayer.Attribute("LayerIndex").Value); ZIndex = Int32.Parse(parallaxLayer.Attribute("ZIndex").Value); parallaxLayers[ZIndex] = new TileMapLayer(ParentScreen, batchService.GetSpriteBatch(TileMapLayer.SpriteBatchName), tileMap, LayerIndex, ScrollSpeed); parallaxLayers[ZIndex].DrawOrder = ZIndex; ParentScreen.Components.Add(parallaxLayers[ZIndex]); } } #endregion }
/// <summary> /// Allows the game to perform any initialization it needs to before starting to run. /// This is where it can query for any required services and load any non-graphic /// related content. Calling base.Initialize will enumerate through any components /// and initialize them as well. /// </summary> public override void Initialize() { if (!this.IsInitialized) { tileEngine = new TileEngine(); fullScreenSettings = new ResolutionSettings(640, 480, 640, 480, true); ScreenManager.Instance.ResolutionService.CurrentResolutionSettings = windowedSettings; batchService = (ISpriteBatchService)this.Game.Services.GetService(typeof(ISpriteBatchService)); // Create a new, empty world: world = new World(this, WORLD_FILENAME); // We need to disable the SpriteSpriteCollisionManager because it makes some assumptions about // the gameScreen... world.SpriteCollisionManager.Enabled = false; // Create an empty, maximally-sized tilemap to center // the loaded map onto: TileMap bigMap = new TileMap(MAX_TILEMAP_WIDTH, MAX_TILEMAP_HEIGHT, DEFAULT_TILE_WIDTH, DEFAULT_TILE_HEIGHT, LAYER_COUNT, SUB_LAYER_COUNT); bigMap.FileName = world.Map.FileName; // Backup the original map: TileMap map = world.Map; // Compute the point where we want to blit it onto the empty map: this.offsetX = (bigMap.Width / 2) - (map.Width / 2); this.offsetY = (bigMap.Height / 2) - (map.Height / 2); bigMap.BlitTileMap(map, offsetX, offsetY); world.Map = bigMap; foreach (TileMapLayer tml in world.interactiveLayers.Values) { Components.Remove(tml); } world.interactiveLayers.Clear(); world.ShiftWorldObjects(new Vector2(world.Map.TileWidth * offsetX, world.Map.TileWidth * offsetY)); for (int i = 0; i < world.Map.LayerCount; ++i) { TileMapLayer tml = new TileMapLayer(this, batchService.GetSpriteBatch(TileMapLayer.SpriteBatchName), world.Map, i); if (i == 0) { tml.DrawOrder = World.PLAYER_DRAW_ORDER - DEFAULT_LAYER_SPACING; } else { if (i == world.Map.LayerCount - 1) { tml.DrawBlanksEnabled = true; tml.DrawEdgesEnabled = true; tml.DrawDestructablesEnabled = true; } tml.DrawOrder = World.PLAYER_DRAW_ORDER + i * DEFAULT_LAYER_SPACING; } world.interactiveLayers[tml.DrawOrder] = tml; Components.Add(world.interactiveLayers[tml.DrawOrder]); } world.Initialize(); world.Camera.Position = world.Player.Position;// -new Vector2(world.Camera.VisibleArea.Width / 2, world.Camera.VisibleArea.Height / 2); world.Paused = true; Components.Add(world); // Set up editor controls: inputMonitor = InputMonitor.Instance; inputMonitor.AssignPressable("EditorLeft", new PressableKey(Keys.A)); inputMonitor.AssignPressable("EditorRight", new PressableKey(Keys.D)); inputMonitor.AssignPressable("EditorUp", new PressableKey(Keys.W)); inputMonitor.AssignPressable("EditorDown", new PressableKey(Keys.S)); inputMonitor.AssignPressable("EditorAppend", new PressableKey(Keys.LeftShift)); inputMonitor.AssignPressable("ToggleFullScreen", new PressableKey(Keys.F)); inputMonitor.AssignPressable("EditorCycleMode", new PressableKey(Keys.Tab)); Components.Add(inputMonitor); CreateUIComponents(); Mode = EditMode.SpriteEdit; CycleMode(); // Initialize all components base.Initialize(); } }
/// <summary> /// Given a list of tile coordinates, create a new TileMap from this /// TileMap that contains copies of each Tile that corresponds to every /// coordinate in the list. /// </summary> /// <param name="tileCoordinates"> /// A List of 2D coordinate sets, each represented as a 2-element array of integers. /// Format: /// int[0] => Tile X coordinate. /// int[1] => Tile Y coordinate. /// This List represents each Tile you want to copy into the new TileMap that will be /// returned from this function. /// </param> /// <returns> /// The resulting TileMap will be just big enough to fit all Tiles /// specified by the tileCoordinates List, and all in-between Tiles /// that aren't specified in the list will be null. /// </returns> public TileMap SubTileMapFromCoordList(List<int[]> tileCoordinates) { TileMap subTileMap; if (tileCoordinates.Count > 0) { // First, compute the minimum required width and height: int minX, minY, maxX, maxY, w, h; minX = minY = 999999999; maxX = maxY = 0; foreach (int[] tileCoord in tileCoordinates) { minX = Math.Min(tileCoord[0], minX); minY = Math.Min(tileCoord[1], minY); maxX = Math.Max(tileCoord[0], maxX); maxY = Math.Max(tileCoord[1], maxY); } w = maxX - minX + 1; h = maxY - minY + 1; subTileMap = new TileMap(w, h, TileWidth, TileHeight, LayerCount, SubLayerCount); foreach (int[] tileCoord in tileCoordinates) { Tile tile = this[tileCoord[0], tileCoord[1]]; DestructableTile destructable = this[tileCoord[0], tileCoord[1]] as DestructableTile; if (destructable != null) { subTileMap.SetTile(destructable, tileCoord[0] - minX, tileCoord[1] - minY); } else if (tile != null) { subTileMap.SetTile(tile, tileCoord[0] - minX, tileCoord[1] - minY); } } } else { subTileMap = new TileMap(0, 0, TileWidth, TileHeight, LayerCount, SubLayerCount); } return subTileMap; }
/// <summary> /// "Blit" another TileMap onto this one, replacing all tiles with those from /// the other TileMap, even if they are null. /// Note that each tile is *copied*. They are not references to the same tiles. /// /// That's right, "Blit"... this is the closest thing to actual 2D /// graphics programming I've encountered while writing this game. ;) /// </summary> /// <param name="other">The TileMap to stamp onto ours.</param> /// <param name="xOffset"> /// The x component of the coordinate in this TileMap where the other TileMap /// will be stamped (topleft corner). /// </param> /// <param name="yOffset"> /// The y component of the coordinate in this TileMap where the other TileMap /// will be stamped (topleft corner). /// </param> public void BlitTileMap(TileMap other, int xOffset, int yOffset) { int startY = yOffset < 0 ? -yOffset : 0; Tile tile; for (int i = xOffset < 0 ? -xOffset : 0; i < other.Width && i + xOffset < Width; ++i) { for (int j = startY; j < other.Height && j + yOffset < Height; ++j) { tile = other[i,j]; if(tile == null) { SetTile(null, i + xOffset, j + yOffset); } else { DestructableTile destructable = other[i,j] as DestructableTile; if (destructable != null) { SetTile(new DestructableTile(tile, destructable.World, i + xOffset, j + yOffset, destructable.MaxHealth), i + xOffset, j + yOffset); } else { SetTile(new Tile(tile), i + xOffset, j + yOffset); } } } } }