Was busy for a few days, now back in action to write updates. However, before I get started on that, I should probably actually write down some documentation.
Documentation
In order for the Pink Engine to properly read Tiled tilesets and maps of your design, it makes use of a number of custom properties. As such, I thought I’d take a moment to introduce these, as well as explain some other design options, constraints and practices you should keep in mind. Note that this documentation is not an introduction to the Tiled editor itself, and it assumes some familiarity with it. There's plenty of documentation for Tiled available already though.
Tilesets
The Pink Engine only works with ‘Collection of Images’-style tilesets. ‘Based on Tileset Image’-style tilesets are not compatible for the Pink Engine, nor are they planned to be.
movement properties
- move_from (str): This defines the directions that a character can move when standing on the given tile. The first symbol corresponds to the upwards direction, and goes clockwise from there. A 1 stands for a direction you can move in, a 0 stands for a direction you cannot move in. So on a tile with move_from 0010, you can only move left. On a tile with move_from 0101, you can move left and right, 1010 for up and down, 1111 (the default) for all directions, 0000 for no directions, etc. etc.
move_to (str): This defines the directions that a character can enter the tile from from. Like with move_from, the first symbol matches moving in from the upwards direction, with the rest going clockwise from there.
move_from and move_to rules are together used to create a movement map for the map in question, with move_to overriding the move_from of neighboring tiles. As a result, unless you’re doing something complicated, you can generally get by just using move_to codes ‘0000’ for impassible objects and ‘1111’ for passable objects.
Movement rules are applied to every grid square intersected by the image's 'base'. As such, an image that has a base larger than a single tile, or which has been placed off-grid to intersect multiple tiles, affects the movement on more than one tile.
base_offset properties
Just now, I made a reference to the concept of an image's base. To explain what exactly that is, I should explain a difference between RPGMaker and the Pink Engine. In RPGMaker, all tileset images must correspond to the size of the Grid. In the Pink Engine, this is not only not necessary, but actively discouraged (since it messes with the occultation of larger-than-usual characters).
Let’s take this image for an example:
This image is meant to represent some kind of computer thingie, and is used in the Pink Engine test maps. These test maps are designed for a 64 x 64 pixel grid, with this image occupying 64 x 192 pixels. So, it’s one grid square wide, three grid squares tall.
In RPGMaker, you would implement this image by turning it into three distinct tileset images. You could then give each of these images their own movement rules (typically, you would pick impassible for the bottom one, and pass behind for the other two). In the Pink Engine, the entire thing is a single image, so you can only assign a single set of movement rules to it. Normally, the Pink Engine would then apply those rules to every grid square that the image intersects. However, with the base_offset properties, you can limit those rules to instead apply only to a certain part of the image. For the computer, you would want to apply the movement rules only to those grid squares that are intersected by this particular part of the image:
For that, you use the base_offset values.
- base_offset_x_start (int): The difference in pixels between the left-most side of the image and the left-most side of the base. In this example, that would be 14.
- base_offset_x_end (int): The difference in pixels between the left-most side of the image and the right-most side of the base. In this example, that would be 50.
- base_offset_y_start (int): The difference in pixels between the top-most side of the image and the top-most side of the base. In this example, that would be 140.
- base_offset_y_end (int): The difference in pixels between the top-most side of the image and the bottom-most side of the base. In this example, that would be 180.
Event properties
The Pink Engine currently offers two distinct kinds of event properties, which are used to trigger events.
- event_on_touch (str): This is used to define a touch event, which is an event triggered by the player entering the grid squares intersected by the image’s base. The value of the property is the name of the ren’py label that the engine should jump to for this event.
- event_on_activate (str): This is used to define an activation event, which is an event triggered by the player using the activation key (spacebar) to interact with a grid square intersected by the image’s base. The value of the property is the name of the ren’py label that the engine should jump to for this event.
It is recommended that you do not define event_on_touch and event_on_activate in your tilesets, but instead add the properties to individual objects on your map through the use of object layers.
As with the movement properties, the event properties are applied to all grid squares that touch the image’s base, and are thus affected by the base_offset properties.
The Conditional Property
Just the one property here:
- conditional (str): A string containing a python expression that evaluates to True or False. If the conditional evaluates to True, the object is rendered on the map, and has active movement and event rules. If the conditional evaluates to False, the object isn't rendered, and does not influence movement or event rules. Note that the evaluation is done in the python context, rather than in the ren'py context. That means that if you want to reference a ren'py variable, you need to do it in this format:
Code: Select all
renpy.store.__dict__['name_of_variable']
Custom occultation
Added in 0.7.1
- occultates_as_y (int): Sometimes, a single tile in your tileset does not represent the entirety of the object. Even with the pink engine's support for larger tiles, you may want to build some objects out of multiple modular tiles. Think of pillars, or shadows. This can cause some issues with occultation. For this reason, the pink engine has the occultates_as_y keyword, which allows an object to occultate as if it were occupying a different y-coordinate.
Sprite Collection Properties
Since 0.6.5, the Pink Engine supports Sprite Collections. These are objects that can play animations and move around the map. NPCs, openable doors, changing background elements, these can all be implemented using the sprite collection system.
- sprite_collection_path (str): This is the property that determines whether something is a sprite collection object or just a regular object. The sprite_collection_path is the path that leads to the .json sprite collection file that the object will use as a basis.
- ref_name (str): An object with a ref_name will be assigned to a ren'py global variable of the same name, allowing you to address it in your ren'py code. Objects with a ref_name are also consistent, while objects without one reset on leaving a map.
- start_orientation (str): The orientation that the object starts with. Objects try to find an oriented version of their currented animation. For example, if you tell an object to run the 'shimmy' animation, and its current orientation is 'right', it will first look for a 'shimmy_right' animation in the sprite collection, and only look for a plain 'shimmy' if none is available. Valid orientations are 'up', 'down', 'left', and 'right'.
- movement_speed (float): The time in seconds the object takes to consume an element on the control stack (the list of commands that proscribe movements to the object). The lower the value, the faster the movement.
- repeat_commands (bool): Whether the object repeats its control stack ad infinitum or just the once. True by default.
- move_animation (str): The name of the animation used when the object changes position due to consuming elements on the control stack. 'walk' by default.
- stand_animation (str): The name of the animation used when not moving. 'stand' by default.
- turn_on_interaction (bool): Whether the object changes its orientation to face the player when interacted with. True by default.
- stand_on_interaction (bool): Whether the object switches to its stand animation when interacted with. True by default.
- default_control_stack (str): The control stack that the object starts out with. Should be a list of PinkControlCommand objects. For example [PinkControlCommand("go_up"), PinkControlCommand("go_up"), PinkControlCommand("go_left"), PinkControlCommand("go_left"), PinkControlCommand("go_down"), PinkControlCommand("go_down"), PinkControlCommand("go_right"), PinkControlCommand("go_right")] is a control stack that makes a character walk in a circle. The following types of control commands are available:
- move_left, move_right, move_up, move_down: Makes the object move one square in the given direction. Does not cause the character to turn. Can be passed the pop_invalid_move command. If set to True, the object will not try to repeat an invalid move (when something is blocking the movement route) for its next movement, but will skip to the next command on the stack. Can also be passed the animate_invalid_move command. If set to False, the object will switch to its 'stand' animation if its current movement command is invalid.
- turn_left, turn_right, turn_up, turn_down: Shifts the object's orientation to the given direction. Can be passed the stand_on_turn argument. If set to False, the object will use its 'move' animation when turning, rather than switching to the 'stand' animation.
- go_left, go_right, go_up, go_down: Makes the character turn (if necessary) and move in the given direction. Go commands can be passed all the arguments for turn and move commands, as well as the turn_and_move command. When set to False, the object will only either turn or move, not both.
- go_to: Makes an object go to a given coordinate. Object will move square by square, first along the y axis, then the x axis, until it reaches its destination. Can be passed all the arguments that the go command can be passed.
- delay: Delays the consumption of the next instruction on the control stack by a number of seconds. The number of seconds can be passed along using the quantity argument.
- play_animation: Causes the object to play a single animation in its sprite collection in full, once. The name of the animation can be passed along using the animation_name argument.
- change_movement_speed: Causes the object to change movement speed. The new movement speed can be passed along using the quantity argument.
- change_stand_animation: Causes the object to change its stand animation to the animation with the given name. The name of the new animation can be passed along using the animation_name argument.
- change_move_animation: Causes the object to change its move animation to the animation with the given name. The name of the new animation can be passed along using the animation_name argument.
In addition to the listed arguments, each PinkControlCommand can also be passed the set_movement_time argument. When set to False, this will cause the object to skip over updating the movement time for that command, cause it to immediately execute the next command. Useful for changing moving speeds, animations, and such things.
Maps
As with the tilesets, the pink engine is designed to work only with one of the options offered by Tiled: The Orthogonal orientation, with CSV tile layer format. The Pink Engine replicates the Right Down tile render order, so you should pick that as well.
Maps only have two custom properties at the moment, which tell the Pink Engine in what order to render the layers.
- layer_type (str): a string with a value ‘sub’, ‘super’ or ‘dynamic’, which tells the Pink Engine how to occultate the objects in the layer. Layers with the layer_type ‘sub’ always have their objects render below characters (so, you should use this for walls and floors). Layers with the layer_type ‘super’ have their objects render above characters (so, use this for lighting and chandeliers). Layers with the layer_type ‘dynamic’ have their objects occultate according to the character’s position, rendering below them when the character stands in front of it, and above them when the character stands behind it. ‘interaction’ and ‘movement’-type layers are planned additions for non-rendering layers.
- z_order (str): Z_order determines the rendering order within each layer type. A sub layer with a z_order value of 101 will render above a sub layer with a z_order value of 100 (but both are rendered below a super layer with a z_order of 99).
Autotile Translator
To make up for my absence, I'm throwing in a tool. To help me with the creation of the test maps, I actually wrote a bit of code that allows me to quickly turn RPGMaker-style autotiles into Tiled tilesets. Not only does it instantly generate all the legal iterations of that tileset, but it also turns them into wang sets to make drawing maps a breeze, as well as assigning the appropriate move_to and move_from Pink Engine values. You can find the executable source code for the translator (along with some sample input and output, so you should know what it looks like) on the itch page under autotile_translator.zip.
How to use:
- Put the autotiles in the “input” folder. Autotiles must be RPGMaker-compatible .png files.
- Rename the autotiles so that the translator can see their type. It separates the input name by underscores, and looks at the second word. So lab_cei_1.png is recognized as containing an image for a ceiling, lab_flo_1.png is recognized as containing an image for a floor, and lab_wal_1.png is recognized as containing an image for a wall.
- Open translator.py in any text editor, go to last line (line 482) and change “tileset_testlab” to the name of the tileset you want to output. The autotile translator will automatically append the dimensions of the tileset to the name.
- Run translator.py, and wait for it to finish running. This should only take a few seconds.
- In the output folder, you now find a whole bunch of .png files, along with a .json file. The .json file is your tileset, and should be put in your game in the pink_engine/tilesets/ folder. The .png files are your tileset images, and should be put in your game in the images/tilesets/<name of the tileset>/ folder. The name of the folder should match the name of the tileset file.