WIP – Stall A (2017 01 03)

First asset: “Stall A” which is a food-stuffs place.

stall_a_2017_01_30_1

Advertisements

It started as a hobby…

…CG, that is. Now, I’m a professional. I’ve been so for 15 years. After a while, though, it becomes a tedium. If you’re good at certain things, it’s quite easy to be scoped in to do those things over and over again because employers would rather employ you to maximise the benefits of your proficiency.

This itself isn’t half bad, if only bosses actually knew what you did.

As I began my career, ‘career advancement’ never entered my mind. That meant that I didn’t know I was coming into a career, nor did I expect my bosses to advance my career while being employed by them. I think this is because I was actively advancing on my own. I was learning new things, I was getting better at the things I already knew.

Now, there is a great dissatisfaction when that advancement stops. When it does, I question why the company doesn’t do more for me. Then I come to understand that even if I had been given a SIGGRAPH pass, or sent to NAB, or some artist convention in Europe, simply knowing more is not career advancement. Neither is a job title — I’m a “CG supervisor” — and neither is a pay raise.

I’ll tell you what it is.

There is a situation that doesn’t allow me to apply what I learned. To be compelled, by my situation, to allow things that go against my knowledge and common-sense tells me that my personal advancement only goes so far as my nose.

When there is no utility in learning or experience, ‘career advancement’ stops.

Let’s compare that with being able to take charge of a situation and come out on top. To apply what I know, to make ignorant mistakes, and by its very virtue to gain experience, that kind of ‘advancement’ is the kind of satisfaction that made me love the craft so much.

This other situation is not dissimilar: not to have the space to learn something new. I want to explore new ground, especially the world of interactivity (it combines my creative interests with the coding skills I’ve learned through the years), but there is no enthusiasm to explore this in the studio where I work. It is only interested in what it already does and continues to ply the same trade routes year in and year out.

When learning is limited to the scope of your established career, –a.k.a boredom — ‘career advancement’ stops.

What started out as a hobby became a profession. It was satisfying as long as you were improving, and learning new things. But 15 years down, it’s become more about evading egos and enduring the squabbles for the Almighty Dollar.

Then there are yearly reviews which tell you that if you only did this or that you’d be worth a lot more.

Workflow: Animated Tiles

Dedicated animated tiles

The syntax to activate animated tiles is in the ‘vars’ (variant) variable of each tile. Again, to recap, the Tiles’ ‘vars’ property denote the any number of states that the Tile can be in. For every state specified in the ‘vars’ property, there is a corresponding data related to the graphic that will be shown when the Tile (of that Layer) reaches that state.

Example:

vars=open*:a,close:a:15

Note * and ‘a’ and ’15’.

The * denotes that it is the default state of the Tile.

The ‘a’ denotes that instead of using another Tile ID for this state, use an animated variant.

The ’15’ denotes an alternate Tile ID which is an extra level of control in order to find the animated Sprite

Ok, so how does it evaluate which animated Sprite to use?

Through the use of Nicknames to reliably instantiate the tileset Family (ts_f) each animated Tile variant is given a unique name. The syntax template is:

<tilesheet_name>_a_<tile_id>_<state>

What this means is this: let’s say we have the above ‘vars’ property in the Tile from the ‘objects’ tilesheet, it’s Tile ID is 10. For a give state, let’s say ‘open’, the system will look for a nickname called:

objects_a_10_open

If this ts_f exists then it will be picked. This ts_f is a dedicated animated sprite for that tilesheet/tile ID/state combination.

Now, as another example, if the Layer’s Tile state becomes ‘close’, the ‘vars’ property above specifies:

close:a:15

In this case, it will look for a nickname called:

objects_a_15_close

No ‘nominal’ state

As an aside topic, this is about whether tile states (ie TcoDict) should have a ‘nominal’ (or default) state. This was apparently not a good idea, since it is logically ambiguous. A default of any state make it impossible to know what is the converse value of it.

At any rate, I’ve made all TcoDict unambiguously have a state, and this is inherited in the C2 import of the TMX.

The behaviour before was that for each TCO, it reads the ‘layers’ property and there initialises the state. This could be tedious in the future. And since it is possible to indicate the state of a Sprite/Tile by visually looking at it (eg open door, closed box), I will do it by reading the Tile’s ‘vars’ and looking for the -1 directive. Whatever state it is, it will be written as the default state of the Tile in the TcoDict.

Workflow: Multiple Tilesets

Dealing with multiple tilesets

C2 Sprite are used as tilesets in conjunction with TMX Importer. One Tile Sprite is considered a single tileset.

This the solution I’ve come up so far.

Use of Family Object and Nickname

Tilesets are grouped into a Family called ts_f (stands for tileset family). They have the instance variables that mimick the previous ’tile’ instance.

tileset_family_variables2

The addition is the Nickname plugin and its corresponding behaviour. These are essential to both instantiate and pick the correct instance of the tileset.

It’s worth nothing that I have tried native C2 methods of generating and picking instances into the SOL. However, what I have observed is that while I am able to instantiate specific Family members (by compare-picking Family instance variables), these newly created Family members were not being picked up properly into the SOL, and thus configuring these new instances were not possible.

Nickname, however, is able to generate instances and then place into the Family again. But unlike C2’s own methods, Nickname somehow allows me to reference the newly-created object by accessing the Family.

