Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
The following walk-throughs show how to use Tiled to create levels in a FlatRedBall project. It covers creating multiple levels, creating collision from tiles, and creating entities from tiles.
Before we start creating levels with Tiled, we will need to install a few requirements.
First, we need to install FlatRedBall, which can be found on the FlatRedBall Download Page. You may already have this installed if you have have been working with FlatRedBall.
Next, we need to install the Tiled program. Tiled is a free, open source, cross platform editor for creating tile-based levels. We will use Tiled to create levels which can include tiled layers, collision, and entities. Tiled can be downloaded on the Tiled page.
That's it! FlatRedBall automatically includes everything you need to use Tiled, so you can get started right away.
This walk-through creates two screens. The first is a screen called GameScreen which defines what our game has in every level. The second is a screen called Level1 which has files and objects for our first level. GameScreen will be a base class for Level1, and any additional levels will also use GameScreen as a base screen. At the end of this walk-through we will have a tile map rendering in a our game.
The New Project Wizard automatically creates a GameScreen and two Levels if you pick either the Platformer or Top Down project types. This is recommended as the starting point for most projects, and most documentation assumes this setup. Therefore, if you have used the project, you can skip this and move to the next tutorial. If you are interested in how to set this up from scratch, then you can continue reading.
First we'll create a screen called GameScreen. Many FlatRedBall projects contain a GameScreen which typically contains the main gameplay - as opposed to menus to set up the game. The GameScreen also contains any common objects such as lists of entities and game logic. Note that if you have used the Platformer or Top-Down wizard options, you will already have a GameScreen. To add a GameScreen:
In the FRB Editor, select the Quick Actions tab
Click the Add Screen/Level button
Notice that FRB suggests creating a GameScreen. We recommend always having one screen called GameScreen, so this default helps you set your project up quickly.
Click the option to Add Map LayeredTileMap. This sets up a base object for your map which will be used in all levels.
Click the option to Add SolidCollision ShapeCollection. Most games need solid collision so this will set up your game for that.
Leave all other defaults and click OK
Once you click OK you will have a GameScreen which includes Map and SolidCollision objects.
For now we'll leave our GameScreen empty, but we'll return later to add objects.
Above we automatically created the SolidCollision object through a check box. If you didn't check this option, or if you are interested in how to set this up manually, this section will walk you through the process. To manually create the SolidCollision object:
Select the GameScreen in Glue
Go to the Quick Actions tab
Click Add Object to GameScreen
Search for TileShapeCollection in the New Object window
Enter the name SolidCollision
Click OK
Now the SolidCollision should appear in the GameScreen. Next we need to modify the TileShapeCollection to properly use the SolidCollision tile.
Select SolidCollision under GameScreen
Select the TileShapeCollection Properties tab
Select the From Tile Class option under Creation Options
Select the Map under Source TMX File/Object
Enter or select SolidCollision under Tile Class:
Finally we need to set the property as Set By Derived so that level screens can modify this:
Select SolidCollision
Select the Properties tab
Set the SetByDerived property to True
Next we'll create our first level. Levels are regular screens which inherit from a base class that contains common gameplay objects, files, and code. To add Level1:
Go to the Quick Actions tab
Click Add Screen/Level
Verify that the following options are set:
Name Level1 (no spaces)
Add Standard TMX File option is selected. This will add a TMX file to this level for you, saving you extra steps.
Click OK
Once you click the OK button, FRB asks you about details for the new map.
Verify the name is Level1Map. The standard naming is to append the word Map to the name of the Screen containing the new TMX file
Leave the other options default (checked). These options will make it easier to create functional tile maps.
Click OK
You should now have a Level1Map file in your Level1 screen.
FRB should automatically update your Map object in Level1 so that it uses your newly-added TMX file. You can verify this by selecting the Map object and looking at its properties tab.
If your values do not match the values shown in the image above, you can manually change them.
To create a tile map file in Tiled:
Open the Tiled program
Select File->New->New Map...
Set the Tile layer format to Base64 (zlib compressed). Compressing the tile map will make the .tmx file smaller. We will need to change the type of compression used in a later step, since the new file window only lets us pick "zlib".
Set the Tile size to a Width of 16px and a Height of 16px. Tile sizes are usually multiples of 2 (2, 4, 8, 16, 32). This guide uses a tile set with 16x16 tiles.
Click Save As...
Navigate to the Level1's Content folder. You can find this by right-clicking on the GameScreen's Files item in Glue and selecting View in explorer
Save the file as Level1File.tmx
Now that we've created a map, we will change the "Tile Layer Format" to "Base64 (gzip compressed)". We need to make this change after we create the map because Tiled does not let us pick gzip compression when first creating the map, and gzip compression works on all FlatRedBall platforms (zlib does not).
Find the map properties on the left-side of the screen
If the properties window is not open, select the Map -> Map Properties... menu item
Now that the format has been changed, save the file again. Finally the file can be added to the Level1 screen by drag+dropping the file from windows explorer to the Files item under Level1.
The game now references the .tmx file, and when executed the game loads the empty .tmx file.
If you have Tiled installed, then the installer should have associated the .TMX file format with the Tiled program. You can edit the file a few ways:
Double-click the TMX file under Level1 Files
Use the drop-down in the toolbar to select the map to edit
If you followed the previous steps, your map should include:
A single layer called GameplayLayer
A single Tileset called TiledIcons
This tileset was automatically added in an earlier step so that you can hit the ground running on creating your game. It contains common tiles for many games, but this tutorial will focus on the solid collision tile, which is the top-left tile in the tileset.
We can click this tile and place it on the GameplayLayer to create walls, floors, or any other type of solid collision.
Don't forget to save your work in Tiled - otherwise it won't show up in game.
Once you have saved your tileset, you can play the game by pushing the play button in the FRB editor.
Alternatively you can open your project in Visual Studio and build/run it there. Use whichever method you are most comfortable with. Either way, you should see your game run with the Level1 map displayed.
Notice the file may be offset depending on which tiles are painted. This is because the center of the screen is (0,0), which is the top-left of the tile. To adjust the camera so that the top left of the game window matches the top left of the tile map:
Open Visual Studio
Open GameScreen.cs. We could do this in Level1.cs if we wanted it to be logic specific to Level 1, but we want to have this code run for all levels.
Modify the CustomInitialize method as follows:
Now the game will be focused on the map.
Tilesets define the appearance of a collection of tiles along with properties which can be specified per-tile to provide functionality in your game (such as collision). We recommend that games have a dedicated tileset for gameplay functionality such as collision. We used the TiledIcons tileset for this earlier. This section will show you how to add a second tileset for visuals. We will use the following image which you can download:
Files which are used by TMX levels should either be saved in the content folder of one of the level screens or in the content folder in the GameScreen. For this tutorial we'll save the file in the GameScreen folder, since the file will be used by multiple levels. First we'll open the content folder for GameScreen:
Expand GameScreen in the FRB editor
Right-click on the Files folder under GameScreen
Select View in explorer
The content folder for GameScreen will be open (and empty).
Save the tileset (shown above) to the GameScreen content folder (which we just opened).
To use the dungeonTileSet.png file in the tile map:
Open Level1Map.tmx (double-click it in the FRB editor or open it in Windows Explorer)
Drag+drop the dungeonTileSet.png file into the Tilesets tab (the bottom right pane in Tiled)
Verify that Tile width and Tile height are both 16px
Click Save As...
Save the file in the same location as the PNG (the GameScreen content folder)
The tileset (called dungeonTileSet) will now be shown in the Tilesets section in Tiled.
The Tiled program is very flexible when when constructing tilesets. For performance reasons, FlatRedBall does not support all tileset features. When constructing your own tilesets, keep the following in mind:
Each tileset must use exactly one image file. Tiled supports multiple image files per tileset, but FlatRedBall does not.
Each layer in your map can only use one tileset. Tiled supports painting multiple tilesets on one layer, but FlatRedBall does not.
The fewer tilesets, the faster your game will load and render. If possible, try to fit your entire game on one tileset. FlatRedBall supports textures as large as 4096x4096, although some phones and older computers can only load textures as large as 2048x2048.
For organization reasons, it's useful to save the tileset file (.tsx) and image file (.png) in the same folder. This tutorial saves the file in the GameScreen folder, a number of other common options exist. No matter which option you choose, make sure the folder is ultimately inside your game's Content folder:
GameScreen folder (as mentioned above)
Top-level Content folder
GlobalContentFiles folder
Dedicated Tiled folder inside the Content folder
TMX files are the file format that contains the tile map. Along with the TMX file, games that use Tiled will usually reference image files (PNG) and reference external tileset files (TSX). The FRB editor is able to track these references automatically, so only the TMX file needs to be added to your screen (as was done earlier). Any PNG and TSX files referenced by the TMX file will automatically be added to your Visual Studio project by the FRB editor. In other words, once you add a TMX to your screen you don't have to do any other file management anywhere in the FRB editor or Visual Studio.
Once a tileset has been created, tiles can be placed by clicking on a tile in the tile set, then painting on the map. As mentioned above, you cannot mix multiple tilesets into a single layer. Therefore, to place the new visual tiles, you will need a new layer.
Add a new tile layer to your map
Name the layer Visuals
Select the newly-created layer
Select the dungeonTileSet
Paint tiles on the new layer
Keep in mind that changes made to the .tmx file in Tiled must be saved before they will show up in game. Also, the FRB editor automatically manages files referenced by .tmx files, so we do not need to manually add the dungeonTileSet.png file to the GameScreen.
For more information, see the TextureFilter page.
If your tile map does not appear, the following section may help solve the problem.
Loaded tile maps are drawn in the FlatRedBall engine, sorted by their Z value. A single-layer map will be drawn at Z = 0, so any object with a larger Z value will draw in front of the map. If a map has multiple layers, each layer will be 1 unit in front of the layer before it. For example, a map with four layers will have the layers at Z values 0, 1 ,2 and 3. Note that if layers are added under the GameplayLayer, and if Shift Map To Move Gameplay Layer To Z0 is checked, then the map will be shifted on the Z axis so that the GameplayLayer is at Z=0, and all other layers are above or below, each offset by one unit.
This walk-through shows how to perform collision between entities and TileShapeCollection instances. The two most common types tile-based collisions are:
Solid collision - collision which prevents a character from passing through a tile, such as solid walls in a maze
True/false tests - used to perform additional logic when collisions occur, such as dealing damage to a character when touching spikes
We'll be looking at both types.
For this guide, we'll create an entity called Player to test our collision code. This entity needs to be collidable (implements ICollidable) and needs logic for movement in response to input.
Normally top-down and platformer games in FRB use a Player entity as the character. This is a convention which should be followed in your games to make it easier to follow documentation and to integrate with future FRB improvements.
To create a new entity:
In FRB, select the Quick Actions tab
Select Add Entity
Enter the name Player
Check the Circle checkbox to give the entity a circle collision object
Verify that ICollidable is checked - this should happen automatically when Circle is checked
Check the Top-Down option under Input Movement Type to automatically give the Player movement logic
Click OK
Notice the Include lists in all base level screens check box. We will leave this checked so that we have a list of players in our game screen. This is a good idea, even if your game will be single player. The new entity should appear in the Entities folder in the FRB editor.
Since the Player entity has its ImplementsICollidable set to true, any shape (Circle, Polygon, AxisAlignedRectangle) in the entity will be used in collision functions.
Our entity is ready to go - we just need to add it to GameScreen. Note that we're adding the Player to the GameScreen rather than Level1 because we want every level to have a player. To add the entity to GameScreen, drag+drop the entity onto the screen:
The Player now appears on in game screen in the PlayerList and can move with the arrow keys.
We can change the starting position of the player by changing the Player1 X and Y values in the FRB editor.
Select the Player1 in the GameScreen
Click the Variables tab
Change X to 200
Change Y to -200
Now the player appears near the center of the level.
Solid collision can be used to prevent an entity from passing through solid objects on a tile map. In this example we'll be colliding the Player instance against tiles that we set up to have rectangle collision in the previous tutorial. Collision in FlatRedBall is usually performed using CollisionRelationships. A CollisionRelationship is an object which defines what happens when two types of objects overlap (collide). In this case, we'll be creating a CollisionRelationship between our PlayerList and SolidCollision. To create a CollisionRelationship:
Expand GameScreen Objects
Drag+drop the PlayerList onto the SolidCollision object. This creates a new CollisionRelationship named PlayerListVsSolidCollision and automatically selects it.
Change the Collision Physics to Move Collision
As shown in the FRB editor, Move Collision prevents the objects from overlapping. If we run the game now, you will notice that the Player can no longer move through the walls.
This guide focuses on collision between an entity that has basic top-down movement logic. Tile maps are also often used in platformers, and the platformer plugin includes support for colliding against TileShapeCollections. For more information, see the Controlling a Platformer Entity page.
This guide shows how to work with TileShapeCollection to perform solid collision (collision which prevents an entity from passing through the collision area) and non-solid collision (collision which is used to drive custom logic). A typical game may include many TileShapeCollection instances for different types of collision. Although we didn't cover it in this guide, the TileShapeCollection class uses axis-based partitioning for efficient collision. In most cases, even mobile platforms will be able to perform collision against TileShapeCollection instances with tens of thousands of rectangles with very little impact on performance. Developers interested in the details of this partitioning are encouraged to look at the TileShapeCollection source code.
Collisions are used in almost every game. Collisions are often used for the following functionality:
Solid collision to keep players, enemies, and bullets from moving between rooms or out of bounds
Damage collision to deal damage to players, slow movement, or heal players
This tutorial will show how to work with the solid collision, and how to add new types of collision to your game.
By default our game already has SolidCollision defined in the GameScreen. If you used the New Project Wizard, then GameScreen already has a SolidCollision object. If you followed the manual steps in the previous tutorial, then you will have added SolidCollision manually.
Until now the SolidCollisions have been invisible, and we haven't created anything to collide against. Therefore, there hasn't been any functionality yet either. We can verify that the SolidCollision shape collection is actually being created by making it visible. To do this:
Expand the GameScreen in FlatRedBall
Select the SolidCollision object. Note that it is blue, indicating that it is visible to children screens such as Level1
Click the Variables tab
Check the Visible property
If you run the game now, you will see that all solid collision tiles are outlined in white. This is the SolidCollision object.
You may want to keep collision visibility set to true to help diagnose problems in your game, but you should turn it to false when your game is ready to distribute.
As mentioned above, the SolidCollision shape collection is a common object, so the FRB editor provides quick defaults for this type. Your game may need additional TileShapeCollections for additional types of collision. For example, your game may need special collision for spikes that the player can walk over, but which deal damage to the player.
For the rest of this tutorial we will cover how to create a new TileShapeCollection. At a high level, the steps are:
Decide on a tile to use for collision
Set the Type on the tile
Create a new TileShapeCollection in GameScreen
Configure the TileShapeCollection to be created from the tile type specified earlier
The first step is to decide which tile you would like to use for your collision. As we mentioned before, all gameplay tiles (such as collision) should be on the TiledIcons. To mark a tile as collidable:
Open Tiled
Click the TiledIcons tileset
Click the Edit icon to edit the TiledIcons tileset
Select a Tile that you would like to use for collision
Enter a Class for that tile.
Don't forget to save your tileset file
Now that the type has been set and the tileset has been saved, you can place the tile in your level. Make sure to place it on the GameplayLayer in case your game has multiple layers.
Be sure to save your map after adding tiles.
Now that we have a new tile type in our game, we can add another TileShapeCollection. To do this:
In FlatRedBall, select the GameScreen
Click the Quick Actions tab
Select the Add Object to GameScreen button
Type or look for TileShapeCollection in the window and select this option
Enter the name for your tileset. Usually this should match the type of your tile.
Click OK
TileShapeCollections usually come from specific tiles in tile maps. We'll set up the TileShapeCollection created in the previous section here. To do this:
Select the newly-created TileShapeCollection
Click the TileShapeCollection Properties tab
Select the From Type option
Select Map as the source TMX
Select the matching type in the Type dropdown
Notice that Remove Tiles is checked by default. Uncheck this option if you would like to see the tiles in game. We should also turn on collision visibility to make sure it is created as we expect.
If you run your game, you will see the collision in game. The tiles will be removed if the Remove Tiles checkbox was left checked.
As mentioned earlier, TileShapeCollection instances can also be created in code. For more information on creating collision code from Tiles, see these links:
Change the Tile Layer Format to Base64 (gzip compressed)
Texture filtering is a method of making objects look less-pixellated when zoomed in. Most 3D games apply a form of "non-point" linear filtering, which removes the square pixel looks of zoomed-in textures. Unfortunately, since tile maps pack each tile adjacent to one-another, this can cause lines to appear between each tile when running the game in FlatRedBall. For example, consider the horizontal lines which appear on the tree and purple ground in the following image: To avoid this, point filtering should be used. To apply point filtering, add the following code, preferably in Game1.cs Initialize, after initializing FlatRedBall:
Many tile-based games include multiple levels. This walk-through shows how to set up a multi-level game.
So far our game has two screens:
GameScreen - the base screen for our levels. It contains all common files, objects, and code
Level1 - our first level. It contains files, objects, and code specific to level 1.
Adding additional levels is very easy in the FRB editor. We'll add a second level on this tutorial.
To add a new level we will create a new screen. These steps are the same as what we did before when we added Level 1:
Select the Quick Actions tab
Click the Add Screen/Level option
Enter the name Level2
Uncheck the option to Copy Entities From Other Level. Note, if you want to use Level1 as a copy, you can keep this checked.
Check the Add Standard TMX File checkbox to add a TMX for the new level. Note, if you want to use Level1 as a copy, you can select to Copy TMX from Other Level
Click OK
On the New File window, enter the name Level2Map and leave the defaults checked
Click OK
Now our game has two levels: Level1 and Level2. We can choose which level we want to play by using the drop-down next to the Play button in Glue.
If we play Level2, we will have an empty level since we haven't added any tiles yet. We can edit Level2Map by selecting it in the Tiled dropdown.
Level2Map already has the TiledIcons referenced, and it already has a GameplayLayer, so we can begin placing tiles immediately.
As always, don't forget to save your work or the map won't appear in game. The tiles should appear in your game, along with the collision for the tiles.
FlatRedBall follows an inheritance pattern for levels. the GameScreen serves as the base screen for all levels. This means that the GameScreen contains everything that is common to all levels. This not only includes objects (such as lists of entities) but also relationships and settings on objects. For example, the GameScreen defines a Map object which creates entities from the maps (which is covered in later tutorials).
If you choose to create Screens which do not inherit, you will have to manually reconfigure some of these settings. This is not recommended for new FlatRedBall users. Readers who are more interested in how TMX Files are loaded can read the LayeredTileMap page.
We can switch between levels by switching between the screens for each level. In an actual game switching between levels may happen if a user collides with an object (such as a door) or if all enemies have been killed. For the sake of simplicity we'll switch between levels whenever the space bar is pressed. Note that the logic for switching between levels can be customized per-level, but we'll be using nearly identical code for both. We can switch from Level2 to Level1 by modifying Level2's CustomActivity :
Similarly, we can modify Level1's CustomActivity to go back to Level2 whenever the space bar is pressed again:
Now we can run the game and press the space bar to switch between levels.
So far we've looked at how to create tile maps and have them display in game. We've also used these tile maps to create collision. This guide shows how to instantiate entities by placing tiles in a tile map (no code required).
Entity instances can be created through Tiled or in the Live Edit system. Each has its own benefit so which you choose depends on the type of entity instances you are creating.
If you are placing entities which are uniform (all instances are the same, except for their position), then Tiled entities can be convenient and easier to work with.
If you are palcing entities which must be customized per-instance, or if the appearance of the entity is important when it is being positioned, then placing entities in Live Edit can be easier than working in Tiled.
For information about working in the Live Edit system, see the Live Edit page.
Any type of entity can be created through tile maps, which provides lots of flexibility. For this example, we'll create a simple entity which displays a yellow rectangle called Monster:
Select the Quick Actions tab in the FRB editor and click Add Entity
Name the entity Monster
Check the AxisAlignedRectangle check box
Leave the other options default and click OK
We need to modify the rectangle so it stands out relative to the collision rectangles:
Select the newly-created rectangle (named AxisAlignedRectangleInstance)
Change Width to 12
Change Height to 12
Change Color to Yellow
We will be using the Type property to set the entity type. For a deeper dive on how this property works, see the Type documentation here: http://flatredball.com/documentation/tools/tiled-plugin/using-tiled-object-types/ The documentation linked above shows how to import an XML file created using the FRB editor so that variables defined on Monster (or any other entity) automatically appear in Tiled. For simplicity we'll skip this step, but you may want to perform that additional step for larger projects. To set the Type property:
Open whichever level is currently being loaded in your game in Tiled (such as Level2Map.tmx)
Select the TiledIcons. We should always use TiledIcons to create entities rather than visual tilesets like dungeonTileSet
Click the Edit Tileset button
Select a tile on your map to represent the monsters. For example, select the red monster icon.
Enter the entity name Monster as the Type or Class for this tile. Depending on what version of Tiled that you are using, you may see Class instead of Type, but they both mean the same thing. Also, note that the name needs to match the entity name exactly, including capitalization.
Any tiles placed with the Type or Class of Monster will create Monster instances at runtime. Tiles for creating entities are placed just like any other tiles. We can place a few monster tiles in either level.
As always, don't forget to save your changes on the tile map and tile set. If we run our game, we will see the monster enemies (yellow rectangles).
If enemies aren't showing up, check the following:
Make sure that Level2Tmx.tmx and dungeonTileSet.tsx files have both been saved
Verify that you entered the correct name (including capitalization) in the Type or Class property.
In the previous tutorial we covered how to create entities from tiles. This approach can simplify entity creation, and works great for entities which are uniform (each instance is identical aside from position). Some entities require custom properties per-instance. For example, consider a game where players can walk through doors to enter other maps. In this case, each door entity needs to have a custom property for which level it links to. This walk-through shows how to create object layers in Tiled and how to create entities using these objects.
For this tutorial we will be creating a Door entity which can be used to move the player from one level to the next. This entity will need to have collision so that the player can collide with it and we can respond to the collision. To create a Door entity:
Select the Quick Actions tab in the FRB editor
Click Add Entity
Enter the name Door
Check the Circle check box
Leave the defaults and click OK
Now you will have a Door entity. We should change the color of the door so it doesn't look like the player (which is currently a white circle). To do this, change the CircleInstance's Color value to Green.
We need to create a variable for which level to load when the Player collides with the Door:
Right-click on the Variables folder under the Door entity
Select Add Variable
Select the Create a new variable option
Select string as the Type
Enter the Name LevelToGoTo
Click OK
The name of the variable that we created (LevelToGoTo) needs to match the name of the property that we will be adding to the tile later in this guide. Note that if using a entity types XML, the property will automatically be added.
Tiled object layers allow placing geometric shapes (such as rectangles, circles, and custom polygons) as well as free-floating images (not snapped to the grid). These images (also referred to as "tiles" in the Tiled program) can be used purely for non-interactive visuals or can be used to place entities. Objects can be created and added to tile maps, where each instance has all of its properties set individually, or objects can be given default properties in the tileset. First we'll set up the common properties on our Door tile:
Open TiledIcons.tsx in Tiled (click the edit button if the tsx file is not already open)
Select the door tile
Enter Door as the Type. Note that this may already be the default.
Click the + button to add a new property
Enter the name LevelToGoTo
Verify the type is string
We won't assign the value of LevelToGo yet, we'll do that per-instance. Now that we've defined the Door tile properties, we'll add a Door to the Level2Map.tmx file. Don't forget to save your tileset in Tiled. First we'll make an object layer:
Open Level2Map.tmx in Tiled
Click the Add Layer button
Select Object Layer
Name the new layer GameplayObjectLayer
Next we'll add an instance of the door to the EntityObjectLayer:
Verify that EntityObjectLayer is selected
Select the tile to be placed in the tile set
Click on the tile map to place the tile. Be careful - if you place the door in the same place as where the player starts, the player will immediately collide with the door, and will move to the next level once we add the collision code.
Notice that the placed door may not align with the tiles. If you wish to make it align, you use the Select Objects command to select the tile and either move it visually or change its X an Y properties:
Alternatively, holding the CTRL key will snap objects to the grid while you place them. Now we can add the LevelToGoTo property to our placed tile:
Click the Select Objects button (if not already selected)
Select the placed Door object (if not already selected)
Enter the value Level1 for the LevelToGoTo property. More generally, the door's LevelToGoTo property should be the name of the screen that we want to go to when the Player entity touches the Door.
Don't forget to save the tile map.
If we run our game now, we should see the Door tile that we placed in Tile replaced by a green circle, which is the collision of the Door entity:
If you are not seeing the Door entity in the game, there may be a problem with the Tiled map, the inheritance in your game, or settings on the entity. Fortunately, the process that FlatRedBall uses to create entities on object layers is the same as the process for creating entities on tile layers. Therefore, to troubleshoot the problem you should go back to the previous tutorial and see if you can create entities from tiles. The previous tutorial also includes troubleshooting steps.
We can use the Door entity to navigate between levels. We'll check collision between the Player and all doors in the DoorList object (our game only has one door, but it could be expanded to have more). If a collision occurs, we'll go to the level set by the Door's LevelToGoTo variable. First we'll create a collision relationship between the PlayerList and DoorList in our GameScreen:
Expand the GameScreen Objects folder in Glue
Drag the PlayerList onto the DoorList to create a CollisionRelationship
This time we won't change the Collision Physics because the purpose of the door isn't to block the movement of the player. Instead, we'll create an event which will contain code to move to a different level. To do this:
Scroll down to the bottom of the Collision tab of the newly-created CollisionRelationship
Click the Add Event button
If asked, leave the defaults on the New Event window and click OK
Collision events are added to the Events file for the current screen. In this case, the events are added to GameScreen.Events.cs. To add handle the code:
Open the project in Visual Studio
Open GameScreen.Event.cs. Notice that the newly created collision event will be located under the GameScreen.cs file
Enter the code to move to a screen based on the Door's LevelToGoTo
Now when the player collides with the door in Level2, the game will move to Level1.
Now that we've covered object layers, you can create entities which are either all identical on tile layers or which have custom properties. Here's some things to try next:
Add a door in Level1 which goes back to Level2. Remember, you don't have to set up the CollisionRelationship again. It's already set up in GameScreen which covers all levels.
Try adding collision between the player and monsters. On collision, you can handle the event by restarting the screen (indicating the player has died)
This walkthrough will show how to directly access tile and object-layer tile properties. So far we have covered how to create collision from properties and how to use properties on objects to assign variables on FRB entities. All of these approaches rely on built-in methods to create collision and entities. This tutorial will perform a deeper dive on how to access tile properties for ultimate flexibility. Note that material covered in this tutorial gives the developer the most flexibility, it is not necessary to create a functional game. If you are interested in the bare minimum to get a game running, feel free to skip this tutorial.
Each layer in the the tile map can contain its own list of tiles. For performance reasons each tile is not an individual object. In other words, we can't simply loop through a list of tile objects to check for certain properties. Instead, we have to ask each layer for a list of indexes for a given name. Once we've obtained these indexes, we can get the tile positions and perform custom logic. For example, we can create purple circles wherever we have a tile with the name "Goal" . First we'll need to modify our tileset to set one of our tiles to have the "Goal" name:
Open Tiled
Open the StandardTileset.tsx file
Select a tile which will represent the goal tile
Click the + button to add a new custom property
Enter the name Name
Verify the type is string
Click OK
Set the value for the Name property to Goal
Note that FlatRedBall treats the Name property as the unique identifier for the tile. Therefore, the same name cannot be used for two different tiles - doing so will crash your program. We can modify the GameScreen.cs as shown in the following code:
If you add goals to your game you will see circles added wherever the goals are located:
Warning: The purpose of the code above and much of the code in this guide is to show how to interact with tile properties at a low level. A realistic example would require additional code which would significantly increase the length of this tutorial. Keep in mind that the code above suffers from some serious problems. The created circles are not stored in a list so they cannot be used for any purpose aside from displaying on screen. Furthermore, since the circles are not stored in any list, they cannot be cleaned up. Exiting the screen or switching levels at this point would result in an exception.
The Name property is built-in to the Tiled Plugin, but we can also read custom properties. For example, we can modify the Goal tile to include a property for coloring the circle:
This property can be read through the level's Properties . We'll modify the code to define the color value and default it to Green . It will be set to Yellow if the CircleColor property is Yellow :
We obtain the circle color outside of any loops because the properties set on tiles in a tile set apply to the entire map, so the value will be the same regardless of layer or individual tile. For instance-specific properties we need to use objects on an Object Layer, as we'll show later in this guide. Now our game displays yellow circles:
Tiles can be removed dynamically removed using the RemoveQuads method. For example, we can remove all of the goal tiles used to create circles:
Tiles on "Object Layers" can contain instance-specific properties, as were used to create the Door instance in an earlier guide. We can also access these properties similar to how we access properties on tiles. We'll write code to look for any tiles that have their "Type" property set to "Door", then manually create a door for every tile we find. To do this, add the following function to GameScreen.cs:
Like before, we need to call this method in CustomInitialize :
Of course you may not need to actually run code like this since it's automatically handled by generated code, but this can provide some insight into how to create your own entities in code.
Note that the TileNamesWithType is a shortcut method which gives you all Tile names that happen to have a Type set on them. We can write our own code for accessing the names using custom logic. For example, the following code also checks for all tiles which have a Type property, and which have Type set to "SolidCollision":
Tiled object layers support "tile objects" (images) and geometric shapes. The following geometric object types can be created in Tiled:
Rectangle
Ellipse (similar to Oval)
Polygon
Polyline
Tile (Image)
The first four types (geometric shapes) are added to the Map.ShapeCollections list when loaded. These can be accessed and used at run time for custom collision, such as the creation of triggers.
Shapes can be added to any object layer (such as the existing GameplayObjectLayer in Level2Map), but we'll keep things organized by creating a dedicated ShapesLayer.
In Tiled, click the Add Layer button
Select "Add Object Layer"
Enter the name "ShapesLayer"
To add a rectangle:
In Tiled, click the Insert Rectangle button
Push and drag the left mouse button to draw a Rectangle
Enter the name "Rectangle1" for the new rectangle. This is needed to find the shape at run time.
As always, don't forget to save your changes in Tiled.
We could also selectively make the shape collections visible:
We need to modify CustomInitialize to call ShapeTutorialLogic :
The TMX loading code performs the following logic when deciding where to add shapes:
A perfect circle (not ellipse) are added to the ShapeCollection's Circles list
An un-rotated rectangle are added to the ShapeCollection's Rectangles list
All other shapes (ovals, rotated rectangles, and polygons) are added to the ShapeCollection's Polygons list
We can perform shape-specific logic by accessing the individual lists. For example, we can access the Rectangles instance as shown in the following code:
Tiled files (.tmx) can be included in entities to create visuals which are tile-based. When used in entities, .tmx files are loaded into LayeredTileMap instances which are attached to the entity. This means that the entire tile map inherits the following from the entity that it is a part of:
Position
Rotation
Layer
Visibility
To add a .tmx file to an entity, follow these steps:
Create a .tmx file using the Tiled program. Make sure this .tmx file is saved in the folder structure of your project's content folder.
Create an Entity
Drag+drop the .tmx file onto the entity
Drag+drop the file from inside the entity's Files folder onto the entity's Objects folder
Select Entire File (Layered TileMap) in the Source Name dropdown
Click OK
LayeredTileMap objects use their top-left corner as their origin. This means that the center of the entity will align with the top-left corner of the map. We can observe this by adding a Circle object to an entity which also has a Tiled object.
We can center the tiles on the center of the entity by following these steps:
Open the .tmx file in Tiled
Resize the map so that it there is no empty space around the object
Save the file
Add the following code to the entity's CustomInitialize :
Now the center of the tilemap will align with the center of the entity.
Tiled files added to entities can also be optionally loaded. Games may need to optionally load .tmx files if a single entity can have different visuals, such as a Boss entity which may be drawn by one of many .tmx files. To add an optionally .tmx file to an entity, follow these steps:
Drag+drop the .tmx file into the entity
Select the .tmx file in the Files folder
Change its LoadedOnlyWhenReferenced to True
If your entity has a LayeredTileMap object (which we called EntireFile earlier) remove it - it needs to be created in code instead.
Modify your entity so that its custom code creates and destroys the entity in CustomInitialize and CustomDestroy as shown in the following code:
The LayeredTileMap implements the IDrawableBatch interface, which means it is rendered outside of the FlatRedBall engine. This means that adding an instance of a LayeredTileMap to your game will add at least one render break, and possibly two if it is drawn inbetween standard FlatRedBall objects. Furthermore, each instance of an entity using a LayeredTileMap will introduce additional render breaks. Therefore, you may consider other ways to render your entity visuals if you plan on having a large number of entity instances in your game at the same time - especially for mobile platforms.
The easiest way to use a TMX file is to create a standard GameScreen and Level. This can be accomplished using one of the following methods:
Run the Wizard when creating a new project - this will automatically add TMX files to your project.
If you are not using the GameScreen/Level pattern, you can add your own TMX files to Screens manually. To add a LayeredTileMap from an existing TMX:
Create a TMX file in Tiled
Save the TMX file in a location relative to your game's content folder. Be sure that all PNG files and TSX files (tileset files) are also relative to the game content folder
Create a game screen
Drag+drop the TMX file into your Screen's Files folder
No additional code is necessary - your map will now show up in the screen.
If using the GameScreen/Level pattern, FlatRedBall will automatically set up a Map object which can be used to create entities. If you are creating your own map object manually and you would like to create entities from this map, a small amount of extra work is needed.
Once you have a TMX file in your screen's Files folder, you can create a Map object by drag+dropping the TMX onto the Screen's Objects folder.
Once the Map object has been created, its Create Entities From Tiles property can be checked.
The LayeredTileMap is mostly a List of MapDrawableBatches. For example, you can print out information about a MapDrawableBatch as follows:
Note that TiledObjects.Generated.xml is generated automatically by the FRB editor whenever entities are added, removed, or changed. Therefore, any changes that are made to TiledObjects.Generated.xml manually (either in a text editor or by changing properties in Tiled) will be overwritten the next time the FRB editor generates these objects. In other words, if you choose to use TiledObjects.Generated.xml, then you can only define and modify types through the FRB editor.
To use this file in Tiled:
Open Tiled (you can do this by double-clicking your .tmx file if it's not open already)
Select View -> Object Types Editor. In newer versions of tiled, it may be called Custom Types Editor.
...to open the Object Types Editor window\
Select File -> Choose Object Types File...
Navigate to the location where your TiledObjects.Generated.xml (which should be in the content folder) is located and click Open. Note that if you are in the correct location, but the TiledObjects.Generated.xml is not visible, that you may need to specify .xml in the Object Types files section, as it might be searching for .json files.
After loading the file, you should see any entities in your project which are marked as CreatedByOtherEntities set to true.
Once you have imported the file, Tiled will let you apply this type to tiles in your tileset and objects in your object layers. To create entity instances using tiles:
Open the tileset (.tsx) file in Tiled
Find a tile that you would like to be associated with one of the entities (such as Monster in the example above)
Right-click on the tile and select Tile Properties...
In the properties window, begin typing the type. Notice that Tiled will list all available entities to help you make a selection
Now this tile can be painted on a tilemap.
Creating entities with Tiles is useful if all of the entities are the same (such as coins in a Mario game). However, sometimes entities must differ from instance to instance - such as NPCs in a role playing game, each with different dialog. Tiled objects support setting different values on an instance-by-instance basis. In this case the FRB entity should probably have one or more variables which will be changed per-instance. For example, the Monster entity may have XP and Gold variables.
To create entity instances on an object layer:
Add an Object Layer to your tilemap
Paint a new tile onto your map
Give the newly-created object a Type of Monster (or whatever entity type you want). Notice that doing so will automatically display the variables added in the FRB editor under the Custom Properties section. Notice that X, Y, and Z variables do not appear in the Custom Properties section - X and Y are already part of the regular properties of an object. The Z value is set according to the object's layer.
These values can be left to their default or modified
Also, note that if a tile is already given a type, then painting that tile on an object layer will automatically result in the painted tile using the same type. This can speed up placing similar objects.
If your entities are not showing up in game or in Tiled, the following steps may help you identify the problem.
The type definition file loaded in Tiled applies app-wide, as opposed to per map or per tileset. This means that if you are using Tiled for multiple projects you will need to remember to swap .xml files when switching between the two projects.
Only entities with their CreatedByOtherEntities property set to true will appear in the TiledObjects.Generated.xml file.
Any screen where you are creating entities from a .tmx file must have a a list for each entity type.
FlatRedBall supports the creation of Entity instances by adding either tiles or objects in a Tiled Map (.tmx). This document shows how to do so.
Before adding an entity to your screen, you must first define an entity. Once an entity is defined, it can be created through Tiled. Any entity can be instantiated in a Tiled map - even entities which are larger than the size of the tiles in your game (usually 16x16). By default FlatRedBall sets the options necessary to instantiate entities through a Tiled Map in the new entity dialog as shown in the following image:
If these options have not been set and you already have an entity created, you can adjust the values manually. To create a factory, set the CreatedByOtherEntities to True.
Also, your entity type should have a corresponding list, typically in GameScreen. If your entity inherits from another entity, then a list of the base type in the GameScreen is adequate.
The easiest way to add an instance of an entity to a game is by dropping a Tile into your level map. First, we will mark which tile to use for the entity type.
Open your map in Tiled
Select the Tileset which has your enemy. Keep in mind that each layer in Tiled can only use one tileset.
Click the wrench icon to edit the tileset
Select which tile you would like to use for your entity type
Enter the name of your entity as the Type. Capitalization matters, so be sure to match the name as it is written in the FlatRedBall Editor
Save your TileSet
Now you can paint the tiles onto your map and they will automatically be converted into entities when you run your game.
By default maps create entities without any manual code. This setting is controlled by the Create Entities From Tiles variable, which is checked by default.
This setting produces the following code:
Note that this setting is only applied in the base GameScreen, so to turn it off it must be turned off on the Map object in GameScreen (or the base Screen). If it is turned off, you can manually add the code to create entities in your CustomInitialize as shown in the following snippet.
Using either approach will result in the same thing - entities being created from tiles.
Entities which implement the ICollidable interface can also be instantiated through Tiled. Any ICollidable entity can be used, but usually entities which will have their collision set by Tiled should not have any collision objects in Glue. To create an empty ICollidable entity:
Right-click on the Entites folder in Glue
Select Add Entity
Make sure no shapes are checked in the add window
Check the ICollidable checkbox
Leave the defaults for Tiled instantiation
Enter a name
Click OK
To create an instance of this shape in Tiled:
Open a TMX file in Tiled
Create or select an Object Layer
Select to insert a rectangle
Add a rectangle to your level
Set the type of the rectangle to CollidableEntity (or the name of whatever entity you wish to instantiate)
Save the map
CreateEntitiesFrom will now automatically create an instance of the CollidableEntity, and it will use a rectangle as its collision matching the size defined in Tiled.
As shown in the , it is possible to create collidable entities using Tiled. These collidable entities ultimately hold references to shapes which can be accessed in code. Some situations (such as triggers in a level) will be easier to create with "raw shapes" rather than entities. These free floating shapes can be of any shape or size, and creating them in Tiled lets us visualize the shapes in context of the entire level.
Each object layer with one or more shape is loaded as a separate ShapeCollection at runtime. This tutorial covers the basics of working with a ShapeCollection, but more information can be found on the . All ShapeCollections are invisible by default, but can be made visible. Add the following method to GameScreen :
The entity will now display the contents of the .tmx file when included in a screen.
CircleInstance is centered on the entity, so we can see that the tiled object's top-left corner aligns with the center of the entity. We can further observe the impact of the origin by rotating the entity. We'll do this by adding the following code to the entity's CustomActivity method:
The LayeredTileMap object is the runtime type for the TMX file format (the native file format for Tiled). Whenever a TMX file is added to FlatRedBall, it will (by default) be loaded into a LayeredTileMap at runtime. The LayeredTileMap represents a collection of . It contains one per layer in the source TMX file. The LayeredTileMap class inherits from so it can be moved and attached to other . Each MapDrawableBatch is attached to its parent LayeredTileMap, and can be moved independently by changing its .
Existing (empty) projects can also run the wizard through the Quick Actions tab.
Create a GameScreen and Level screens and check the options for creating TMX files.
[subpages depth="1"]
The Tiled plugin automatically creates and maintains a file called TiledObjects.Generated.xml whenever an entity is created or modified. It can be used in Tiled to simplify object creation. For a more detailed discussion of using a custom XML file for tiled objects, see the Tiled manual: This file contains a list of all entities which have their Created by Other Entities marked as true. It is formatted such at it can be used in Tiled to create new entity instances. This file is located in the content folder of your main project. For XNA projects, this is located in: <solution location>/<project name>/<project name>Content/TiledObjects.Generated.xml
If we select the Monster type in Tiled we will see the XP and Gold variables as well. Default values from FRB editor will even be carried over to Tiled.
Once tiles have been given a type, these can be converted to entities using the TileEntityInstantiator . For a full tutorial on using the TileEntityInstantiator, see this link: To instantiate all entities, add the following code to your screen's CustomInitialize:
As of Tiled 1.0.3, the referenced Object Types file does not automatically get reloaded when it changes on disk. This means that if you add an entity, remove an entity, or add a new property to an entity, you may need to restart Tiled for the changes to apply. This bug is logged and can be tracked here: Furthermore, there is sometimes an issue with your properties/variables not being loaded to your Tiled type even when the variables show up in the .xml file and after you have refreshed Tiled. If you encounter this, you may need to re-import the .xml file in the object/custom types editor again, and it should show up after doing so.
For more information on how to create lists, see the .
The Collisions object is a List<TileShapeCollection>. When a LayeredTileMap is created (usually from TMX), each tile layer is checked for tiles with shapes. If any tiles on a layer contain shapes (defined in the Tileset), then a TileShapeCollection will be created for that layer. If tiles have shapes defined, but do not have a Type defined, then the name of the TileShapeCollection matches the name of the layer. If a tile defines a type, then the TileShapeCollection will be named after the Type. Note that this is populated from the shapes added to tiles in the tileset, as opposed to the ShapeCollections object which is populated based on shapes added to object layers.
Destroy method fully removes the LayeredTileMap from the engine. Specifically this method performs the following:
Removes the LayeredTileMap from the engine's DrawableBatch list (removes it from being rendered)
Removes all TileShapeCollections that have been created when the LayeredTileMap was loaded
Removes any ShapeCollections created by shapes included in the LayeredTileMap
Removes this object from being managed by the engine (if the map uses velocity, acceleration, or other every-frame variables)
This method is automatically called if the LayeredTileMap is loaded from a TMX in generated code, but must be called manually if the map is created manually in custom code.
The following code destroys the calling LayeredTileMap:
The Z value of a LayeredTileMap controls the order that it is drawn relative to other objects such as FlatRedBall Entities. Each layer (MapDrawableBatch) on the LayeredTileMap is drawn at one Z value greater than the layer under. For example, consider a map with layers shown in the following image:
Assuming the map's Z value is set to 0, then the layers will have the following Z values:
GameplayLayer Z = 0
AboveLayer1 Z = 1
AboveLayer2 Z = 2
The Map object (the default LayeredTileMap when using a wizard setup) provides the option to shift the map's Z value so the GameplayLayer's Z is at 0. If this option is checked, then any layer above GameplayLayer has a positive Z value and draws on top of entities at Z = 0. Similarly, if this option is checked then any layer below GameplayLayer has a negative Z value and draws under entities at Z = 0.
The NameTileOrderedIndexes property can be used to find tiles by a given name. It is a Dictionary<string, List<int>> , where the key is a name, and the value is the index of tiles which have the given name.
The MapDrawableBatch object stores a list of vertices (points) which are used to define the coordinates for each tile. These points are used by the rendering code in the MapDrawableBatch class to perform efficient rendering. Each tile is composed of a list of vertices, as opposed to a Sprite (as might be the case if the MapDrawableBatch were a FlatRedBall-drawn object). Therefore, to access and modify properties on a tile, its index must be known. The following image shows the indexes of a simple tile map:
The following code example shows how to create an Entity for every tile with the name "CreateEntity".
Tiles will only have properties at runtime if it uses a tile in a tileset with a Name property.
The CoordinateAdjustment variable is used to adjust the texture coordinate of tiles inward to prevent adjacent pixels from bleeding in to tiles. This value needs to be balanced between being too small (resulting in values bleeding in to tiles) and too large (resulting in pixels being excluded from tiles). This value is in texture coordinates as opposed to pixels, so ideally it should be adjusted according to the size texture size used on the tile map.
If CoordinateAdjustment is set to 0, then the texture coordinates are assigned according to the edges of the tiles. For example, a texture coordinate of 0 would use the area represented by the yellow are in the image below:
Increasing the CoordinateAdjustment value results in the yellow area shrinking.
CoordinateAdjustment is a static property no the MapDrawableBatch so it can be assigned prior to loading a TMX. Glue projects typically load TMX files when a Screen is first created, so the CoordinateAdjustment value must be assigned prior to loading the screen to take effect.
The MapDrawableBatch class is the heart of the Tile Graphics Plugin. It is ultimately the class responsible for rendering the tile map graphics when your game runs. Although the Tile Graphics Plugin provides ways to construct MapDrawableBatches from .scnx files, the MapDrawableBatch can also be constructed purely in code. While this does require some code, working with the MapDrawableBatch class is actually very easy.
The name MapDrawableBatch comes from the fact that it's usually used for tile maps, and it implements the FlatRedBall IDrawableBatch interface. The IDrawableBatch interface allows classes to implement completely custom rendering code using XNA, yet the result of the rendering will still be properly sorted with other FRB objects. The result is that the rendering code appears to be fully integrated into FRB despite being completely custom. If you are interested in more info on IDrawableBatch, see the IDrawableBatch page.
The MapDrawableBatch class works very well in Screens, but it can also be used in a non-Glue project. If you are not using Glue, make sure to follow the proper initialize/activity/destroy pattern explained here. For simplicity the rest of this article will be written assuming you are using Glue Screens. First you will need to download and install the Tile Graphics Plugin from GlueVault which can be found here. If you are not using Glue, but instead doing everything with pure code, you can download all of the .cs files from here: http://www.flatredball.com/FlatRedBallAddOns/Trunk/FlatRedBall.TileGraphics/FlatRedBall.TileGraphics/. Next you will need to create or open a Glue project. Doing so after the the Tile Graphics Plugin has been installed will automatically add the appropriate classes to your code. Once you have a project created, you can verify the Tile graphics Plugin is installed and that it has properly modified your project by checking the project in Visual Studio. You should have a TileGraphics folder in your project.
The next step is to add a Screen to your Glue project. This Screen will also need to contain a .png (any will do). We will be using this .png file in code. For more information on how to add files to your Screen, and how to access files in code, see this page.
Now that we have a project set up and we have a file that is available to be used, we can create our map. The first step is to create an instance in our GameScreen:
Open your project in Visual Studio
Navigate to your Screen class's .cs file (the custom code file)
Add the following code inside your GameScreen class but outside of any function:
Next we'll initialize our class. First I'll present the code, then break apart what each piece means. The full code is:
Let's look at each section and see what it means:
The UsePixelCoordinates code is responsible for putting our Camera in "2D mode". For more information, see this page.
This code creates an instance of the MapDrawableBatch. Here we specify the number of tiles we want in our map. We are specifying it as 32 x 32. Keep in mind that increasing the dimensions will increase the number of tiles much faster. For example if your map is 32 tall and 32 wide, then it will include 32x32 = 1024. However, increasing to 64x64 results in 4096 tiles. While a 4096 map will usually render without any performance slowdown, it is possible to get to very large numbers very quickly, so you will want to run performance tests on your target platforms for the size of map you are interested in creating. Next we specify the size in pixels of how big our cells on our sprite sheet (the texture used by our tile map) will be. For example, consider the following image to show how big the cells are in a sprite sheet:
In this example the size of the sprite sheet cell is 16 by 16 pixels. My image happens to be 16 by 16 pixels so there is only one cell in the sprite sheet.
This line of code creates each cell. Each cell needs to know 3 pieces of information:
The bottom-left corner of the tile in world coordinates.
The width and height of the tile. This will usually match the size of the cells.
The top, bottom, left, and right pixels of the cell to use. In this case we are rendering the entire sprite sheet, so we use 0 - 16.
The AddToManagers call adds the MapDrawableBatch to the engine. In other words, once this call is made the MapDrawableBatch will be rendered to the screen when your game runs:
The MapDrawableBatch class represents a single layer in a .tmx file. It implements the IDrawableBatch class to perform custom rendering. It internally creates a single vertex buffer which is drawn all at once with no render state changes for maximum performance. Usually .tmx files are loaded into a LayeredTileMap, which contains one or more MapDrawableBatch instances.
When the MapDrawableBatch is created it will only create vertices for tiles which exist. Therefore tiles which are not painted or which have been erased in Tiled will not create vertices.
MapDrawableBatch supports a Modulate color operation through its Red, Green, and Blue values. By default these values are all set to 1.0f, but they can be modified at runtime to tint or darken the map.
MapDrawableBatch instances are typically created by adding a TMX file to your project. By default FlatRedBall top down and platformer projects contain TMX files for each level. MapDrawableBatch instances can also be created in code. The following code shows how to create a new MapDrawableBatch which is filled with a pattern from a texture called FRBeefcakeSpritesheet The following code assumes that an existing Map exists (although this is not necessary), that the code has access to a Texture called FRBeefcakeSpritesheet, and that this code exists in the CustomInitialize of a Screen such as Level1.
The code above includes some subtle considerations:
The CustomLayer MapDrawableBatch uses X axis sorting. Therefore, all tiles must be added in order of X, largest to small. Breaking this order will result in incorrect rendering and other unpredictable behavior.
The entire tile set is filled. This enables painting later without having to add tiles. If tiles are added on paint, this can make sorting far more difficult.
MergeOntoThis can be used to merge tiles from one or more source layers into a destination layer. Merging can be used for a number of reasons:
To simplify management of layers
To improve performance
This example uses a tmx file which includes a layer named Layer2 which contains ice blocks.
The other tiles (the red number 1 and the orange brick surrounding blocks) are part of the GameplayLayer - the standard layout for Level1 if using the wizard. The following code shows how to merge the layers:
The code above includes diagnostic variables to count quads and layers. These values can help verify that the layers have been merged at runtime as shown in the following screenshot:
Even though layer2 has been destroyed, the ice blocks still draw as shown in the following screenshot:
Note that LayeredTileMaps partition their tiles based on the X or Y axis, so merging is not simply an addition of quads at the end of the layer. Rather, merging inserts the quads to preserve the axis sorting so that efficient partitioning during drawing can be performed.
The PaintTile can be used to change the texture coordinate on an existing tile in the MapDrawableBatch according to its index. This method can be used if your game requires dynamically the graphics of a tile after it is created (either from a .TMX file or manually).
PaintTile has the following overrides:
PaintTile takes the orderedTileIndex and the texture ID.
The orderedTileIndex value is the index of the tile on the tilemap. Usually, an index of 0 is the top-left tile on the map. The subsequent tiles are ordered counting left-to-right if the map is taller than it is wide. The following image shows example orderedTileIndex values for a map which is ordered left-to-right.
If your map is wider than it is tall, then the ordering is performed top-to-bottom rather than left-to-right. The following image shows example orderedTileIndex values for a map which is ordered top-to-bottom.
The newTileId is the index of the texture of the tileset. This index uses a similar indexing pattern but it always begins at the top-left with a value of 0 and is ordered left-to-right. The following image shows example newTileId values in a tileset.
This example assumes the following:
You have a LayeredTileMap in your game called Map
You have a Layer added to the LayeredTileMap called LayerForPainting. This could be created through code, but the easiest way to do this is to add this layer in Tiled. For information on how to create a layer through code, see the MapDrawableBatch page.
This layer references a tileset that you intend to paint with. This can be done by painting tiles on the layer in Tiled which will result in the layer being associated with the tileset containing the painted tiles
The layer is already filled with tiles. This enables the painting to adjust texture coordinates without adding new tiles.
In this example, this map is the modified Level1Map.tmx which is created automatically in a platformer game. To paint on this tile, add the following code:
FlatRedBall does not support multiple tilesets per layer (MapDrawableBatch). In other words, each MapDrawableBatch can only paint tiles using its current layer. Therefore, the value of 0 (the top-left most tile in the tileset) depends on the layer's current TileSet. Games which require multiple tilesets should create multiple layers.
MapDrawableBatches (map layers) support parallax by assigning the values in Tiled or in code. By default parallax has a value of 1, which means that the object will show no parallax. A value between 0 and 1 results in the layer behaving as if it is in the distance (not scrolling as quickly when the camera moves). A value greater than 1 results in the layer behaving as if it is in the foreground (scrolling more quickly when the camera moves).
To set parallax:
Open an existing map
Select a layer
Change its Parallax Factor property to the desired value
Tiled provides a preview of the parallax if you scroll the main view
Once the file is saved, the parallax will automatically be applied at runtime in the game.
PaintTileTextureCoordinates can be used to change the texture coordinates on a tile by its ordered index. This method can specify all four coordiantes (left, top, right, bottom) or just the top and left. If only the top and left are specified, the bottom and right are automatically determined based on the tileset's tile dimensions.
Note that this requires the ordered tile index. This sample assumes that tiles have been added manually, and then painted later.
This article shows how to use the MapDrawableBatch to render a large number of Sprites very efficiently. The MapDrawableBatch is less flexible than using individual Sprites; however, in exchange for giving up that flexibility the MapDrawableBatch can be extremely efficient. In fact regardless of optimizations the FlatRedBall Engine will likely never be able to render a large number of Sprites faster than MapDrawableBatch because of the flexibility it supports. Keep in mind that the MapDrawlableBatch is used for Sprites which do not move. Once they have been pasted, they will be there until MapDrawableBatch is either made invisible or removed completely from the engine. This makes the MapDrawableBatch ideal for tile maps and static environments; although it could be used for other static objects such as backgrounds and static UI/HUD components.
Internally MapDrawableBatches do not store references to Sprites. Instead they store a list of vertices which are used for rendering, much like model objects when dealing with 3D rendering. The Paste method will create a new set of vertices to match the argument Sprite; however, the Sprite itself is not held by the MapDrawableBatch. This means that the same Sprite can be used over and over to reduce allocation during the creation of a MapDrawableBatch.
The following code shows how to create a 4096 (that's 64x64) MapDrawableBatch using the Paste method. Despite the large number of Sprites, the MapDrawableBatch will render efficiently - even on mobile platforms such as the Windows Phone 7.
You will need to add the following using statement for MapDrawableBatch to be resolved:
The Paste method adds vertices to the MapDrawableBatch class. The Sprite which is passed in the map method is *not* stored by the MapDrawableBatch. This means a few things:
Changes to the Sprite after paste will not be reflected in the map. This means that if you move the Sprite around, it will not change on the map. The map is static.
Since the Sprite reference is not used internally in the MapDrawableBatch, the same Sprite can be used over and over. This reduces the amount of allocation needed when creating a MapDrawableBatch.
RemoveQuads can be used to remove quads from the MapDrawableBatch by index. This method is useful in situations where you want to remove tiles from the MapDrawableBatch at runtime, such as when creating Entities from the contents of a tile map.
The following shows how to remove the first three tiles from the MapDrawableBatch:
For more information on LayeredTileMap, see the LayeredTileMap page.
Often the internal quad ordering is unknown. Therefore, the MapDrawableBatch class provides a GetQuadIndex method to convert world X and Y to an index. If no tile is located at the index, a value of null is returned. The following code could be used to remove quads when the user clicks a mouse:
SortAxis controls how the MapDrawableBatch performs culling. This value controls how culling is performed when the MapDrawableBatch is drawn. If SortAxis is set to SortAxis.X, then the map will cull tiles from the left and right of the camera visible bounds. Otherwise, if SortAxis is set to Y, then the map will cull tiles from above and below the camera visible bounds. This value is automatically set when the map is created according to whether the map is wider (SortAxis.X) or taller (SortAxis.Y). Setting SortAxis to SortAxis.None results in the map not being culled at all when rendered.
RenderingScale can be used to draw a MapDrawableBatch at a larger size. By default this value is set to 1 which means the MapDrawableBatch draws at its original size. Note that increasing the RenderingScale is not recommended for "zooming" the game in or out - it's best to use the FlatRedBall Camera. Increasing the RenderingScale can be used to make layers in-game appear larger or smaller.
The following code finds a layer called CloudLayer and increases the RenderingScale gradually as the user holds either the up arrow or down arrow on the keyboard.
The AddCollisionFrom method can be used to add AxisAlignedRectangle instances to the TileShapeCollection from a tile map (MapDrawableBatch).
AddCollisionFrom provides lots of flexibility for adding collision. The simplest form is to add collision from a tile by the tile name. The following code adds collision for all tiles named "CollisionTile":
Using names is simple, but can also be restrictive. For example, we can check a tile to see if any of its properties are named "IsSpikes":
Note that if adding collision based on tile property names alone (not the value), see the AddCollisionFromTilesWithProperty method: http://flatredball.com/documentation/tools/tiled-plugin/glue-gluevault-component-pages-tile-graphics-plugin-tileshapecollection/addcollisionfromtileswithproperty/
AddCollisionAtWorld creates attempts to create a new rectangle at the location specified. If the TileShapeCollection already has an AxisAlignedRectangle at the argument location, then it will not create another. If there is no rectangle at the argument location, then a new one will be created. Newly-created rectangles will automatically be sized and positioned according to the rectangle size and seed of the TileShapeCollection.
AddCollisionAtWorld adds a collision rectangle at the argument X and Y values. Rather than using the exact X and Y values, the rectangle will be placed at the center of the tile, extending to the edges using the TileShapeCollection.GridSize value. For example, consider a TileShapeCollection with a GridSize of 16. Calling the AddCollisionAtWorld method with any value between 0 and 16 will result in a rectangle being placed at (8,8). Furthermore, calling AddCollisionAtWorld inserts a rectangle in the proper index to keep the shape collection ordered along its SortAxis . Therefore, AddCollisionAtWorld can be called in any order and all rectangles will still be sorted and collision methods will use partitioning.
The following code shows how to create AxisAlignedRectangles with the cursor. The following code assumes that SolidCollision is a valid TileShapeCollection and that it is visible.
AddCollisionFromTilesWithProperty adds rectangles to the calling TileShapeCollection for all tiles which have the argument custom property. This is the most common way to create collisions from a TMX file in code.
Additional Information For more control over which tiles create collisions (for example checking a property and its value), see the AddCollisionFrom method: http://flatredball.com/documentation/tools/tiled-plugin/glue-gluevault-component-pages-tile-graphics-plugin-tileshapecollection/addcollisionfrom/
AddMergedCollisionFromLayer adds rectangles to the calling TileShapeCollection for all layers in the argument layer which have properties matching the predicate. Rather than creating individual rectangles for each tile, the created rectangles will be merged - all adjacent rectangles in either a row or column will be combined into one to reduce memory consumption and to speed up collision calls. AddMergedCollisionFromLayer is similar to AddMergedCollisionFromTilesWithProperty, but it provides more control over how collisions are created. Note that AddMergedCollisionFromTilesWithProperty is simpler and may provide enough flexibility for many games.
The following shows how to add collisions for any tile which has a property IsSpike with a value of true.
Note that in this case the Name is the name of the property and the Value is the value of the property. The code above could be modified to check any property or desired value.
AddMergedCollisionFromTilesWithProperty adds rectangles to the calling TileShapeCollection for all tiles in the first argument (LayeredTileMap). Rather than creating individual rectangles for each tile, the rectangles will be merged - all adjacent rectangles in either a row or column will be combined into one to reduce memory consumption and to speed up collision calls. Merging will happen either along rows or columns depending on the SortAxis property.
The following code creates adds collision to a LayeredTileMap called SolidCollision from a LayeredTileMap called Level1 . It adds collision for all tiles with the property HasCollision .
Merging will work even for more complex maps, such as maps with gaps and concave areas, as shown in the following image:
As mentioned above, merging will be performed according to the SortAxis property. By default the SortAxis value is set to X, so collision will be merged along columns, so that the rectangles can be sorted along the X axis.
If we change the SortAxis to Y prior to adding collision, then merging will happen along rows.
In general the SortAxis should be X if the map is wider than it is tall, and it should be Y if the map is taller than it is wide. Adjusting the SortAxis according to the map's width or height will allow collision partitioning to operate efficiently.
Consider the following image (from Tiled). In this map all painted tiles have the HasCollision property, so all tiles will create collision. At runtime this will produce the following collision if not using merged collision (if calling AddCollisionFromTilesWithProperty ) : If we change the call to use AddMergedCollisionFromTilesWithProperty then the number of rectangles is significantly reduced, as shown in the following image:
TileShapeCollection is a class created specifically for tile based collision. Its features include:
Very fast collision - it has partitioning built-in.
Eliminates snagging - Internally the TileShapeCollection modifies contained AxisAlignedRectangles' RepositionDirections to eliminate snagging.
Full support in the FlatRedBall Editor for initial definition and collision relationships.
Simplified syntax - Adding collisions to TileShapeCollection is very easy to do in code, whether doing so manually in code or from a loaded TMX file.
If you have created your project using the FlatRedBall Editor Wizard (either platformer or top-down), then your game already has TileShapeCollections. For example, the GameScreen should have a SolidCollision TileShapeCollection.
To add a TileShapeCollection:
Expand your GameScreen or Screen which should contain the TileShapeCollection. Typically collision is added to GameScreen.
Right-click on Objects and select Add Object
Verify FlatRedBall or Custom Type is selected
Select the TileShapeCollection option
Click OK
Now that you have created a TileShapeCollection, you can fill it using a variety of methods as shown before.
The most common usage of TileShapeCollections is to add collision from a particular tile Type. Usually this is done through a Map object in the GameScreen. If your project has been set up using the wizard, then you should have a Map object in GameScreen. If so, you can:
Select the TileShapeCollection that you would like to fill from the map
Check the TileShapeCollection properties
Select the From Type option
Use the dropdown to select the type. These types will match the types defined in your map's Tileset (tsx) file
When creating a game, you may want to add some placeholder collisions to test your logic and collision relationships. To create placeholder collisions:
Select your TileShapeCollection in Glue
Click the TileShapeCollection Properties
Select the Fill Completely option
Set the Tiles Wide and Tiles High to define the size of collision block you want
Click the Variables tab
Check the Visible checkbox
Now the TileShapeCollection will appear in your game and can be used for testing.
Open Tiled
Click the wrench icon to edit the tileset
Select one (or more) tiles which should have collision
Add a Custom Property called SolidCollision. The type of the variable doesn't matter.
Save your tileset (tsx)
Place some tiles in your map
Save your TMX
Now in Glue we can associate the SolidCollision with the TileShapeCollection:
Select the TileShapeCollection in your GameScreen
Click the TileShapeCollection Properties tab
Select the From Property option
Use the dropdown to select your TMX file
Enter the property SolidCollision
Now if you run your game you will see collision wherever you placed your tiles.
Collision can be added to a TileShapeCollection from a loaded TMX file (which loads into a LayeredTileMap). The following code shows how to add collision from all tiles with the custom property HasCollision.
The following example shows how to create an AxisAlignedRectangle that moves around with the keyboard and collides against a TileShapeCollection. This project assumes a Glue project with:
A Screen called GameScreen
An AxisAlignedRectangle object named Rectangle in GameScreen
To add the TileShapeCollection:
Open the project in Visual Studio
Open GameScreen.cs
Add the following using statement:
Add the following at class scope:
Add the following to CustomInitialize:
To add movement and collision to your rectangle, add the following code to CustomActivity:
Finally you'll need to remove the TileShapeCollection. To do this, add the following to CustomDestroy:
By default each rectangle in a TileShapeCollection occupies the entire tile (16x16). Custom shapes can be defined in Tiled to create rectangles which occupy less than the entire tile, or even polygons for sloped collision. Partial tile collisions are defined in the TSX file, typically in the StandardTileset.tsx. To add collision on tiles:
Open the TSX file in Tiled
Select the tile which should have partial collision
Select View -> View and Toolbars -> Tile Collision Editor
Draw a rectangle or polygon on the tile
Set the type on the tile which has the collision. Note that the same type can be given to multiple tiles. Be sure to select the tile and not the shape. You may need to deselect and re-select the tile to force its properties to display rather than the newly-drawn polygon.
Repeat this process for any other tile which should have custom shapes.
Once you have added shapes to all of the tiles, and once you have set the types on the tiles, save the TSX file.
Paint the tiles in their desired locations. Note that tile collision can be previewed in Tiled by selecting the View -> Show Tile Collision Shapes option
Save the Tiled (TMX) file.
To use these shapes:
Select an existing TileShapeCollection or create a new TileShapeCollection. Typically this TileShapeCollection would be in the GameScreen.
Select the TileShapeCollection Properties tab
Select the From TMX Collision (use tileset shapes) option
Set Source TMX File/Object to Map
The TileShapeCollection will now include custom shapes as defined in Tiled.
PlatformerCharacterBase and TileShapeCollection - discusses how to use the PlatfromerCharacterBase with TileShapeCollection.
Testing your collision using Fill or Border Outline is a handy way to make sure your game is working as you expect it, but eventually you will want to have collision defined in a map. For this tutorial we'll work with a simple game with a single TMX file already added to the GameScreen which also contains a TileShapeCollection. First we'll specify which tiles should have collision:
AdjustRepositionDirectionsOnAddAndRemove determines whether a TileShapeCollection adjusts the RepositionDirections property on contained AxisAlignedRectangles when a new rectangle is added. This value defaults to true, and in most cases it should be left unchanged. For more information on the RepositionDirections, including how it pertains to TileShapeCollections, see the AxisAlignedRectangle.RepositionDirections page.
By default, TileShapeCollections adjust the contained rectangle RepositionDirections to prevent snagging. For example, the following image shows how RepositionDirections are adjusted to prevent snagging on a flat surface.
The image above displays the RepositionDirections of four rectangles, all of which belong to the same TileShapeCollection. However, consider a situation where two TileShapeCollections are needed. For example, a game may have two TileShapeCollections:
SolidCollision (white, regular ground collision)
IceCollision (blue, slippery collision)
In this case, each TileShapeCollection would adjust the RepositionDirections of each of its contained rectangles, but areas where the TileShapeCollections touch would not be properly handled, as shown in the following image.
In this case if a player were to walk across the transition between SolidCollision and IceCollision, the player's may snag on the seam (horizontal velocity may stop). The RepositionDirections for the rectangles in the middle of the strip should consider adjacent rectangles in different TileShapeCollections, rather than only rectangles in their own TileShapeCollection. To solve this problem, we can use another TileShapeCollection which contains all rectangles from both the SolidCollision and IceCollision. Keep in mind, a rectangle can exist as multiple TileShapeCollections, so we can take advantage of this to properly adjust RepositionDirections. Once we solve this problem (as shown below), the center rectangles where the two TileShapeCollections meet will no longer have inward reposition directions.
For this example, consider two TileShapeCollections defined in a GameScreen in Glue: SolidCollision and IceCollision.
We can uncheck the Adjust Reposition Directions On Add And Remove option in the Variables tab for both TileShapeCollections.
Next we can create a combined TileShapeCollection in Glue.
We'll mark this new TileShapeCollection as Empty so that we can fill it in code.
Finally, we can insert the TileShapeCollections which we'd like to adjust the RepositionDirections of, in context of each other, in code. To do this, we can modify the CustomInitialize of our GameScreen:
It's important to note that the purpose of inserting the collisions into CombinedTileShapeCollection is to adjust the RepositionDirections of each of the contained rectangles. Each individual TileShapeCollection (SolidCollision and IceCollision in this case) are still fully-functional TileShapeCollections, and CollisionRelationships can still be created between entities and these TileShapeCollections.
The CollideAgainstClosest method can be used to perform collision between a Line and a TileShapeCollection. The method returns whether a collision has occurred. Also, it marks the closest collision point. Line vs TileShapeCollection closest collision can be used for a variety of gameplay purposes such as:
Laser vs. level
Grappling hook vs. level
Fast-traveling bullet vs level
Other types of shapes usually are checked over the course of multiple frames as a collidable object moves, and these shapes have a fixed size. However, lines can be of infinite size, and often times are checked just once, such as when a bullet is fired.
The following code can be added to a GameScreen to draw a line from the camera's position to the cursor's position. CollideAgainstClosest is used to find the last collision point which is used to draw a circle. This code assumes that your screen (such as GameScreen or Level1) contains a TileShapeCollection named SolidCollision.
The CollideAgainst function returns a bool value indicating whether the calling TileShapeCollection collides with the argument. CollideAgainst can be used to test collisions against:
ICollidable (usually Glue entities)
AxisAlignedRectangle
Circle
Line
Polygon
Note that in most cases CollideAgainst does not need to be called because collision relationships can be created between TileShapeCollections and Glue ICollidable entities.
The following code shows how to test if an entity is colliding with a TileShapeCollection whenever the space bar is pressed. The code assumes that the entity implements ICollidable.
RemoveFromManagers removes all contained tiles from any managers and other PositionedObjectLists that hold the tiles. Specifically calling RemoveFromManagers will:
Remove all shapes from the ShapeManager for every-frame management
Remove all shapes from the ShapeManager for rendering
Clear the TileShapeCollection
Remove shapes in the TileShapeCollection from any other PositionedObjectList containing these shapes, including parent/child relationships
The following code will remove the calling TileShapeCollection from all managers and will clear it
GetRectangleAtPosition returns the AxisAlignedRectangle instance at the argument position. This method checks if the position is inside the bounds of the rectangle, so an exact position is not needed. This method also takes advantage of the axis-based partitioning in the TileShapeCollection so this method does not need to check every rectangle. In other words, this method is very fast, even for TileShapeCollections with a lot of rectangles.
The following code can be used to obtain a rectangle at the Cursor's position:
The LastCollisionAxisAlignedRectangles property stores a list of AxisAlignedRectangles which collided with the last object to perform collision against a TileShapeCollection. This can change multiple times per frame since multiple objects may collide with a TileShapeCollection. Therefore, this property should be used immediately after a collision occurs. Typically this is accessed in a CollisionRelationship event. This list may contain multiple rectangles if the last collision check resulted in multiple rectangles overlapping.
For this example, consider a platformer entity which is performing solid collision. We can print information about the collision to the screen in an event for the collision relationship, as shown in the following code:
InsertCollidables allows the adding of a list of ICollidable rectangles to a ShapeCollection. This is usually done for collidables which align with a grid and which are used for solid or platformer collision.
Often when creating solid collisions, a game uses the TileShapeCollection type. However, at times each collision rectangle should be an entity. This is necessary if the collision has additional behavior beyond collision. For example blocks may play animations, may trigger game actions (such as unlocking a door), or may HP and break (such as when being shot). In situations like these, each block should be an entity to keep track of its state and to provide additional functionality through custom code. TileShapeCollections automatically adjust their contained rectangle RepositionDirections, but collidable lists do not have this functionality built-in. Prior to adjusting reposition directions, a row of blocks may have the following RepositionDirections:
The purple reposition directions are considered undesirable because they can cause snagging. After fixing this problem using InsertCollidables, the RepositionDirections will only point outward, allowing other entities to collide without snagging.
This example uses a collidable entity named Block which has a list called BlockList in GameScreen.
We will use an empty TileShapeCollection to fix the RepositionDirections:
In code, call InsertCollidables on the CombinedTileShapeCollection to add the BlockList
Now all blocks in the BlockList will have their RepositionDirections adjusted for every Block that is already created when the method is called.
Add a new TileShapeCollection to the GameScreen called CombinedTileShapeCollection. The name CombinedTileShapeCollection is a recommended name for TileShapeCollections used specifically for fixing RepositionDirections.
Leave the newly-created TileShapeCollection as empty.
The Rectangles property provides access to the list of AxisAlignedRectangles stored in a TileShapeCollection. This list will be ordered based on the TileShapeCollection's SortAxis property.
The following code shows how to loop through all rectangles in a TileShapeCollection and perform custom logic:
RemoveSurroundedCollision removes all rectangles which are surrounded by other collisions on all four sides. Calling this method removes the "inside" of solid collision areas, resulting in only the outline tiles being preserved.
This method can be used to reduce the number of collision objects to improve runtime performance and reduce memory usage. This method should only be used when the collision is solid because solid collisions only need their outline to function properly. However, non-solid collision (such as a collision area representing water that the user can swim through) should not use this method. RemoveSurroundedCollision can provide performance improvements similar to merged collisions (such as AddMergedCollisionFromTilesWithProperty ), but this method does not introduce snagging so it is suitable to be used in platformers.
The following code shows how to remove all surrounding collisions using the RemoveSurroundedCollision method.
Note that this method can be called after multiple AddCollision methods.