about 6 minutes unity

Tactical-RPG Move Range

In Tile-based games finding targets or showing valid tiles in an area can be done using this algorithm.

How would you do these things in a tile-based game?

  • Display selectable tiles in an area.
  • Find all entities in a specified area.
  • Calculate the best tile or target to hit in an area.

I say tile-based game because this technique loops through all tiles in an area starting from the start position.

It will continue searching until:

  • There no more tiles left.
  • Was told to stop.
  • Hit the max depth.

Showing Movement Range

Tile search is used for showing the movement range and attack range.

In Rifle Storm, it starts at the MoveCommand inside Show(). This is called when a command will be displayed on screen.

// MoveCommand.cs

public override void Show() {
    Clear(); // colorMap.Clear();

    props.OnVisit = OnVisit;
    props.MoveCheck(currentEntity, currentEntity.iso.tile);

    tileSearch.Search(props);
}
  • Clear will remove all unrelated tiles from the view.
  • OnVisit is called for every tile visited by the move.
  • MoveCheck is where the tile search is configured, move length, avoid enemies, etc.
  • Search will start the search.

What is props

props is similar to the Strategy design pattern, it is an instance that encapsulates how the action will be performed.

The class is called TileSearchProps and it has methods for handling a move search, shoot search, effect search etc.

Visiting a Tile

Final Fantasy Tactics also uses this algorithm to show movement range.

For each tile searched, if it's a valid tile (no enemy occupying, etc) then display a green color.

// MoveCommand.cs

private void OnVisit(Vector2 pos, int depth) {
    IEntity en = teamList.FindEntityAt(pos);

    if (en != null && en != (IEntity)currentEntity) {
        // don't show color
        return;
    }

    // cannot walk to same position
    if (currentEntity.iso.IsAt(pos)) return;

    colorMap.PaintTile(pos, walkColor);
}

To determine if the selected tile by the user is valid, the game will check if there is a color on the tile. Has a color, then it's valid.

Configuring The Move

The blue tiles are created using a similar algorithm.

Because moves can be initiated from other parts of the code base. I created a handy TileSearchProps strategy class. This will configure the type of tile search wanted.

// TileSearchProps.cs

public void MoveCheck(IEntity currentEntity, Vector2 startPos) {
    Reset();

    this.startPos = startPos;
    length = currentEntity.equip.MoveRange + 1;

    minLength = 0;
    costLimit = currentEntity.equip.JumpLimit;

    bool moveThroughEnemies = currentEntity.HasGadget(GadgetType.BarbedWire);

    OnCheck = (pos, par, depth) => {
        bool walkable = tileUtil.IsWalkable(pos, (en) => en.IsTeammate(currentEntity) || en.IsDead || moveThroughEnemies);

        return walkable;
    };

    OnCost = (pos, par, depth) => {
        if (par.x == -1) return 0;

        int cost = tileUtil.JumpCost(pos, par);

        // remove water for now
        // float water = objectMap.GetWaterDepth(pos);
        // if (water > 0) return (int)water + cost;

        if (currentEntity.equip.HasVal(Stat.UnlimitedJump)) return 0;

        return cost;
    };
}
  • length determines how deep should the search go. This is called depth.
  • costLimit is used to determine how high an entity can jump. See the pathfind post.
  • OnCheck is called for every tile checked, if returned false, then the tile is skipped and OnVisit will not be called. par is the parent tile.
  • OnCost is called for every tile and a number -- the cost -- for moving there should be returned. If the limit is reached, then that line of search is stopped.

didn't include all the TileSearchProps methods because most of them are custom for the game. I've only included one to give an example. Some searches like for shooting include line of sight searches and I felt they are out of scope for this tutorial.

Note

+1 is added to MoveRange because tile searches on the start tile (where the entity is) counts as 1. I want it to extend out one tile further.

Note

Water will slow down entities movement, like in Final Fantasy Tactics. I commented out the water code because I didn't want to add it to the game. But it works fine.

More Examples

Tile searches in Rifle Storm are used in all over.

  • Any player action, moving, shooting, knifing, grenade throws.
  • Ability effects, grenade explosions, heals, etc.
  • Gadget effects, like detecting if a player is beside a friendly.
  • Bot AI like finding targets to attack at a specified tile.

Conclusion

I've posted the source code for tile searching below. If you have any questions please post below.

Note

I didn't include all the TileSearchProps methods because most of them are custom for the game. I've only included one to give an example. Some searches like for shooting include line of sight searches and I felt they are out of scope for this tutorial.

Back to tutorials