Category Archives: Brainstorms

Look and feel

Though I’ve already done a bit of art for the game, I’ve honestly been fluffing about this one for quite some time. I didn’t have a definitive look and feel so i’m setting one up now.

I had been discussing with B about how to really get into terms with this. I think my main problem, which includes the art I’ve already made, is that the inspiration came from simply an attraction to a particular artwork (in this case Gray Shuko), but had nothing to do with the theme or the feel of the game itself as I want to depict it.

This is 2400 AD:

Playing it when I was but a babe, I can summarise the overall feeling in several points.

  • Dark
  • Bright neon lights
  • Dirty and clean contrasts
  • Feeling of unease in the environment

Note that while certain feelings are not readily expressible from a lookdev perspective, it helped to focus on the overall emotion/feeling I was having when I played the game, because that is the sort of thing that motivated me to develop CITIZEN. Perhaps what seems unrelated might actually be useful when the time comes. Who knows?

As B pointed out, the darkness comes from the black background, and the ‘neon’ probably comes from the magenta-coloured gui frames.

The ‘clean’ is obvious, because the graphics are simple. But I think I there was a ‘dirtiness’ in line with what was going on as a game, so that there are those contrasting elements, especially when going from one area to another (eg entering a room from exterior).

The feeling of unease is harder to track down, and I think that’s more of a gameplay issue, at least from how it looks like right now. I think however, that it will also inform other design aspects, like how the robots will look like, and perhaps even how sound, or the writing is done.

With those 4 points guiding me I scoured for anything in the web for indicators that may give me an idea how to hammer home those things. The thing was, I didn’t necessarily look for the most beautiful images, because I knew that beautiful images were stuffing up my efforts to have an actual theme to the game.

Good examples and why

Dark, neon, simple shapes. This is one of the prime lookdev reference images. Note that I’m not aiming for pixel art, but rather, aiming for the simplicity in detail, as well as non-assuming design.
The colours are muted in the darkness, and the outlines are aesthetically-pleasing.
From the game ‘The Last Night’; again, not about pixel art — and not even about the sidescroller viewpoint, which is not what CITIZEN is, but rather, the dark mood.
From the game Black Annex, I keep this peg to remind myself of simplicity in rendering. Granted, this is rather austere, but the game (gameplay itself) gives a connection between the look and how the game responds and feels spatially, so that simple renders can be given a lot of life, and other considerations and compromises can be made depending on how the graphics are used.
The space is cozy; the rendering is more in line with my initial art. The outlines are pleasing (again), and the proportions are not so realistic.
Not every location in CITIZEN is in darkness, so in exterior situations, I think this lighting condition, and overall feel, is close to the feel I’m going for. I won’t be able to really represent atmospherics, but the cyan haze is appealing.
Though not dark, I can imagine myself filling in the darkness and the mood and tone. The appeal of this image is of the minimum detail to represent the scene. It looks very game-y, The colours are represented more matter-of-factly; while I prefer grading the artwork to fit the darkness, I keep this peg to remind me that I don’t have to go too overboard with it.

Lighting considerations

In respect to the Good Examples shown above, the most use of lighting was the picture of The Last Night which features area lighting, where one portion of the screen will affect a surface’s diffuse colour. This is fine as long as no shadows are implicitly cast (ie by use of explicit harsh lighting).

Note that even when neons were used in the abovementioned image, the overall effect was still diffused; as it is pixel art, there’s an acceptance of these compromises. The artwork that I have to develop should also have the same acceptability using those compromises.

A good example of area-based lighting. It’s basically a masked colour layer that sits on a particular region, affecting those elements that come underneath it.

Proportional considerations

The image shown on the right is probably the kind of character proportions/shape that I want. This means it is realistically proportioned, but not particularly realistically shaped or accurate.

Bad examples (to avoid)

While appealing in of itself, the rendering is a tad too realistic: reflections, soft and hard shadows which require any character in the scene to be rendered as such. Textures are also too subtle. I would like use gradient of colours more often than textures.
From ShadowRun, this is too realistic.
While I love this game, the rendering — like Fallout — is done with too many hi-freq textures.
Though I had originally imagined a scene in the Hills in the same mood and feel as this, this is the sort of lighting that is not practical to do, so I avoid not only these types of lights, but a pitch black exterior, where the only light will inevitably have to come from point sources.
Too simple to the point where I won’t get my tone. Outlines, when too thick, end up brightening the colours, which is the reverse of what I want to do.
Though a beautiful image, the grading is too biased and ultimately too realistic.
Amazing to look at, nevertheless, even static light sources where pronounced shadows are produced is going to be a problem. However, lights above the reach of the main level (eg player, npc, ground-level env), might be ok, even when animated like this picture. Rain might also be a good thing to explore at a later time.

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.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.

