public override void draw(Batcher batcher, Vector2 position, float layerDepth, RectangleF cameraClipBounds) { // offset render position by the layer offset, used for isometric layer depth position += offset; // offset it by the entity position since the tilemap will always expect positions in its own coordinate space cameraClipBounds.location -= position; if (tiledMap.requiresLargeTileCulling) { // we expand our cameraClipBounds by the excess tile width/height of the largest tiles to ensure we include tiles whose // origin might be outside of the cameraClipBounds cameraClipBounds.location -= new Vector2( tiledMap.largestTileWidth, tiledMap.largestTileHeight - tiledMap.tileHeight); cameraClipBounds.size += new Vector2( tiledMap.largestTileWidth, tiledMap.largestTileHeight - tiledMap.tileHeight); } Point min, max; min = new Point(0, 0); max = new Point(tiledMap.width - 1, tiledMap.height - 1); // loop through and draw all the non-culled tiles for (var y = min.Y; y <= max.Y; y++) { for (var x = min.X; x <= max.X; x++) { var tile = getTile(x, y); if (tile == null) { continue; } var tileworldpos = tiledMap.isometricTileToWorldPosition(x, y); if (tileworldpos.X < cameraClipBounds.left || tileworldpos.Y < cameraClipBounds.top || tileworldpos.X > cameraClipBounds.right || tileworldpos.Y > cameraClipBounds.bottom) { continue; } var tileRegion = tile.textureRegion; // culling for arbitrary size tiles if necessary if (tiledMap.requiresLargeTileCulling) { // TODO: this only checks left and bottom. we should check top and right as well to deal with rotated, odd-sized tiles if (tileworldpos.X + tileRegion.sourceRect.Width < cameraClipBounds.left || tileworldpos.Y - tileRegion.sourceRect.Height > cameraClipBounds.bottom) { continue; } } drawTile(batcher, position, layerDepth, x, y, 1); } } }