monogame using Tiled tilemap

I don’t have a working example yet - I will put something up when I do.

@lonely-unicorn

This displays text in the top left showing the X,Y and tile type currently under the mouse.

4 Likes

I downloaded the code to a separate folder to test it works.

There a few things to watch out for:
The content manager application has relative paths in the References.

To ensure the paths work, you need to Unzip the file into this folder:
C:\Users\YOURUSERNAME\source\repo

Load the solution into Visual Studio (I am using 2022 community edition).

Right click on Solution in the Solution Explorer pane and select “Restore nuget packages”.

Open the content manager and build it.

Build the solution.

1 Like

Fantastic! I was looking for the same.

There is a person here writing tutorials on github for monogame.
I think a Tiled tutorial could be made out of this.
Maybe you can contact him to add it?

Is it correct the tile type is the ID you can see in the tileset in Tiled map editor or am I wrong?

Would you maybe be so kind to add to this code example a layer to the existing map that define collision objects and a player you can move with the keyboard to show how collisions are done using monogame.extended?
I can’t figure it out.

Yes - its the Tile ID that you can see when you edit the tiles in Tiled application.

I am looking at collisions at the moment.
What I have done so far is:

  1. read in the Tiled map
  2. Go through all the tiles and add a rectangle to the monogame.extended.collisions object for each tile that I want to block the player.

This is working fine - but as you suggest, I think it would be better to use a separate layer on the map or alternatively, use a custom property on the tile to indicate it blocks.

image

1 Like

Thx! Please upload the example when ready :slight_smile:

I was also wondering if you know if there is a way to change a Tiled map using monogame.extended.
Can we change a tile type when a player moves over the tile and for example presses a key “T” to change the tile to another type? (or can maps only be read-only)

thx

Hi

I think the code example is not reading the tile type correctly.
If I compare to Tiled, I get wrong IDs.

Look at screenshot. The yellow color tiles are all type 15 as read by the code example.

But if I look in Tiled, tile with ID 15 is not completely yellow.
It has grass at the right side. So all yellow tiles can’t have ID 15 …
See below.

Good catch. I hit the same issue yesterday in my main project.
The issue is Tiled uses a start ID for each TileSet in the map called “firstGid”.

This allows multiple TileSets to be used in the same map.

The problem is, monogame.extended.Tiled is not making this firstGid attribute available in the code.
You can see it’s there in the map file (samplemap.tmx):
tileset firstgid=“1” source="[A]Grass_pipo.tsx"
tileset firstgid=“529” source="[A]Water_pipo.tsx"

If the TileId returned is 1-528, that means it’s in the first tileset.
If it’s > 529 its in the second tileset.

As we don’t have access to the 1 or 529, it’s impossible to tell which tile set.
According to the documentation, the first TileSet always has firstGid = 1 so for now, I have changed the code to just subtract 1 from the index which fixes the tiles from the first tileset (everything except the water).

    private void UpdateTileText(int x, int y)
    {
        if (ContainsXY(x, y))
        {
            int tileX, tileY;
            GetTileXYAtPoint(x, y, out tileX, out tileY);
            var tile = _tiledMap.TileLayers[0].GetTile((ushort)tileX, (ushort)tileY);
            _tileText = $"{tileX}, {tileY} TileType: [{tile.GlobalIdentifier - 1}]";      // Subtract firstGid (== 1) here
        }
    }

I can’t see how to support multiple tileSets at the moment without changing the monogame.extended.Tiled code.

Options:

  • Switch to another Tiled package such as TiledCS
  • Change monogame.extended.tiled and add firstGid to the class. I took a look at the code and it looks like it reads it in from the file so I may be missing something.

Tiled docs are here:
https://doc.mapeditor.org/en/stable/reference/tmx-map-format/#tmx-tileset

I have solved the issue now.
monogame.extended.tiled TiledMap class has this function:

public int GetTilesetFirstGlobalIdentifier(TiledMapTileset tileset)

The tileSet and tile offset can be found like this:

    private string GetTileText(TiledMap map, int id)
    {
        foreach (var tileSet in map.Tilesets)
        {
            int firstGid = map.GetTilesetFirstGlobalIdentifier(tileSet);

            if ((id >= firstGid) && (id < firstGid + tileSet.TileCount))
                return $"{tileSet.Name}: {id - firstGid}";
        }

        return "Unknown";            
    }

I have updated the Git repository.

Great! Thanks to your explanation, everything is very understandable now!
(this should be in the monogame.extended docs so everybody sees how it works)
For some reason monogame.extended adds “_0” to the name of a tileset, do you know why? (it’s not a real problem)
They are called Grass_pipo_0 and Water_pipo_0

Do you still want to make a collisions layer and a moving player by using monogame.extended?

  • I’m also interested in the most easy way of handling collisions (preferred by a layer which you don’t draw on the screen, but is just used for collisions)

  • I don’t know for sure how to know on what tile a moving player is currently standing. What method to use for this (instead of the mouse code)?