Thoughts on accomps

Accomps is ‘accomplishments’ and I’ve separated map-related accomps (m_accomps) with global accomps (g_accomps). Global accomps persist, while m_accomps are re-populated  when a map loads.

This separation may not be necessary, but for the meantime, there it is.

accomps have the key as the accomplishment, and the value is either 0 or 1. 0 if not yet accomplished (default value), and 1 if it is.

In the RND test, the accomp related to exiting an area was triggered 1 every time the player was on top of the designated area (ie current_trigger variable). But when  the current_trigger="", it triggered (using TOWT) a reset to 0. So as long as the player was not on the trigger, the accomps will always revert to 0.

On the map logic script, the ‘success’ of a map is checked whether all (or some) of the accomps have been set to 1. Because it is map specific, anything can be written here.

In the TMX side, there are some inputs that need to be done. First, the map’s accomps are written in the Map’s custom properties called ‘accomps’. Eg, accomps=talk:npc1,kill:guard1,remain:exit

It is done in the TMX because it is only relevant for this map. There are other data that could be offloaded here.

In this case, when player talks to an NPC, this interaction is marked as ‘talk’, and thus the trigger is sent as ‘talk’. If player talks to ‘npc1′ then this is sent to npc1. Now in the TOWT trigger for f_trigger_receiver.f_name==’npc1’, it is responsible for writing the proper key to the accomps. The syntax is free-form so care must be taken.

In the RND test, the killing of an enemy was not broadcast, but this is a good example of implementing such a broadcast (eg BroadcastTrigger(“killed”,f_trigger_receiver.uid)) within the main logic.

Then in the main logic, a trigger receiver is actually waiting to receive the news of death. When it does, it takes care of its own key in the accomps: accomps["kill:guard1"] = 1.


Thoughts on triggers

On the RND test, here are some thoughts on triggers.

Triggers are broadcast by a function. Triggers may have a targeted object/instance. In order to target any potential object, they’re put into a Family, which I’ll refer to as f_trigger_receiver (f_tr, for short).

There are 2 parts to triggers. The ‘main’ logic, and the ‘map’ logic. The main logic handles generic logic of triggers.

Main logic


The Family for all trigger receivers. Requires f_name, and f_receivedtrigger variables. f_name is the name of the entity which a trigger will use to refer to this instance. f_receivedtrigger is the string identifying the trigger that has been sent out.

On player GridMove reach target

Fired every time the player moves into a tile. This queries if a trigger area was stepped on.

Also, the player must have a current_trigger variable which keeps track of the trigger area it is on at any given time. This prevents re-triggering when the trigger area covers adjacent tiles. Also, this allows to find out if the player has stepped out of a trigger.


A function which handles the send off to f_trigger_receiver. It accepts a trigger_name, and a trigger_target. The trigger_name is the identifier of the trigger. The trigger_target is a comma-delimited string that identifies the objects/instances that the trigger will be sent to. The f_trigger_receiver family is used in order to go across different object types.

Other interactions

Any other interactions deemed worthy of a trigger only has to call the BroadcastTrigger function, and feed it an object that can accept a trigger.

The RND test, for example, had broadcast an NPC interaction generically by feeding it trigger_name="npctalk", trigger_target="npc1". Then the trigger was broadcast only on npc1 and processed accordingly.

There are no  ‘global’ triggers (ie triggers must always have a target). If a ‘global’-like trigger is needed, it might be better to use the player’s mover token as that, since it’s as global as you’re going to get.

Map logic

Map logic refers to the map/room-specific stuff.

Typically, the triggers for a particular room are stored in a separate event sheet (which I call scripts).

Time triggers

I put the time triggers in the map because it’s more specific to the map/mission. I still call BroadcastTrigger, but the trigger_name is specific to the map, of course.

Time triggers include ‘per-tick’ or any kind of time-related triggers.


Some instances need to init themselves before going into play. For example, a waypoint traveller needs to init the first waypoint index. This is done using the post_tmx boolean check, which is basically a switch that tells that the TMX has been completely read, and all objects have been created (and thus referenceable).

Other triggers and functions

Any other kind of triggers, whether they’re from FSM or TOWT, can be put in the map logic script. In the RND test, I’ve put in unique FSM states (eg “reachpath”) to put it in a special state so that the rest of AI can contextualise itself.

Map-specific functions are put here as well.





