Category Archives: Rex’s plugins

Workflow: Diagonal movement across edges

The basic problem is that when moving diagonally, the edges are ignored because edges only exist at the sides of the square, and not at the corners.

Moving across diagonally travels across the corner of the logical square, which do not have any edges.

The solution to this was to query both the start tile (slg.PreTileUID) and the target tile (slg.TileUID) and from there, determine the GridMove/Board direction index that the current path was taking.

Using the principal direction (let’s assume it was a diagonal value of 6 (as demonstrated in the above image), the two other directions flanking the main one was also queried.

In the above image, the movement from the start tile is at direction 6. Direction 2 and 3 were derived from this by a lookup that defined two flanking direction for any given direction.

Then the target tile was also queried, but this time, the principal direction was the reverse of the start tile (computing for the reverse tile was made simpler by using a lookup, although a simple modulus would have done it, too). In other words, 4 is the direction. Using the same lookup, 0 and 1 were looked up as the flanking reverse directions.

Then a check is made against existing edges: are there any edges on the 2 and 3 directions of the start tile? If so, movement cost is BLOCKING. If not, then check the target tile’s 0 and 1 direction edges if they exist. And if they do block the movement.

The method used in determining the principal direction was simply comparing the logical X and Y positions of the start and end tiles.

 

Gotcha: SLG, moving across edge issue

There is a gotcha with using SLG movement and edges which relates to cache cost (a parameter in SLG movement).

The image above describes how a movement from tile [1,13] to [1,12] should yield a path that comes around. However if the cache cost parameter is set to Yes then it will refuse to yield a path at all.

Setting it to No will solve the issue.

Not sure what this is about, but noting it down for future reference.

Workflow: Z-Sorting by Y

In the RND test project, I ran into performance issues with ZSorter due to the high number of instances I was using. I’ve easily re-implemented the C2 ‘native’ action of z sorting and the performance is much better.

However there is a gotcha.

The native version, despite what seems to be a vague reference of layering behaviour in the manual (search for Sort Z ordermoves instances which might have been in other layers to layer that had been sorted last. If the sorting is done per tick, there is no way to force a particular instance to another layer and expect that to render accordingly. (For example, I created a ghost clone over my main sprite. The ghost sits on a top layer, but is an instance of that sprite. Because the ghost belongs to the same sort family in which I base the sort, the ghost also gets sorted. And because the action moves the ghost into the same layer as the other instances, it loses its layer blending purpose.

The solution looks more like a hack: in cases like the above, where instances need to be separated, the sort reference variable (the variable that the action uses as a basis for a sort), should be overridden. In the case above, the ghost instance’s sort reference variable had an extremely large value so that the sort engine will always have to place it on top.

Workflow: Using AnimationLoader, dynamic tilesets

As usual, Rex has done it again. Or rather, he’d already done it.

The look development of the game is what I’ve always been concerned about. I’m creating tiles, binning them, replacing them. The tile management in Tiled is a bit too simple for my needs.

First came the issue of volatile tile IDs. Then the inability of re-arranging the tiles. So what I’ve done now is to offload all the actual organisation of data to 3d and C2 workflows. What this means is that I no longer have to use tile IDs to reference.

This is an outline of what I’m thinking of designing (and have implemented it for the most part at the end).

Renders

3d renders, or wherever the tile renders may come from are rendered directly to the C2 folder’s /Files directory. They have the following name convention.

_<tileset_name>_<tileset_id>.png

This collapses the tilset name and tile id into one name. These are then put into a flat hierarchy in the /Files directory.

C2 animation name

Back in C2, I create a single tile sprite. The content of this sprite can be empty because the idea here is that the image will be dynamically loaded in.

This is the gtiles sprite (GBoard tiles), and contains (I think) all of the tilesets used in the game. Now the tilesets are stored in C2’s animation blocks. So in the gtiles sprite, I create all the tileset names that should exist:

proto_gnd
proto_walls
proto_canal
..etc

This refers to the naming convention of the .png described above.

C2 animation frames

After the animation blocks/tilesets have been created, then I note down how many frames each tileset should have. I create the exact number of frames for them though the frames are blank. If I don’t I will get errors in the Browser console, but it won’t stop the execution of the game.

AnimationLoader

Rex’s AnimationLoader handles the loading of the renders in the /Files folder by going through every animation block in the gtiles sprite, and then through every frame that it has. I’ve written events that concats it properly, adds the underscores to conform with the convention, and it loads the images into those frames.

Tiled

This is the important bit.

In Tiled, when I load in the tiles into the tileset, I must reference the png files in the /Files folder, because when the TMX is read, the image source from the tile is also read. This image source TMX attribute is the string that is parsed in order to determine which tileset this belongs to, and what the tile ID is. So, in effect, by the naming convention alone, regardless of which tileset the tiles belong to in Tiled, the fact that the file contains the tileset and id, that’s enough to make a connection to C2. In this way, it doesn’t matter how I arrange my tiles in Tiled because I only use the name of the png for the correspondence.

Collisions

Collisions are often defined in the C2 image editor, and the information is stored in the caproj. However, when dynamically loading sprites, the corresponding collisions must also be dynamically loaded.

I’m currently implementing a solution to this which involves writing out .col files (collision files) that is partnered with their respective images. This much in the same vein as .imagepoint files.

Collision polygons are defined in Photoshop using paths. A ‘Work Path’ must be created, and a jsx to save that path is run. This outputs a .col file alongside the .png file that is being edited.

Back in C2, I’m currently modifying Rex’s AnimationLoader to take in this .col file implicitly, by reading the file, and then injecting the information directly into the poly_pnts array of the Sprite object.

 

Thoughts on displaying adventure text

Adventure text can be long, and should be variable as much as possible.

In the RND test, I’ve formulated an initial design that has the following aspects.

Terms (TextTerms)

The use of terms mean that a keyword is used as a topic. So if I used the term ‘missionsuccess’, then I could define that the displayed text is ‘Mission successful! Congratulations!’

Furthermore, I can use a TMX entity, for example an npc with the name ‘letigus’, and use that as my term. And thus define ‘letigus’ as ‘Hi, my name is Letigus. What can I do you for?’

Also, through the use of terms, I can encapsulate a variations into one term. This is the syntax which I use to implement this. This is written in a separate text file which read by the AJAX object and then put into a Dictionary using the CSV2Dictionary plugin by Rex.

Each term is defined by at least 2 lines. One line is a declaration of how many variations there are. And the succeeding lines are the content of the term.

<term>|<default index>/<maximum index>
<term>.<index>.<text type>.<duration>|<text>

The first line’s <term> is the declaration of the term’s name. The default index refers to which index it should start with. The maximum index is expected maximum variations of the term.

The second line’s <term> signifies this is the term being used. The <index> is defining this particular term’s index. <text type> can be anything that identifies the kind of text it is supposed to be. For example, the text could refer to a person speaking, or it could refer to a ‘narrator’, or it could refer to a description of something. This <text type> is used to colour the text according.y The <duration> is the number of seconds that the text will hold. If 0, it will hold indefinitely, which is useful in cases, for example, if a player is killed, and a ‘defeat’ term is used. Then there is a bar ‘|’ and the <text> follows afterwards.

Note that in the text file, there are no newlines, so the use of ‘\n’ is just a marker for a C2 text replacement for an actual C2 newline character.

To recap, here’s an example:

look_r1|1/2
look_r1.1.desc.0|The place is a smelly hole.\nAnd a sight for sore eyes.
look_r1.2.desc.0|You don't know how anyone could live here.

So at the start, ‘look_r1’ is defined as having 2 variations, and it starts at the first index.

Then look_r1’s two texts are defined, each specifying their own index, and type, and duration, and finally, the text.

Displaying the text

The display of the text is then offloaded to another function (DisplayText) which sets the duration and colour based on the data it receives from the Term itself.

For example, if the type is an NPC speaking, the DisplayText function will wrap the text in quotation marks, and maybe give it a different colour.

External text file, map-specific

As I said before, the AJAX and CSV2Dictionary plugins are used to transfer an external text file’s contents to a dictionary, and following the format above, this is relatively trivial.

CSV2Dictionary requires a pair separation by a specified delimiter. I chose the default (comma) and used the  bar ‘|’ as a separator within the tokens.

In the RND test, there was no distinction between map-centric adventure text and more generic/global text. However, this should be implemented as it makes most sense.

Workflow: ZSorter, sorting other imagepoints

In this post I write that there is no way to customise the behaviour of ZSorter to deal with sorting objects that have a different imagepoint as a sort reference. I was wrong. In fact it is possible to sort objects out a specific way using ZSorter’s On sorting function trigger.

Simple sort using a particular imagepoint rather than the default one.