Understanding REXRAINBOW’s Board plugin

Overview

The Board plugin has several important dependencies that must be put in the project depending on what functionality is desired. Some of the following notes are not necessarily in Rex’s docs, which sometimes can be sparse in detail, though his examples explain things very clearly. So, in effect, the following is a distillation of the things learned in the docs and as it relates to the examples.

Board Setup

Before anything, the Board must be setup, which, at its most primitive, just the Board object, which defines the logical positions of the tiles.

Board

The Board is responsible for creating the virtual logical grid (ie tile coordinates with logical positions). It specifies its dimensions.

LayoutToBoard

This is a plugin that allows sprites/tiles to be placed on the Board as they currently are positioned in the editor. This is a convenience feature that is more useful if I was editing my level in C2. However, Tiled is my editor and will place tiles procedurally through other means.

ProjectionTx

ProjectionTx properties
ProjectionTx allows for trimetric projections, and other custom aspects. The key to its customisation is the VectorU/V.

This was an improvement that I personally suggested to Rex which is an upgrade from the original squareTx plugin. (Currently, ProjectionTx is not available at his site). The purpose of these ‘Tx’ plugins is to display the Board’s logical positions as a particular projection. Rex has kept these two aspects separate, as it is easier to visualise a ‘top-down’ Board as the basis for computation, and a ‘projection’ as a basis for defining how that Board is going to be visually represented.

When a call to Board’s Action:Create tile is made it uses ProjectionTx to place it in screenspace. It also seems that all other calls that involve visual representation, Board uses ProjectionTx to translate it.

The image to the right is ProjectionTx’s property panel. VectorU represent the direction of the U (or X or left-right) of the tile (if you imagine looking top-down) and VectorV represent the other axis. In other words, ProjectionTx is asking what is the screenspace direction of the X and Y axis of the tile. In an isometric projection, 32×16 pixels sprite, UX=+32, UY=-16, VX=-32, VY=-16. Explanation: X axis of the tile right and down: right for 32 pixels (+32), and down 16 pixels (-16); the Y axis of the tiles goes left and down, hence -32 (left) and -16 (down).

Edge

The Edge plugin works in conjunction with Board and movement. Edge objects exist between tiles, and the Edge object itself is queried if a particular edge exists between two tiles. This might contrast with the instinctive notion that we query the Board if certain Edges exist in its logical positions. After all, it is the Board’s turf. However, the way it works is that Edge objects keep track of themselves and where they exist between tiles.

Edges oriented by default along VectorU/V.
Edges oriented by default along VectorU/V.

When Edges are created, a Sprite is used to visually represent the Edge. It is thus rotated perpendicularly to the VectorU or VectorV of any given tile depending on the side of the tile the Edge is being created on. In isometric tiles, this produces a wrong result, since the orientation has a isometric ‘skewing’, and thus the angles must be set manually.

 

edges_manual_orietnation
In isometric projection, the rotation of Edges facing along U (side=1|3) is -60 degrees, and those facing along V (side=0|2) is 60 degrees.
The result of a 60/-60 degree fix based on direction of Edge.
The result of a 60/-60 degree fix based on direction of Edge.

 

Movement

Movement is more involved than Board setup. It involves at least two plugins working in conjunction with each other, and involves a third if pathfinding is needed. For my needs, I need all three.

SLGMovement

SLGMovement is the plugin that is responsible for pathfinding. Its responsibility is querying the board for the best possible path, and taking that information and feeding it into the InstGroup plugin (explained later). Thus, SLGMovement has two dependencies at all times: Board, and InstGroup.

Implicitly, it will use the first Board and InstGroup object in the scene.

However, a specific Board and InstGroup can be specified through its Action:Setup call.

The plugin computes for ‘cost’, which is the concept of how many ‘points’ it takes to travel to a tile. In the same vein, it can also prevent movement from one tile to another (for example when tile is impassable).

Edges

Edge objects can be optionally queried in cases where movement between two tiles cannot occur at a particular direction between each other (though it can occur if the path goes around the Edge).

slg_movement_edge_cost
The example here shows that if an Edge exists between two tiles that the ‘chess’ is trying to move across, then that particular movement is slg_movement.BLOCKING.

