/// <summary> /// casts a line from start to end returning the first solid tile it intersects. Note that start and end and clamped to the tilemap /// bounds so make sure you pass in valid positions else you may get odd results! /// </summary> /// <param name="start">Start.</param> /// <param name="end">End.</param> public TiledTile Linecast(Vector2 start, Vector2 end) { var direction = end - start; // worldToTilePosition clamps to the tilemaps bounds so no need to worry about overlow var startCell = TiledMap.WorldToTilePosition(start); var endCell = TiledMap.WorldToTilePosition(end); start.X /= TiledMap.TileWidth; start.Y /= TiledMap.TileHeight; // what tile are we on var intX = startCell.X; var intY = startCell.Y; // ensure our start cell exists if (intX < 0 || intX >= TiledMap.Width || intY < 0 || intY >= TiledMap.Height) { return(null); } // which way we go var stepX = Math.Sign(direction.X); var stepY = Math.Sign(direction.Y); // Calculate cell boundaries. when the step is positive, the next cell is after this one meaning we add 1. // If negative, cell is before this one in which case dont add to boundary var boundaryX = intX + (stepX > 0 ? 1 : 0); var boundaryY = intY + (stepY > 0 ? 1 : 0); // determine the value of t at which the ray crosses the first vertical tile boundary. same for y/horizontal. // The minimum of these two values will indicate how much we can travel along the ray and still remain in the current tile // may be infinite for near vertical/horizontal rays var tMaxX = (boundaryX - start.X) / direction.X; var tMaxY = (boundaryY - start.Y) / direction.Y; if (direction.X == 0f) { tMaxX = float.PositiveInfinity; } if (direction.Y == 0f) { tMaxY = float.PositiveInfinity; } // how far do we have to walk before crossing a cell from a cell boundary. may be infinite for near vertical/horizontal rays var tDeltaX = stepX / direction.X; var tDeltaY = stepY / direction.Y; // start walking and returning the intersecting tiles var tile = Tiles[intX + intY * Width]; if (tile != null) { return(tile); } while (intX != endCell.X || intY != endCell.Y) { if (tMaxX < tMaxY) { intX += stepX; tMaxX += tDeltaX; } else { intY += stepY; tMaxY += tDeltaY; } tile = Tiles[intX + intY * Width]; if (tile != null) { return(tile); } } return(null); }