VisibilityGrid

Introduction

The VisibilityGrid can be used to quickly calculate line of sight between IViewers. The VisibilityGrid is a very efficient class when dealing with a small number of squares. For example, if each IViewer has a radius smaller than 10, visibility updates can be incredibly fast. The larger the radius (in tiles), the slower performance becomes. Visibility calculations require O(n^2) operations where N is the view radius in tiles, so be careful with larger view radii.

VisibilityGrid and IViewer

The VisibilityGrid can contain any number of IViewers. An IViewer is an object with a position and a view radius. The VisibilityGrid uses this information to calculate what is in view. Therefore, to use a VisibilityGrid, you must create a class that implements the IViewer interface.

Code Example

The following example shows how to create a simple Sprite IViewer, move it around a grid, and view the resulting visibility.

Create the IViewer class. Normally this would be an Entity, but we're going to just whip something together quickly for this example:

public class Viewer : IViewer
{
    public Sprite Sprite
    {
        get;
        set;
    }

    public float WorldViewRadius
    {
        get
        {
            return 5;
        }
        set
        {
            // do nothing, may want to allow a setter in real code.                
        }
    }

    public float X
    {
        get
        {
            return Sprite.X;
        }
        set
        {
            Sprite.X = value;
        }
    }

    public float Y
    {
        get
        {
            return Sprite.Y;
        }
        set
        {
            Sprite.Y = value;
        }
    }

    public float Z
    {
        get
        {
            return Sprite.Z;
        }
        set
        {
            Sprite.Z = value;
        }
    }
}

Add the following using statements in your Game1.cs file:

using FlatRedBall.AI.LineOfSight;
using FlatRedBall.Input;

Add the following at class scope:

VisibilityGrid visibilityGrid;
Viewer viewer;

Add the following to Initialize after initializing FlatRedBall:

float seedX = -15; // this is the left side
float seedY = -15; // this is the bottom
float spacing = 1; // the size of each grid space (this means 1X1)
int gridSizeX = 32; // the number of cells on the X axis
int gridSizeY = 32; // the number of cells on the Y axis
visibilityGrid = new VisibilityGrid(seedX, seedY, spacing, 
    gridSizeX, gridSizeY);

visibilityGrid.Visible = true; // for debugging, this makes the light-blue Sprite show up

viewer = new Viewer();
viewer.Sprite = SpriteManager.AddSprite("redball.bmp");
visibilityGrid.AddViewer(viewer);

Add the following to Update:

InputManager.Keyboard.ControlPositionedObject(viewer.Sprite);

if (visibilityGrid.Activity())
{
    visibilityGrid.UpdateDisplay();
}

Adding blockers

You can modify the code above as follows: Add the following after creating the VisibilityGrid:

visibilityGrid.BlockWorld(3, 3);
visibilityGrid.BlockWorld(4, 3);
visibilityGrid.BlockWorld(3, -2);
visibilityGrid.BlockWorld(5, 0);

// This will help us see the debug display better:
FlatRedBallServices.GraphicsOptions.TextureFilter = TextureFilter.Point;

Did this article leave any questions unanswered? Post any question in our forums for a rapid response.

Last updated