If interested, I would love to see both things above added (or another project if you don’t want to add it to this one)

Thanks in advance!

Hi

For some reason the water tiles all have ID 454 but some have ID 2758.
Do you have an idea why? Because the tiles are all the same.
If you look in the tileset 454 and 2758 seem to be identical too (how they look) but they have other IDs.

I made a screenshot and indicated in red the water that has ID 2758. All other water tiles have ID 454

Please let me know if you have an explanation for this.

thanks!
Lisa

Hi

I found a youtube video that shows collisions on a Tiled map by using TiledSharp.
Maybe you can use this to get an idea to make the same by using monogame.extended?
I understand how they do it, but don’t know the code for monogame.extended (they loop through the “collisions” layer)

Here is the github

Thx
Lisa

There is a bit of work to add a player and collisions.

Take a look at monogame.extended.collisions.

This is what I am doing (in my main project - not the TiledExample)

  • create a Tile class which implements ICollisionActor interface
  • create a Player class which implements ICollisionActor interface
  • create a CollisionComponent class which handles the collisions
  • create an array of Tile which corresponds to the tiles in the map
  • Add all the blocking tiles and the player to the CollisionComponent.

Follow the docs above to setup the OnCollision method in the Player classes.
The Tile OnCollision doesn’t need to do anything.

do you want to share that example too if finished?

i have no idea how to do it :frowning:
Can’t it be made like the video i showed but with code from monogame.extended to read the “collisions” layer?
Because your way seems much more work/difficult.

thx
Lisa

Can you tell me how to read a layer of a Tiled map with name “collisions” by using monogame.extended?
Maybe I can replace the code of the video then by this monogame.extended code.

The video is using TiledSharp which is no longer supported (also I found it unwatchable unless I muted the horrendous music :laughing:)

I’m not using a separate layer for collisions - I added a custom attribute to each tile (in Tiled) to indicate whether it blocks movement.
image

You need to read up on the monogame.extended.collisions docs and understand them before you can proceed.

I literally followed the example code on their page.

Take bite sized pieces and work on each one before trying the next ‘bite’:

  1. get your Tiled map displayed on the screen
  2. get your player character displaying on the screen
  3. allow the player to be moved around using the keys
  4. Add in collision support by following the monogame.extended.collisions example.

This code sets up the array of Tile objects - one for each tile in the map.
It looks up the tile at Layer[0] to see if it blocks and if it does it adds it to the collisions handler.

    // member variables
    private TiledMap _tileMap;
    private TiledMapRenderer _tiledMapRenderer;
    private OrthographicCamera _camera;
    private Vector2 _cameraPosition;

    private CollisionComponent _collisionHandler;
...
    _collisionHandler = new CollisionComponent(new RectangleF(0, 0, 800, 600));
...

    public void InitialiseTiles()
    {
        _tileMap = GraphicsManager.Instance.GetMap();
        _tiledMapRenderer = new TiledMapRenderer(GraphicsManager.Instance.GetGraphicsDevice(), _tileMap);

        var viewportadapter = new BoxingViewportAdapter(GraphicsManager.Instance.GetWindow(), GraphicsManager.Instance.GetGraphicsDevice(), 800, 600);
        _camera = new OrthographicCamera(viewportadapter);
        _cameraPosition = new Vector2(512, 384);

        _tiles = new LevelTile[_tileMap.Width, _tileMap.Height];
        for (int i = 0; i < _tileMap.Width; i++)
        {
            for (int j = 0; j < _tileMap.Height; j++)
            {
                int tileType = -1;
                var tile = _tileMap.TileLayers[0].GetTile((ushort)i, (ushort)j);

                var tileSet = _tileMap.GetTilesetByTileGlobalIdentifier(tile.GlobalIdentifier);
                if (tileSet == null) continue;

                tileType = GetTileId(_tileMap, tileSet, tile.GlobalIdentifier);
                if (tileType < 0) continue;

                _tiles[i, j] = new LevelTile(i, j, tile.GlobalIdentifier, 0);

                if (tileSet.Tiles[tileType].Properties.ContainsKey("Blocks"))
                {
                    string blocks;
                    tileSet.Tiles[tileType].Properties.TryGetValue("Blocks", out blocks);

                    if (blocks == "true")
                        _collisionHandler.Insert(_tiles[i, j]);
                }
            }
        }
    }

    private int GetTileId(TiledMap map, TiledMapTileset tileSet, int id)
    {
        int firstGid = map.GetTilesetFirstGlobalIdentifier(tileSet);          
        if ((id >= firstGid) && (id < firstGid + tileSet.TileCount))
                return id - firstGid;
        
        return -1;
    }

(I am not in a position to upload my working project at this stage.)

Once your project is working, do you want to upload it then?
Because it’s too difficult for me (i’m both a C# and monogame beginner)

Lisa

Hi

I’m also interested to see the project.
If you want, you can put it on github?