Skip to content

Grid & tile help

Matt Filer edited this page Nov 14, 2020 · 1 revision

Levels are created upon a grid system which is loaded from disk. The grid is of fixed size, and represented in editor by a checkerboard sprite. You can click on this grid to see tile X,Y locations in the Unity editor, as well as extra debug information such as pathability and prop coverage.

While the grid is not a singleton, it can be accessed from anywhere using the level manager. As the grid is loaded from disk, the system is asynchronous: be aware of this when writing scripts that query it. You can subscribe to the LevelManager.Instance.LevelLoadCompleted delegate, which will allow you to execute code after the level has loaded into the grid.

Getting grid dimensions

The grid dimensions are hard-set in the editor and are currently not intended to be changed. While not intended to be changed, this is possible - however doing so will block you from loading any previously created levels that don't match the new size. You can query LevelManager.Instance.Grid.GridTileDims to get a Vector2 containing the grid's X & Y tile counts, which should be used instead of assuming the current values will stick through production.

Accessing tiles in the grid

The grid is a 2D set of tiles. Each tile contains its own metadata, as well as objects within it. To access a tile, you can query LevelManager.Instance.Grid.AllTiles - this returns a List of all tile objects. Additional functionality is provided by the grid, which may be helpful for finding tiles at a given location, or neighbouring other tiles.

Tiles overview

A tile within the grid exists whether it is a part of the map or not - this is an important point to remember! If a tile is "unoccupied", the tile is simply a void space which has not been used in the map design. If a tile is "occupied", it will contain a reference to the occupying object, which is the map tile itself (containing the sprite and tile type information). Think of it this way: the grid could be 30x30, but the actual map may only use 10x10 - those 10x10 tiles are considered "occupied", while the rest are "unoccupied".

As well as the notion of a tile being occupied, tiles can also have props. Props are separate entities that render above the occupier, and are intended to be used for additive details to a tile (E.G. a vending machine, or a puddle). Props allow for extra functionality to standard tiles such as events, waypoints, and more.

Tile metadata

Tiles contain a series of information that is useful for monitoring gameplay. This includes:

  • Dimensions - a Vector2 object of the tile's X&Y dimensions.
  • Position - a Vector2 object of the tile's X&Y position in 2D world space.
  • IsOccupied - a bool which is true if the tile is occupied by a tile object (E.G. a wall, the floor, etc).
  • Occupier - if IsOccupied is true, this will return the LevelTileEntity which occupies the tile.
  • HasProp - a bool which is true if the tile has a prop object (E.G. a vending machine).
  • Prop - if HasProp is true, this will return the LevelPropEntity which is on top of the tile.
  • HasPropOrigin - a bool which is true if this tile has the origin of a prop. Some bigger props cover multiple tiles, so finding their origin may be useful for things like waypoints, where you'd want to path to an instance of a prop, rather than every tile it covers.
  • GridPos - a Vector2 object of the tile's X&Y position relative to the grid.
  • Index - the index of the tile in the grid array.

Tile functionality

Individual tiles contain some functionality which may be of use:

  • SetOccupied() - this is ONLY to be used by the level editor, and level loading system.
  • SetProp() - this is ONLY to be used by the level editor, and level loading system.
  • SetPropOrigin() - this is ONLY to be used by the level editor, and level loading system.
  • Contains() - call this function to check if a given point is within the tile (in 2D world space).
  • HasNeighbours() - call this function to see if the tile has any occupied neighbouring tiles.
  • IsAtTop() - call this function to see if the tile is at the very top of the grid.

Grid functionality

The grid itself has some in-built functionality (aside from its debugging gizmos) that may be useful:

  • GetTileAtPosition() - call this to get the tile which covers the given position (in 2D world space).
  • GetTileAtGridPos() - this performs the same functionality as GetTileAtPosition, however works on grid space not world space.
  • GetTileNeighbours() - call this with a tile object to return an array of neighbours, which can be used nicely with the TileNeighbour enum. Be aware, if a tile is at the edge of the grid, a neighbour reference may be null, so handle this in your code.
  • GetNeighboursFromBounds() - this returns an array of tiles around a tile given bounds information (the array includes the original tile at index 0).
  • ClearGrid() - this is ONLY to be used by the level editor, and level loading system.

Getting properties

If a tile is occupied (see tile metadata above), you will be able to get properties of the occupier. The same goes for props. This property information will be useful to drive gameplay systems, such as fire spreading.

