Difference between revisions of "Setup and map example"
(→Create a New Class) |
(→Drawing Objects) |
||
(2 intermediate revisions by the same user not shown) | |||
Line 96: | Line 96: | ||
spriteBatch.End(); | spriteBatch.End(); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | =Draw a Tiled layer= | ||
+ | I have noticed that using Squared.Tiled layers are drawn in alphabetical order, so it often appears that your layers aren't drawn. Your object layers will be drawn within this alphabetical order also. You could fix alternatively draw your layers separately. Quite often, not all layers are drawn. For example the top down racing game I created seems to have 2 layers which are drawn but has a layer that doesn't. So instead you can create a Layer in Game1.cs, read the Layer from the map and then draw the Layer separately in the draw method. | ||
+ | |||
+ | In the declaration section of your Game1.cs you can declare a Layer: | ||
+ | |||
+ | <syntaxhighlight lang=c#> | ||
+ | Layer testLayer; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | you can then add the following in the LoadContent method to read in the layer: | ||
+ | |||
+ | <syntaxhighlight lang=c#> | ||
+ | testLayer = map.Layers["LayerName"]; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Now in the Draw method, and you must put this code after the code to draw your map: | ||
+ | |||
+ | <syntaxhighlight lang=c#> | ||
+ | testLayer.Draw(spriteBatch, | ||
+ | map.Tilesets.Values, | ||
+ | new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight), | ||
+ | new Vector2(300,300), | ||
+ | 128, | ||
+ | 128); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | The map.Tilesets.Values passes the tileset into the layers draw method. The rectangle should be how much of the map is displayed, The Vector2 is the position in the map, these should obviously match the position & viewport specified in the code to draw the main map. 128 is the dimensions of each tile, you could get this directly from the map so: | ||
+ | |||
+ | <syntaxhighlight lang=c#> | ||
+ | testLayer.Draw(spriteBatch, | ||
+ | map.Tilesets.Values, | ||
+ | new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight), | ||
+ | new Vector2(300,300), | ||
+ | map.TileWidth, | ||
+ | map.TileHeight); | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==Drawing the map layer by layer== | ||
+ | |||
+ | You could alternatively in the draw method of Game1.cs, remove your map.Draw() line and instead do something like this to select each layer in turn: | ||
+ | |||
+ | <syntaxhighlight lang=c#> | ||
+ | foreach (Layer testlayer in Map.Layers.Values) | ||
+ | { | ||
+ | if (testlayer.Name != "Collision") | ||
+ | { | ||
+ | testLayer.Draw(spriteBatch, | ||
+ | map.Tilesets.Values, | ||
+ | new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight), | ||
+ | new Vector2(300,300), | ||
+ | map.TileWidth, | ||
+ | map.TileHeight); | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | The above example will not draw the layer called Collision. Remember the layers will be drawn in alphabetical order. | ||
+ | |||
+ | =Drawing Objects= | ||
+ | The layer foreach loop above will not draw any objects. You can draw the objects within an object layer or object group by doing the following, but the easiest approach is to name your layers alphabetically including your object layers: | ||
+ | |||
+ | <syntaxhighlight lang=c#> | ||
+ | foreach (Squared.Tiled.Object test in Map.ObjectGroups["Objects"].Objects.Values) | ||
+ | { | ||
+ | if (test.Texture != null) | ||
+ | { | ||
+ | test.Draw( | ||
+ | spriteBatch, | ||
+ | new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight), //window | ||
+ | new Vector2(0,0), //Offset | ||
+ | new Vector2(300,300), //Position | ||
+ | 1f //float for opacity | ||
+ | ); | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | |||
+ | =Get Texture of a Tile= | ||
+ | [[Get tile texture from map]] |
Latest revision as of 12:05, 17 February 2024
Contents
Create a New Class
You will need to have a MonoGame project in order to complete this. If you have a project ready, create a new class in your project.
Copy the code from this document: Square.Tiled Class
Or from GitHub: GitHub TRCCompSci tiled-xna
Add Using Refereneces
You will need to add references to the following:
using System.IO;
using Squared.Tiled;
New Variables
At the top of your Game1 class add these additional variables:
Map map;
Vector2 viewportPosition;
The name viewportPosition is important because the rest of the class uses it, so if you use a different name it may not work.
Content
Download the file from here. Extract it and you must build the 2 images using the content pipeline.
In the LoadContent method add the following line to load the map:
map = Map.Load(Path.Combine(Content.RootDirectory, "MapTest.tmx"), Content);
Now the map contains an object layer called events, and this contains a start position for hero. Use the code below to add a texture to the hero:
map.ObjectGroups["events"].Objects["hero"].Texture = Content.Load<Texture2D>("hero");
Now we need to set the viewportPosition, this will ensure the map starts with the player in the center. So add the following code:
viewportPosition= new Vector2(map.ObjectGroups["events"].Objects["hero"].X, map.ObjectGroups["events"].Objects["hero"].Y);
In order to center the hero you may need to subtract from either the X or Y.
The Update Method
scroll & scrolly are used to store the direction required.
These are multiplied by the scroll speed to get the exact X & Y movement required.
The X & Y of the hero are updated to give a new position.
GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);
KeyboardState keyState = Keyboard.GetState();
float scrollx = 0, scrolly = 0;
if (keyState.IsKeyDown(Keys.Left))
scrollx = -1;
if (keyState.IsKeyDown(Keys.Right))
scrollx = 1;
if (keyState.IsKeyDown(Keys.Up))
scrolly = 1;
if (keyState.IsKeyDown(Keys.Down))
scrolly = -1;
scrollx += gamePadState.ThumbSticks.Left.X;
scrolly += gamePadState.ThumbSticks.Left.Y;
if (gamePadState.IsButtonDown(Buttons.Back) || keyState.IsKeyDown(Keys.Escape))
this.Exit();
float scrollSpeed = 8.0f;
map.ObjectGroups["events"].Objects["hero"].X += (int)(scrollx * scrollSpeed);
map.ObjectGroups["events"].Objects["hero"].Y -= (int)(scrolly * scrollSpeed);
You will also need to update the viewportPosition:
viewportPosition= new Vector2(map.ObjectGroups["events"].Objects["hero"].X, map.ObjectGroups["events"].Objects["hero"].Y);
The Draw Method
Add the following to the draw method to draw the map and hero to the screen.
If you already have spriteBatch.Begin() or spriteBatch.End() then just place the middle line inbetween your lines.
spriteBatch.Begin();
map.Draw(spriteBatch, new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height), viewportPosition);
spriteBatch.End();
Draw a Tiled layer
I have noticed that using Squared.Tiled layers are drawn in alphabetical order, so it often appears that your layers aren't drawn. Your object layers will be drawn within this alphabetical order also. You could fix alternatively draw your layers separately. Quite often, not all layers are drawn. For example the top down racing game I created seems to have 2 layers which are drawn but has a layer that doesn't. So instead you can create a Layer in Game1.cs, read the Layer from the map and then draw the Layer separately in the draw method.
In the declaration section of your Game1.cs you can declare a Layer:
Layer testLayer;
you can then add the following in the LoadContent method to read in the layer:
testLayer = map.Layers["LayerName"];
Now in the Draw method, and you must put this code after the code to draw your map:
testLayer.Draw(spriteBatch,
map.Tilesets.Values,
new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight),
new Vector2(300,300),
128,
128);
The map.Tilesets.Values passes the tileset into the layers draw method. The rectangle should be how much of the map is displayed, The Vector2 is the position in the map, these should obviously match the position & viewport specified in the code to draw the main map. 128 is the dimensions of each tile, you could get this directly from the map so:
testLayer.Draw(spriteBatch,
map.Tilesets.Values,
new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight),
new Vector2(300,300),
map.TileWidth,
map.TileHeight);
Drawing the map layer by layer
You could alternatively in the draw method of Game1.cs, remove your map.Draw() line and instead do something like this to select each layer in turn:
foreach (Layer testlayer in Map.Layers.Values)
{
if (testlayer.Name != "Collision")
{
testLayer.Draw(spriteBatch,
map.Tilesets.Values,
new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight),
new Vector2(300,300),
map.TileWidth,
map.TileHeight);
}
}
The above example will not draw the layer called Collision. Remember the layers will be drawn in alphabetical order.
Drawing Objects
The layer foreach loop above will not draw any objects. You can draw the objects within an object layer or object group by doing the following, but the easiest approach is to name your layers alphabetically including your object layers:
foreach (Squared.Tiled.Object test in Map.ObjectGroups["Objects"].Objects.Values)
{
if (test.Texture != null)
{
test.Draw(
spriteBatch,
new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight), //window
new Vector2(0,0), //Offset
new Vector2(300,300), //Position
1f //float for opacity
);
}
}