This might be a worthwhile bug report.

Because of Nickname I was able to retain all my events save several modifications as to the placement of the Tile/Chess objects. Instead of using Action:Create chess/tile, I had to use the System’s Create object to generate the Sprite instance, position it using the Board’s convenience positioning expressions (eg Board.PXY2LXY), and then use Board’s Action:Add chess/tile, which adds the entity into the Board without additionally creating an instance of it.

In summary, I am loading in tilesets manually in C2 and assigning them the name that corresponds with the ones used in Tiled. When TMX is being loaded, during Tile Placement, the tmx.TileSetname is queried and stored. This is the same being used by Nickname to instantiate that tileset/spritesheet.

Just in case it doesn’t immediately become apparent to my future self, the reason why ts_f even exists is simply to conform all tileset’s instance variables. All tilesets are put into the family to inherit the variables.

 

Gotchas: Losing ‘scope’ while calling function

losing_scope_function1

The above shows a certain situation where function calls are not aware of certain changes made by other functions.

In the picture above, I call “TanimChange by uid”. Part of the events look like this:

losing_scope_function2

Note that I create an instance using Nickname. All ts_f set variable directives work fine.

At the end of “TanimChange by uid” I return the uid of the newly created ts_f.

Back to the top image: when “TcoChange repost tile (ts_f.UID)” is called, it’s actually a very simple function:

losing_scope_function3

All I do here is get reference the UID argument and search ts_f for the UID. Unfortunately, it doesn’t see the ts_f.

In fact, when I bypass the check and let the For each ts_f loop run, it doesn’t register the newly-created ts_f instance.

I consider this a bug, and would try to get report going and try to replicate this without using 3rd-party plugins.

Workflow: Changing Tiles

Overview and purpose

I’ve worked out a method of changing tiles at run-time using the same kind of Object ‘tagging’ system I’ve outlined in previous posts (eg Storage) using the same reasoning: the need to identify entities uniquely.

The purpose of changing tiles is to indicate a state of a Tile/Chess, and visually represent the change.

For example, a door’s opened or closed state, or a floor’s damaged or otherwise modified state.

Implementation

tco_explainer

Three elements are needed for this implementation that I call Tile Change Object (TCO).

  1. TCO Object (defined in the TMX)
  2. TCO Sprite (created in C2 through TMX loading)
  3. TCO Dictionary (created in C2 in conjunction with TCO Sprite)
  4. Tiles ‘vars’ property
A TCO Object in the TMX is defined by a 'tco' type. Additionally, it needs a custom property called 'layers' to define the extent of its control over which Tile is on which Layer.
A TCO Object in the TMX is defined by a ‘tco’ type. Additionally, it needs a custom property called ‘layers’ to define the extent of its control over which Tile is on which Layer.

TCO Object

The TCO Object defined in the TMX is any Object with type ‘tco’. It requires a custom property called ‘layers’ which is a comma-separated string defining a list of Layers that is meant to be changed. by this TCO. For example:

layers=Walls,Floor

Again, the TCO Object only marks the tile as changeable. The configuration of how it changes is defined in the Tile itself.

TCO Sprite

The TCO Sprite is a Chess object that resides in its own z-layer in the Board (“Tco”). The Sprite is the effective marker of the TCO in the Board.

TCO Dictionary (TcoDict)

When a TCO Sprite is created on the Board, it creates a TCO Dictionary (TcoDict). This TcoDict’s keys is thus added using the TCO Object’s ‘layers’ property values:

TcoDict["Floor"] = ""
TcoDict["Walls"] = ""

Note that the value is empty, and this means it is in its nominal state.

Tiles ‘vars’ Property

The 'vars' property define the possible states that the Tile could be in, and the Tile ID to use if in that state. A value of -1 means to use the 'self' Tile ID, and implicitly means that the nominal state of the Tile is as defined.
The ‘vars’ property define the possible states that the Tile could be in, and the Tile ID to use if in that state. A value of -1 means to use the ‘self’ Tile ID, and implicitly means that the nominal state of the Tile is as defined.

(Edit: the ‘vars’ property syntax is always in a state of flux so this part has been edited a few times)

The Tiles in the TMX which are expected to change need a property called ‘vars’. This ‘vars’ property define a state, and the Tile ID it’s supposed to use when the Tile and Layer is switched to that state. Example of a ‘vars’ value:

vars=open:42,closed*:-1,broken:5,burning:a,burninglow:a:2

The ‘vars’ line is tokenised by commas ‘,’, which separate it into what we’ll call ‘subvars’

open:42
closed*:-1
broken:5
burning:a
burninglow:a:2

Then it is further tokenised by colon ‘:’.

The first token is the possible state that this Tile could be in. If that state has a *, it is considered to be the default state of the Tile. This is important in the initial creation of the map, to initialise the state of each Tile.

The second token is the Tile ID (of the same Tilesheet) that represents that state. If -1 is specified, it means to use the original Tile ID that the Tile originally began with.

If ‘a’ is specified in the second token, then that means that an animated Sprite is intended.

If ‘a’ was specified in the second token, then the third token can also be specified to denote to use another Tile’s animated Sprite.

For reference this is the syntax template for a subvar:

<state>[*]:<Tile_ID>|a[:<Alt_Tile_ID>]

Refer to the Animated Tiles post on how this is used.