Converting angles to isometric angles

I don’t think ‘isometric angles’ is even a term, but I’m referring to how an angle should appear like in isometric view.

The image below describes the situation.


Given an  angle (75deg and 45deg depicted in red arrows above), what is computed angle if the circle was compressed by half (ie an isometric view). The small ellipse depict a circle in isometric view.

The yellow arrows depict the scaling effect of the point on the big white circle and is projected to touch the isometric circle.

The green arrows represent the vectors whose angles I am computing.


I must apologise to any potential researcher that this solution is entirely homemade and there might be more elegant solutions out there.

  • With a given angle, determine the normalised length of the Adjacent side A. This is done by cos(angle).
  • The length of the A enables the measurement of the Opposite side O.
  • O is computed by multiply A with the tan() ratio of the angle: O = tan(angle)*A
  • Now that O has been found out (the yellow arrow line depicted above), scale the length down as per the isometric projection. For simplicity, I’m scaling it by half (eg for 256×125 tile): O2=O/2
  • Then recompute the ratio of the known A and new O2: ratio=O2/A
  • The new ratio can be used to determine angle using atan(): new_angle=atan(ratio)
  • If angle reaches 90, then A has no length, and this corresponds with the nominal orthographic angle.
  • If angle reaches 180, then O has no length, and so the same thing.
  • If angle > 90 and < 180 the result of A=cos(angle) will be negative.  The same with tan(angle).
  • If angle > 180 and < 270 then A=cos(angle) will be negative still, but tan(angle) will be positive.
  • If  angle > 270 and < 360 then A=cos(angle) will be positive, and tan(angle) will be negative.
  • When result angle is reached, modify the value based on the quadrant of the original angle:
    • If cos(angle) is negative, and tan(angle) is negative, add 180 degrees. (Quadrant 2)
    • If cos(angle) is negative, and tan(angle) is positive, add 180 degrees. (Quadrant 3)
    • If cos(angle) is positive, and tan(angle) is negative, add 360 degrees. (Quadrant 4)
    • If cos(angle) is positive, and tan(angle) is positive, then keep result. (Quadrant 1)

C2 angle

The images above show 45 degrees as pointing NE. In C2, however, it’s pointing SE. But this orientation allowed me to understand what was going on.

C2 Implementation


Working rather well.

To reverse the operation, to get the orthogonal angle from an isometric angle, reverse tile’s width/height in O2: O2=O/(SquareTx.Height/SquareTx.Width)


Brainstorm: Larger-than-tile-size images

(This is an old log re-published as a post.)

Placing Tiles which are bigger than the Map’s tile size. A reference in the Tiled forums.

Summary of the issue is that multi-selecting tiles in while in Isometric projection does not yield a ‘flat’ orthographic placement of the tile, obviously. Ideally, a multi-selected Tile should be presented as a flat screen-space graphic, but the proper procedure, as Bjorn pointed out in the link above is to use a Collection of Images, so as to obviate the need to select multiple tiles to get to a bigger image.

This is fine in respect to the OP’s problem of putting in establishments. But my issues are putting walls, and all sorts of tiles that need to be connected precisely unto other tiles. The problem is how tiles are aligned in the first place. Tiles are anchored at the lower-left point. That means the bigger the tile gets in relation to the map tile size, the further up and right the tile’s registration will be.


On the outer hand, an Image Object aligns itself with the bottom anchor point making it ideal as a positioning entity.

I went ahead and modified TMX Importer V2 to retrieve the tileset id or image used by the Image Object, but Rex has also modified it after requesting it, so either way this is a doable solution.

Brainstorm: Thoughts on tile walls

N and W and NW tiles only

To create perpendicular wall maps, I need only N and W wall tiles, plus a NW one. N and W defines one edge each. NW defines two edges.

Then there’s the block tile, which is impassable.

S and E seemed superfluous.

Shadows and lights

Now, there’s an issue with possible spillover from the tile boundaries, for example, when some AO/shadow or lights are rendered.

Shadows on floor won’t appear on top of walls at any time, so they can be placed in a shadow layer below the walls. Lights on floor is the same thing (lights on walls, is another issue).

Generate at runtime

These floor-level effects are objects because the effect spills over to other tile spaces, and so they can placed by hand. Or, procedurally: tagging tiles with ‘floorlights’ sprites (as C2 objects) can be generated at runtime.

Shadows and lights on walls is problematic because they need to be associated with the walls, which means they follow the z-ordering.

Maybe I can ‘parent’ the z-order during creation phase (association phase). Then I need to figure out how to exclude sorting for those in ZSorter.