Update to the docs to make them more filled out and detailed to make it easier to get started
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 :)
