Files
MonoGame.Extended/Docs/Features/Tiled.md
T
HellFireDragonandDylan Wilson 9cef465c3a Updating and filling Documentation (#637)
Update to the docs to make them more filled out and detailed to make it easier to get started
2019-10-08 20:44:30 +10:00

18 KiB

Tiled

The MonoGame.Extended.Tiled library loads and renders maps created with the popular Tiled Map Editor.

Tiled is an open sourced free to use "generic tile map editor". Tiled lets you easily design and view tile maps, and through the Monogame.Extended.Tiled package, you can load and display a map generated with Tiled in monogame

To load a TiledMap into your project, you first need to add it to your ContentManager, and in order to compile the tile map for use in MonoGame you must add a reference to the pipeline tool.

Instructions to do so can be found here

Using the map in your game

The first thing you will need to do is to add the library your reference like this

// The tiled map parts
using MonoGame.Extended.Tiled;
// The tile renderers
using MonoGame.Extended.Tiled.Renderers;

Its recomended to use a camera aswell when you use tiled maps

// To get the camera
using MonoGame.Extended;
// Then you need a viewport adapter
using MonoGame.Extended.ViewportAdapters;
// The camera object
private OrthographicCamera camera;

To get a map to render you will need 2 new properties

// The tile map
private TiledMap map;
// The renderer for the map
private TiledMapRenderer mapRenderer;

Now we want to initialize the things, you can do this in either the Initialize() or LoadContent() methods

protected override void Initialize() 
{
    base.Initialize();

    // Load the map
    map = Content.Load<TiledMap>("path/to/your/map/file");
    // Create the map renderer
    mapRenderer = new TiledMapRenderer(GraphicsDevice, map);
    // If you decided to use the camere, then you could also initialize it here like this
    var viewportadapter = new BoxingViewportAdapter(Window, GraphicsDevice, 800, 600);
    camera = new OrthographicCamere(viewportadapter);
}

Now after all this we will need to update and draw the mapRenderer, we do this in the Update() and Draw() methods like this

protected override void Update(GameTime gameTime)
{
    // Update the map renderer
    mapRenderer.Update(gameTime);
    // If you used the camera then we update it aswell
    camera.LookAt(new Vector2(0, 0));

    base.Update(gameTime);
}

protected override void Draw(GameTime gameTime)
{
    // Clear the screen
    GraphicsDevice.Clear(Color.White);

    // Transform matrix is only needed if you have a camera
    // Setting the sampler state to `new SamplerState { Filter = TextureFilter.Point }` will reduce gaps and odd artifacts when using animated tiles
    spriteBatch.Begin(transformMatrix: camera.GetViewMatrix(), samplerState: new SamplerState { Filter = TextureFilter.Point });

    // Then we will render the map
    mapRenderer.Draw(camera.GetViewMatrix());

    // End the sprite batch
    spriteBatch.End();

    base.Draw(gameTime);
}

Help with the many things

Here we will just go into what some of the functions do

The TiledMap, this is what contains the map data generated by Tiled, this will contain all the diffrent layers and tilesets that your map uses.

The TiledMapTileLayer, this is what contains the array of id's that tell your renderer what to draw at specific locations, they will generally be usefull for drawing the environment. But can also be used for simple collision detection.

The TiledMapObjectLayer, this is what contains all the data for your many map objects, this will generally be usefull for things like telling where to spawn the player, what happens when something is over it and so on.

The TiledMapRenderer, this is what draws your map, simple as that.

Some examples for this

If you are still not sure how you can use this, you may want to look at some example code, and here you will get just that!

Simple collision handler

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using MonoGame.Extended;
using MonoGame.Extended.Animations;
using MonoGame.Extended.Animations.SpriteSheets;
using MonoGame.Extended.Sprites;
using MonoGame.Extended.TextureAtlases;
using MonoGame.Extended.Tiled;
using MonoGame.Extended.Tiled.Renderers;
using MonoGame.Extended.ViewportAdapters;

namespace MapCollisions
{
    // Control states to determine what animation to play
    public enum PlayerStates
    {
        Up,
        Down,
        Left,
        Right,
        Idle,
    }

    public class Player
    {
        private readonly AnimatedSprite sprite; // The sprite
        private float _directionX = 0.0f; // The left and right direction
        private float _directionY = 0.0f; // The up and down direction
        private PlayerStates state;

        private Transform2 transform;
        private const float movementSpeed = 4f; // How fast the player moves
        private const int minimumDistance = 8; // The minimum distance the player can be from a wall

        public RectangleF BoundingBox => sprite.GetBoundingRectangle(transform.Position, transform.Rotation, transform.Scale);

        public Vector2 Position
        {
            get { return transform.Position; }
            set { transform.Position = value; }
        }

        // Update the playerstate
        public PlayerStates State
        {
            get { return state; }
            private set
            {
                if (state != value)
                {
                    state = value;

                    switch (state)
                    {
                        case PlayerStates.Up:
                            sprite.Play("WalkUp", () => State = PlayerStates.Idle);
                            break;
                        case PlayerStates.Down:
                            sprite.Play("WalkDown", () => State = PlayerStates.Idle);
                            break;
                        case PlayerStates.Left:
                            sprite.Play("WalkLeft", () => State = PlayerStates.Idle);
                            break;
                        case PlayerStates.Right:
                            sprite.Play("WalkRight", () => State = PlayerStates.Idle);
                            break;
                        case PlayerStates.Idle:
                            sprite.Play("Idle");
                            break;
                    }
                }
            }
        }

        // The player constructor
        public Player(SpriteSheetAnimationFactory animations, Vector2 startposition)
        {
            sprite = new AnimatedSprite(animations);
            transform = new Transform2();

            Position = startposition;

            State = PlayerStates.Idle;
        }

        // Check for if the player can go to the location
        public bool CanGoTo(TiledMapTileLayer tileLayer)
        {
            TiledMapTile? tile;
            if (_directionX != 0.0f && _directionY != 0.0f)
            {
                if (_directionX < 0.0f)
                {
                    if (_directionY < 0.0f)
                    {
                        ushort tx = (ushort)((Position.X - minimumdist) / tileLayer.TileWidth);
                        ushort ty = (ushort)((Position.Y + minimumdist) / tileLayer.TileHeight);
                        tileLayer.TryGetTile(tx, ty, out tile);
                        if (!tile.Value.IsBlank)
                        {
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    }
                    else
                    {
                        ushort tx = (ushort)((Position.X - minimumdist) / tileLayer.TileWidth);
                        ushort ty = (ushort)((Position.Y - minimumdist) / tileLayer.TileHeight);
                        tileLayer.TryGetTile(tx, ty, out tile);
                        if (!tile.Value.IsBlank)
                        {
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    }
                }
                else
                {
                    if (_directionY < 0.0f)
                    {
                        ushort tx = (ushort)((Position.X + minimumdist) / tileLayer.TileWidth);
                        ushort ty = (ushort)((Position.Y + minimumdist) / tileLayer.TileHeight);
                        tileLayer.TryGetTile(tx, ty, out tile);
                        if (!tile.Value.IsBlank)
                        {
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    }
                    else
                    {
                        ushort tx = (ushort)((Position.X + minimumdist) / tileLayer.TileWidth);
                        ushort ty = (ushort)((Position.Y - minimumdist) / tileLayer.TileHeight);
                        tileLayer.TryGetTile(tx, ty, out tile);
                        if (!tile.Value.IsBlank)
                        {
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    }
                }
            }
            else if (_directionX != 0.0f)
            {
                if (_directionX < 0.0f)
                {
                    ushort tx = (ushort)((Position.X - minimumdist) / tileLayer.TileWidth);
                    ushort ty = (ushort)(Position.Y / tileLayer.TileHeight);
                    tileLayer.TryGetTile(tx, ty, out tile);
                    if (!tile.Value.IsBlank)
                    {
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }
                else
                {
                    ushort tx = (ushort)((Position.X + minimumdist) / tileLayer.TileWidth);
                    ushort ty = (ushort)(Position.Y / tileLayer.TileHeight);
                    tileLayer.TryGetTile(tx, ty, out tile);
                    if (!tile.Value.IsBlank)
                    {
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }
            }
            else
            {
                if (_directionY < 0.0f)
                {
                    ushort tx = (ushort)(Position.X / tileLayer.TileWidth);
                    ushort ty = (ushort)((Position.Y + minimumdist) / tileLayer.TileHeight);
                    tileLayer.TryGetTile(tx, ty, out tile);
                    if (!tile.Value.IsBlank)
                    {
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }
                else
                {
                    ushort tx = (ushort)(Position.X / tileLayer.TileWidth);
                    ushort ty = (ushort)((Position.Y - minimumdist) / tileLayer.TileHeight);
                    tileLayer.TryGetTile(tx, ty, out tile);
                    if (!tile.Value.IsBlank)
                    {
                        return false;
                    }
                    else
                    {
                        return true;
                    }
                }
            }
        }

        // Update the controls
        public void ControlUpdate(KeyboardState keyboardstate, KeyboardState oldkeyboardstate, GamePadState gamepadstate, GamePadState oldgamepadstate)
        {
            if (keyboardstate.IsKeyDown(Keys.W) ||
            keyboardstate.IsKeyDown(Keys.Up) ||
            gamepadstate.DPad.Up == ButtonState.Pressed) 
            { 
                this.Walk(0.0f, 1.0f); 
            }
            else if (keyboardstate.IsKeyDown(Keys.S) || 
            keyboardstate.IsKeyDown(Keys.Down) || 
            gamepadstate.DPad.Down == ButtonState.Pressed) 
            { 
                this.Walk(0.0f, -1.0f); 
            }
            else if (keyboardstate.IsKeyDown(Keys.A) ||
            keyboardstate.IsKeyDown(Keys.Left) || 
            gamepadstate.DPad.Left == ButtonState.Pressed) 
            { 
                this.Walk(-1.0f, 0.0f); 
            }
            else if (keyboardstate.IsKeyDown(Keys.D) ||
            keyboardstate.IsKeyDown(Keys.Right) || 
            gamepadstate.DPad.Right == ButtonState.Pressed) 
            { 
                this.Walk(1.0f, 0.0f); 
            }
            else
            {
                this.Walk(0.0f, 0.0f);
            }
        }

        // Update the player location
        public void Update(GameTime gameTime, TiledMapTileLayer tileLayer)
        {
            sprite.Update(gameTime);

            if (State == PlayerState.Down)
            {
                if (CanGoTo(tileLayer) is true)
                {
                    Position = new Vector2(Position.X, Position.Y + movementSpeed);
                }
                else
                {
                    State = PlayerState.Idle;
                }
            }
            if (State == PlayerState.Left)
            {
                if (CanGoTo(tileLayer) is true)
                {
                    Position = new Vector2(Position.X - movementSpeed, Position.Y);
                }
                else
                {
                    State = PlayerState.Idle;
                }
            }
            if (State == PlayerState.Right)
            {
                if (CanGoTo(tileLayer) is true)
                {
                    Position = new Vector2(Position.X + movementSpeed, Position.Y);
                }
                else
                {
                    State = PlayerState.Idle;
                }
            }
            if (State == PlayerState.Up)
            {
                if (CanGoTo(tileLayer) is true)
                {
                    Position = new Vector2(Position.X, Position.Y - movementSpeed);
                }
                else
                {
                    State = PlayerState.Idle;
                }
            }
        }

        // Draw the player
        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(sprite, transform);
        }

        // Walk function to change state
        public void Walk(float directionX, float directionY)
        {
            _directionX = directionX;
            _directionY = directionY;

            if (_directionX != 0.0f && _directionY == 0.0f)
            {
                if (_directionX < 0.0f)
                {
                    State = PlayerState.Left;
                }
                else
                {
                    State = PlayerState.Right;
                }
            }
            else if (_directionX == 0.0f && _directionY != 0.0f)
            {
                if (_directionY < 0.0f)
                {
                    State = PlayerState.Down;
                }
                else
                {
                    State = PlayerState.Up;
                }
            }
            else
            {
                State = PlayerState.Idle;
            }
        }
    }

    public class Game1 : Game
    {
        private readonly GraphicsDeviceManager graphics;
        private SpriteBatch spriteBatch;
        private OrthographicCamera camera;

        private TiledMap map;
        private TiledMapTileLayer mapCollisions;
        private TiledMapRenderer mapRenderer;

        private Player player;

        private KeyboardState keyboard;
        private GamePadState gamepad;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            var viewportAdapter = new BoxingViewportAdapter(Window, GraphicsDevice, 800, 600);
            camera = new OrthographicCamera(viewportAdapter);

            var playeranimations = Content.Load<SpriteSheetAnimationFactory>("playeranimations");

            map = Content.Load<TiledMap>("world");
            mapRenderer = new TiledMapRenderer(GraphicsDevice, map);
            mapCollisions = map.GetLayer<TiledMapLayer>("Collisions");

            var start = map.GetLayer<TiledMapObjectLayer>("Objects").Objects[1].Position;

            player = new Player(playeranimations, start);
        }

        protected override void UnloadContent()
        {
            
        }

        protected override void Update(GameTime gameTime)
        {
            var keyboardstate = Keyboard.GetState();
            var gamepadstate = GamePad.GetState(PlayerIndex.One);

            if (keyboardstate.IsKeyDown(Keys.Excape) || gamepadstate.Buttons.Back == ButtonState.Pressed)
            {
                Exit();
            }

            player.ControlUpdate(keyboardstate, keyboard, gamepadstate, gamepad);
            player.Update(gameTime);
            mapRenderer.Update(gameTime);
            camera.LookAt(player.Position);

            keyboard = keyboardstate;
            gamepad = gamepadstate;

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            spriteBatch(transformMatrix: camera.GetViewMatrix(), samplerState: new SamplerState { Filter = TextureFilter.Point});
            mapRenderer.Draw(camera.GetViewMatrix());
            player.Draw(spriteBatch);
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }

    public static class Program
    {
        [STAThread]
        static void Main()
        {
            using (var game = new Game1())
                game.Run();
        }
    }
}

Good luck and happy coding :)