Tile occupiers are of type LevelTileEntity, and props are of type LevelPropEntity. Both of these classes contain the parameter Type, which is what you will need to use in order to query the tile/prop parameter databases. (They also both contain a parameter RenderOrder for returning their sprite's current sorting order, and a function Initialise for spawning them in the grid. If instantiating a prop, this Initialise function should be used instead of calling SetProp on the grid, as Initialise will handle all of this for you correctly. LevelPropEntity also contains rotation information, and functionality to rotate it after being spawned. Please note: props that are rotated after they are spawned may cause issues. Their colliders will update to represent the new rotation, however the tiles they occupy will remain as they were at their original rotation - this is due to the fact that a rotated prop may not fit the environment, and would therefore destroy itself. Please ONLY edit use rotation at runtime if you are aware of the potential consequences, or the prop is designed to work around that (e.g. doors).

In this example, we are querying the level's grid for a tile at X/Y location position and getting the type of the tile within it. This code assumes prior checks for tile IsOccupied and the level/grid being loaded: LevelManager.Instance.Grid.GetTileAtPosition(position).Occupier.Type.

With the Type acquired, we can now get its properties. To do this, you can use the TileProperties static class. This class has data which is populated asynchronously, and so you should check TileProperties.Loaded before querying it.

When Loaded, TileProperties provides functionality for:

  • GetDescription() - given a Type, this will return the tile's description string.
  • GetSpriteSet() - given a Type, this will return a set of sprites and their bounds for use on the tile.
  • IsPathable() - given a Type, this will return true if the tile is pathable.
  • IsFlammable() - given a Type, this will return true if the tile is flammable.
  • AllowsProps() - given a Type, this will return true if the tile supports props.
  • GetVariant() - given a Type, this will return a TileVariant enum value to tell you if the tile is of WALL or FLOOR variant.
  • GetUseage() - given a Type, this will return a TileUseage enum value to tell you if the tile is for INTERIOR or EXTERIOR useage.
  • GetZOffset() - given a Type, this will return an integer to be used for offsetting the tile's rendering order.
  • IsVisibleInEditor() - given a Type, this will return true if the tile should show in the level editor UI.

A similar system is in place for props. Using a similar example to above, here we will get a tile at a given position, and grab its prop (assuming prior checks for being occupied, and having a prop): LevelManager.Instance.Grid.GetTileAtPosition(position).Prop.Type.

With the prop's type, you can now query the PropProperties static class (after waiting for it to be Loaded), with any of this functionality:

  • GetDescription() - given a Type, this will return the prop's description string.
  • GetSpriteSet() - given a Type, this will return a set of sprites for use on the prop.
  • IsScriptedObject() - given a Type, this will return true if the prop is a scripted object.
  • GetScriptClassName() - given a Type, this will return a string matching the name of the script's class (if IsScriptedObject). You can convert this string to the actual class using reflection, with System.Type.GetType().
  • IsWaypoint() - given a Type, this will return true if the prop is a waypoint.
  • GetWaypointTarget() - given a Type, this will return a PropWaypointUser enum value to represent the user of the waypoint (if IsWaypoint).
  • GetWaypointType() - given a Type, this will return a PropWaypointType enum value to represent the type of the waypoint (if IsWaypoint).
  • IsPOI() - given a Type, this will return true if the prop is a point of interest.
  • GetPOIType() - given a Type, this will return a PoiPoint enum value to represent the type of POI for this prop.
  • GetPOIGoonCount() - given a Type, this will return an integer representing the maximum number of goons that can use this POI concurrently.
  • GetPlacementLocation() - given a Type, this will return a PropPlacement enum value to represent its intended location (INTERIOR or EXTERIOR).
  • IsUnpathable() - given a Type, this will return true if the prop's tile should be considered unpathable.
  • IsVisibleInEditor() - given a Type, this will return true if the prop should show in the level editor UI.
  • GetZOffset() - given a Type, this will return the prop's unique z-order offset value.

Tile waypoints are intended to be used for vehicles - for example, the GOON_BATTLEBUS should spawn on the START waypoint type, drop students off on the MIDDLE waypoint type, and then exit the level on the END waypoint type.

The GOON END waypoint is handled as the victory marker in levels.

Adding new tile/prop types

New tile and prop types can be added using the DWB Toolkit in the root of the repo. This tool allows creation of props and tiles, and management of their sprites and metadata once created.

The tool writes to a proprietary binary format which can get jumbled in Git merges, so please refrain from adding or modifying any tiles or props unless given explicit permission by other members of the team. Deleting props or tiles can cause SERIOUS implications for maps that utilise them: it is recommended that you mark a tile or prop as "deprecated" in its configuration - this will hide it in editor, but allow backwards compatibility for older maps.

Clone this wiki locally