Though this syntax was developed many months ago, I had forgotten to document this.
This edge definition refers to the edges that exists in any GTile tile/sprite. This obviously means that edge definition is a Tiled property of the GTile, which is then passed on in C2 to generate MTile edges at runtime.
Note that a GTile refers to a graphics tile which is a bigger-sized tile. An MTile refers to a movement tile which is smaller and forms the grid of possible tiles to move to. Every GTile is subdivided into equal square MTiles.
Below is an image representing one GTile, and the MTile IDs within it:
For every GTile, there can exist any number of edges. Using this image as an example:
That sprite is mapped out as:
Here, we introduce the edge syntax used to define those edges.
Where mtile_id is the id of the MTile that needs an edge definition (because it is neighbouring a GTile edge), and gridmove_direction is the direction where the edge lies on that MTile specified in the GridMove format.
In the sprite above, the edge definition is:
That is, the MTile ID 1 and 5 have a edges at Direction 0 (east), IDs 8, 9, 10, and 11 have edge at Direction 3 (north). Note that it’s possible to have defined other MTiles, such as:
…to replace 10:3, 11:3. It doesn’t matter, as long as the same edge is not specified twice.
Note that the edge definition is inputted in Tiled in its tilesheet editor. Currently, there are two Tile properties associated with edge: edge and edge4. edge was the original use, which subdivided each GTile into 2×2 MTiles. edge4 subdivided it further (4×4) giving it a maximum of 16 MTiles per GTile (this depicted in the image above).
In the C2 project, only one type is used and can be interchanged or modified depending on final design choices.
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.
Before anything, the Board must be setup, which, at its most primitive, just the Board object, which defines the logical positions of the tiles.
The Board is responsible for creating the virtual logical grid (ie tile coordinates with logical positions). It specifies its dimensions.
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.
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).
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.
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.
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 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).
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).
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:
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.
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.
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.
So, these are the following procedures that comprise isometric tile-based movement.
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.
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.
Knowledgebase for creating a Construct 2 isometric game.