Through the example SLGMovement works this way: the path to follow is computed beforehand. This means that SLGMovement calls the On cost function repeatedly as it makes its way to query which tiles it can use to the desired destination. When by setting the cost as SLGMovement travels to the destination using its pathfinding algorithm, it can determine the best way. If SLGMovement.BLOCKING is encoutered, this means that this particular ‘leg’ of the path is not possible, and SLGMovement will try to find another way around.

Get moving path and InstGroup

The heart of SLGMovement is its Get moving path function, which calls the pathfinder. It has a few parameters:

SLGMovement dialog
Get moving path from a particular ‘chess’ object, to a particular tile (or ‘chess’). Moving points limits how far the pathfinder will trace. Moving cost is the ‘moving cost function’ that is called during query. Group is the InstGroup object which will receive the pathfinding data.

As the captions explain, the ‘moving cost function’ is the heart of the pathfinding querying. It’s here where a valid path is traced based on the moving points and the results of the ‘moving cost function’.

The weird thing about this setup, however, is in the InstGroup, which is an implicit dependency. You need InstGroup to make SLGMovement work because there is no other way to store the resulting path.

Once the path has been stored, the next part is the actual movement, which is handled by GridMove.

GridMove

Once SLGMovement has stored the path in InstGroup, GridMove is used to access the path. The principle is to start the chain of calls to GridMove by ‘popping’ the first element that’s stored in InstGroup. The first ‘pop’ and move occurs in the ‘Mouse on click’ or ‘Touch’ trigger itself. When the first node is ‘popped’ it is SOL’d, and thus a call to ‘GridMove move to tile‘ will yield the SOL’d tile as the target.

GridMove On reach target
GridMove is used as a chain, where an initial move is made, and then using GridMove’s Condition:On reach target to iterate through the next point on the path. Note InstGroup’s ‘Pop one instance’ usage here, as it looks like a condition, but actually is a condition and an ‘action’ in a sense that it ‘pops’ one instance off the group ‘path’, and selects (SOL) that instance for GridMove to move to.

Then on Condition:On GridMove reach target, another instance is ‘popped’ out of the InstGroup. As the caption above describes, the ‘popping’ of the the instance is a GridMove condition. The condition will return a False if there are no more elements to ‘pop’, and in the image above, Function “GetMoveableTile” is run after the path has been reached.

Note that the ‘popping’ occurs at the head of the InstGroup array. This denotes that the sorting of the path nodes where the first element is always the next waypoint down the line.

Connection to Board

Normally, I would expect a explicit connection from GridMove to the Board, and hence, access to ProjectionTx in order to find the screen position of the logical coordinates. But as I look at it, the GridMove is attached as a behaviour of any given ‘chess’ (ie a movable element on the Board), and a ‘chess’ instance can only be in one Board anyway. So it seems that GridMove is able to trace back the Sprite’s association to the Board it was originally created in.

Conclusion

So, these are the following procedures that comprise isometric tile-based movement.

Layout

  • Board plugin as the basis for providing logical coordinates for positioning, and populating its own tiles with content through procedure.
  • (Optional) LayoutToBoard plugin as a convenience feature to populate Board with ‘chess’ data based on how the objects themselves are placed in the C2 editor in relation to the established Board.
  • Edge plugin as another element that is can be used in conjunction with SLGMovement to determine pathfinding. Though Edge is not technically related to Board, determining Edges is best done during the setup (though it can be changed any time).
  • ProjectionTx plugin as a visual transformation of the Board into a desired projection. In this case I’m concentrating on an isometric (or possibly trimetric) projection.

Movement

  • SLGMovement plugin as the pathfinding engine. It is connected to two other plugins: Board and InstGroup. By default, it will use the first object of each kind, so there’s no need to setup SLGMovement unless you need to. SLGMovement computes the cost of movement from one tile to another in the Board, and in this ‘cost function’ you can influence the pathfinding (eg blocking tiles). It then puts the resulting path into a named group in InstGroup.
  • InstGroup plugin as the container and actionable condition that works in conjunction with GridMove to ‘daisy-chain’ the stored waypoints. InstGroup allows ‘popping’ of instances in the array (ie group) which give the effect of moving to the next waypoint which is then fed into GridMove
  • GridMove behaviour as the function that moves the Sprite. GridMove is implicitly connected to the Board that the Sprite had been generated in using Board’s Action:Create tile method.