Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

A place for Ren'Py tutorials and reusable Ren'Py code.
Forum rules
Do not post questions here!

This forum is for example code you want to show other people. Ren'Py questions should be asked in the Ren'Py Questions and Announcements forum.
Message
Author
ijffdrie
Regular
Posts: 32
Joined: Mon Apr 13, 2020 1:11 pm
itch: pink-productions
Contact:

Re: Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

#16 Post by ijffdrie »

Apologies for the delay. Off-grid movement turned out to be trickier than I thought, and the heat wave murdered my productivity for a bit. Should have the new release ready by tomorrow.
Syrale wrote: Tue Jul 28, 2020 2:43 pm I love the new update and I'm really happy some of my suggestions were already implemented. Thank you so much!

I wanted to find a way to prevent the map from getting blurry when zooming in (since, at least for me, 2.0 zoom would be the most common one to use), and I came across a solution that doesn't break anything (I think!):

Code: Select all

define config.nearest_neighbor = True
Image

It does affect all images, so that could be a downside for some people. Nonetheless, I thought it might be a useful piece of code to include.
I tested it a bit, but it does seem to cause some minor side effects at default zoom. For instance, the pink diamond things get a slightly irregular outline. Still, it is handy if your game is heavy on close zooms, so I added it to pink_config.
Late addition:
Is there a way to define sprite collections on a tileset rather than on the map/object layer? This would be useful for things that have the same consistent animation, no matter which map they're on, and don't need to be interacted with (for example water tiles, or trees swaying in the wind).
Image
I've noticed Tiled grays out the property if it's defined on the tileset rather than the map. In this case, the animation won't work. Fortunately, I did get it to work when it's defined directly on the object.
In this example, the left seaweed has a grayed out "sprite_collection_path" while the right one is black:
Image
Image
Okay, yeah, that one there is a legit bug. I'll go fix it.

edit: Turned out that when identifying whether something should be a sprite collection object, it only looked at the object's properties, not the parent tile's properties. It will be fixed in the next update.
Also: My player character's walking animation works, but she can't physically move on the new map I created. I didn't change her "move_from" and "move_to" values, the terrain layer is set to "sub" and every terrain tile is set to "1111".
A list of things to keep in mind when creating new maps would be very helpful, but I can understand if that has to wait until the tutorial is out.
Good news: I'm starting on the tutorial right after this next update. I've got a couple of requests for them over discord, so I'm prioritizing it over adding sight events.
Further addition:
Okay, so I figured out why my player couldn't walk: The map's grid size was too small. I was working with a 32x32 tileset, while the player character is 45x60.

Setting the map's tile size to 64x64 fixed the walking issue, and enables me to now make a specific suggestion:
Would it be possible to allow tilesets that are smaller than the player sprite (and ideally position the player in the center)? I'm assuming the width is the issue, since taller player characters already work.
Yeah, I ran into this one myself while making the next update. The long and short of it was that a model's movement-blocking rules also applied to itself. So a character wasn't able to move in any direction that caused any part of it to occupy a position currently occupied by another part. It should be fixed now (a moving object now considers any tile already occupied by itself as passable).

I'm trying to fix the centering of bigger-than-grid characters before the release. I already did smaller-than-grid player characters last update, so I can just integrate it into the same function.

EDIT: Actually, what you should consider doing is making the character's 'base' fit the grid. Without the base being specified, a character is considered to occupy all the grid coordinates that intersect with its image. When the pc thus occupies more than a single coordinate, pathing and interaction become kind of a massive pain.

To make the 45x60 character's base occupy a single grid in the 32x32 grid (aka, make it move like it was occupying only a single coordinate), add the following properties to all the animations of the character:
{"name":"base_offset_x_start", "type":"int", "value":7},
{"name":"base_offset_x_end", "type":"int", "value":39},
{"name":"base_offset_y_start", "type":"int", "value":28},
{"name":"base_offset_y_end", "type":"int", "value":60}


(I've started learning tkinter so I can eventually make a nice, visual editor for the sprite collection jsons. Having to edit the .json files directly results in a rather opaque system.)

ijffdrie
Regular
Posts: 32
Joined: Mon Apr 13, 2020 1:11 pm
itch: pink-productions
Contact:

Re: Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

#17 Post by ijffdrie »

The first of the tutorials is finally here. This tutorial teaches you to build a very, very, very basic game in the pink engine.

note: This tutorial was updated on 2021/09/21 for pink engine version 0.11.2

Tutorial 1: The Simplest Game
Our first tutorial shall be an exercising in simplicity. It will explore the very basics of creating Pink Engine tilesets, maps and sprite collections. For this tutorial, we shall create a simple game out of whole cloth. The game’s world shall consist of a single room. This room shall contain a button. Once pressed, the player is considered to have won the game.

First, we should prepare a new pink engine project. I’ve prepared an empty pink engine module:
pink_engine-0.17.0-pc-empty.zip
(348.56 KiB) Downloaded 42 times
(it's also available on the itch.io page). To start the tutorial, create a new ren’py project, and extract the empty pink engine module into it. I have named mine ‘Brick room and the quest for the button’. After extraction, the project folder’s ‘game’ directory should look like this:

Image

Section a: The tileset
As stated, our gameworld shall consist of a single room, containing a button. To accomplish this, we need the following four tiles:
-A floor
-A wall
-A ceiling
-A button

So, let’s go make these things. I usually make my maps on a 64 x 64 grid, but the Pink Engine can handle almost any arbitrary size. Here are my attempts:

Image

Note the folder structure followed above. The Pink Engine is, for now, designed for projects with a rather specific folder structure. Each tileset should have its own distinct folder under images/tilesets/, which *exactly* matches the name of the tileset. In my case, the name of the tileset shall thus be ‘tutorial tileset’.

Now that the images are ready, we’re gonna use them to create a tileset. To do this, we start up Tiled, and go to File→New→ New Tileset

Image

You should copy the name you gave to the earlier folder, to ensure that it matches exactly. Always select ‘collection of images’ when creating a pink engine tileset, and do not embed it in the map. ‘Based on tileset image’ is not currently supported, nor are there plans to support it. The reason for this is one of the central philosophies behind the pink engine: The grid should be a tool, not an obstacle. With ‘collection of images’, you are capable of creating tilesets wherein the image diverge from one another in size, which is much more in keeping with this design philosophy. We will show the advantages of this philosophy in a future tutorial.

When prompted, save your file *as a .json file*. By default, Tiled will try to save as a .tsx file. Like with the images, the pink engine expects its tilesets to be located in a very specific folder.

Image

With the tileset now created, you should put the images into it. Just select the images from your explorer window, and click-drag them into Tiled’s new tileset. This will add the images to the tileset.

We are now almost done with our tileset, and only need to set the movement rules to complete it. We do this by adding properties to the tiles in our tileset. The Pink Engine uses two properties to determine its movement rules: ‘move_from’ and ‘move_to’. As the names suggest, the first property describes the rules for moving from this tile to an adjoining tile, the second property describes the rules for moving from an adjoining tile to this tile.

Both properties take the form of a string of length four, consisting exclusively of 0s and 1s. Each of these numbers represents a single side of the tile, starting from the top and going clockwise. A ‘1’ means that movement is allowed, a ‘0’ means that movement is not allowed. So if you have a tile with a move_from value of ‘1010’, it means that you can only leave move down and up from that tile.

For most purposes, the values of ‘0000’ (all movement barred) and ‘1111’ (all movement allowed) are sufficient. Wall and ceiling tiles should have a ‘move_to’ and ‘move_from’ value of ‘0000’, whereas floor tiles should have a ‘move_to’ and ‘move_from’ value of ‘1111’. Adding movement properties to the button isn’t necessary, as the engine will simply look at the movement rules of the underlying tile. So, the movement rules for our four tiles would end up looking like this:

Image

And that finishes up the tileset. Save it, and let’s go implement the tileset in a map.

Section b: The Map
In Tiled, go to File→New→ New Map

Image

Here is where you set some basic values of your map. For Pink Engine maps, orientation should always be ‘orthogonal’, tile layer format should be CSV, and Tile render order should be Right Down (this last one is technically not a strict requirement, but the Pink Engine will render using a Right Down render order regardless of what you pick here). Tile size should match what you just set up in your tileset, and the map can be as large as you want it to be.

Like with the images and the tilesets, you should again save as a .json file to a specific location:

Image

Any map you create in Tiled starts out with a single tile layer. We’re gonna use this tile layer to place our floors, walls and ceilings. The button is gonna wait for later. This is the point where you’re gonna let your creativity flow (well, as much as it can with three tiles) and create yourself a proper map design. I did it like this:

Image

Like with the tileset, it’s now time to apply some properties. In the Pink Engine, the order of occultation (which object is drawn in front of which) is dependent on the properties of the map’s layer (this is different from RPGMaker, where the order of occultation is dependent on the movement rules set in the tileset). Specifically, it looks at the ‘layer_type’ and ‘z_order’ properties. Our map’s only layer should have its properties set like this:

Image

Layer type (a string) tells the engine whether this layer should be draw behind (sub), in front of (super), or at the same height as (dynamic) the player. Z order (an integer) determines the draw order for layers that share a layer type. A layer with a z order of 101 is drawn in front of one with a z order of 100. I use 100 as the generic, standard z layer in my maps. The player sprite is inserted in a dynamic layer with a z order of 100.

Important Note: The Pink Engine looks only at the layer_type and z_order attributes to determine the occultation order. It completely ignores everything else, including the layering order used in the Tiled editor. If you don’t take care to have the two line up, there could be some divergence.

To add our button, we should create another layer. While we used a tile layer for our background, our button will be created in an object layer. Object layer allows you to add objects anywhere on the map. I have placed my button like this:

Image

I made sure to place the button within the boundaries of a single tile. The Pink Engine considers an object to occupy any tile that intersects with the image’s ‘base’. More information about the concept of a base will be available in tutorial 2. For now, you can just assume that an image’s base matches the boundaries of the image. So if I placed a button like this (I made the grid visible for clarification),

Image

the Pink Engine would treat the button as being present in both of those grid slots. This can be useful for bigger objects, but for a button, it would probably just get confusing.

The object layer, like the prior tile layer, also needs some properties to make it occultate in the right order.

Image

You can see that that the z_order has been increased by 1 to ensure that the object layer renders over the tile layer.

Finally, to round off our map, we also need to add a property to our button Objects in object layers inherit all the properties you gave them in the tileset, but they can also be given their own. In this case, we will be adding an ‘event_on_activate’ property to the button:

Image

This property causes interactions with the button to cause the game to jump to ren’py label with the name given in that value.

Section c: The player sprite collection
Sprite collections are created using the sprite collection editor. For the sprite collection editor tutorial, go here.

Like with the tileset, we should first create our images. I remain not an artist, so this is what you get out of me:

Image

For a sprite collection to be suitable for a player, it requires at least the following twelve animations:
  • stand_up, stand_down, stand_left, stand_right
  • walk_up, walk_down, walk_left, walk_right
  • run_up, run_down, run_left, run_right
Each of these animations should have the "move_to" property, set to a value of '0000'. The animation speed for walking and running is something you can determine yourself, except that running should have a lower value than walking (the animation speed is the delay between frames, so the lower the value, the faster the animation goes).
Image

And with that, we are done with the player sprite.

Section d: The Ren'py code
Since our game is simple, our ren’py code shall also be simple. We basically only to do three things:

We require a piece of ren’py code that sends us from the start of the game to the Pink Engine map. For this, we should edit script.rpy:

Image

Line 6 is the only pink engine-specific code here, sending you to to a new pink engine map. ‘otm’ is short for Orthogonal Tiled Map. It’s included in the function address since I have plans to add more types of maps in the future.

Secondly, we should select the sprite for the player character. For this, we should edit pink_engine/pink_config.rpy.

Image

The only line here that needed updating is line 8, which now points towards the sprite collection .json file we set up in section c.

Finally, we should create an event for the button. As a matter of personal taste, I like creating a distinct .rpy file for every Pink Engine map that I make, which I then put in the maps folder. This is by no means a requirement though.

Image

In this label, you can see the basic elements of a pink engine event. In line 1, you’ll notice that the label exactly matches the event_on_activate value we gave to the button in the map.
Line 2 starts a dynamic event. Dynamic events are one of the three classes of event available in the pink engine (the others being 'static' and 'continuous'). We will get into the distinction between the different event types in a later tutorial. The event is ended by line 19, which unhalts the pink engine map and makes it start responding to input again.
If you want an event without the pink engine map in the background, you should use `pink.otm.leave_otm()` instead of the start statement and `pink.otm.return_to_otm()` instead of the end statement. These need not neccearily be in the same label either, allowing you to switch between normal ren'py gameplay and pink engine gameplay at will.

And bam, we have our game. I have put a build of this game as an attachment here. The next tutorial will expand this game, adding more maps, furniture, shadows, and making the player taller.
Brickroomandthequestforthebutton-1.0-pc.zip
(51.76 MiB) Downloaded 74 times
Last edited by ijffdrie on Tue Jun 13, 2023 12:26 pm, edited 4 times in total.

ijffdrie
Regular
Posts: 32
Joined: Mon Apr 13, 2020 1:11 pm
itch: pink-productions
Contact:

Re: Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

#18 Post by ijffdrie »

Tutorial 2: More Map Design
In the first tutorial, we covered how to create a very basic pink engine game. In this second tutorial, we will expand our game with a second map, add various bits of furniture to our map, will force the player character to undergo a growth spurt, and add shadows.

note: This tutorial was updated on 2021/09/22 for pink engine version 0.11.2

Section A: Rooms and Map Transfers
The first and most obvious task in expanding the game is literally expanding the game. After all, it is pretty rare for a game to consist of just a single map. Adding new maps is pretty easy. First, we follow the instructions from the first tutorial to create a new map:

Image

This map is saved as a .json file to the same folder as our first map:

Image

And now we add an event that transfers us from the old map to the new one:

Code: Select all

label tutorial_1_door:
    $ pink.otm.go_to_map(target_map='tutorial room 2.json', x_coord=3, y_coord=9)
Of course, we need to attach that event to an object, but we already know how to do that from the button. In this case, I crafted a simple door graphic, and put it in our original map:

Image

Then I attached the door script to the door, in the same way we attached the button script to the button back in tutorial 1. Voila, we can now access a second map. Of course, this script only transfers us from map 1 to map 2. In order to transfer back, we also need to put an object and event in map 2. In this case, if you look at map 2, you’ll see that the location of the door is implied by the shape of the map, and there isn’t actually a door visible. Since you still need an object to attach your event to, the trick is to add an empty tile to your tileset, and attach the event to that.

Section B: Objects and Bases
Currently, our maps are a bit bare. For this reason, I drew up a bunch of furniture sprites to add to the maps. Some objects can go on the same 'sub' layer that the door and button exist on. Paintings, for example, are attached to walls, so should have the same layer type as those walls. They also don't require their own movement rules, since the grid will just look at the movement rules of the wall itself.

Image

However, this is not true of all kinds of furniture.

Image

The stools and bookcases have been added to a ‘dynamic’ layer. Dynamic layers represent objects that exist on the same plane as the player character. This means that their occultation order depends on their position relative to the player. If the player stands in front of the object, the object is rendered under the player. If the player stands behind the object, the object is rendered over the player. Now there’s currently two issues with what I just said:
  1. All our furniture is set to be impassible, so the player can never stand behind anything.
  2. Our player character sprite is only 64 x 64, so the player can never stand in front of anything.
Both these issues are fixed through customization of object ‘bases’. An object’s base represents the physical space occupied by an object. An object is considered to occupy any grid coordinate that intersects with its base, applying its properties to those coordinates. By default, an object’s base is the same size as its image. However, the pink engine has properties that allow you to adjust an object’s base. Let us take the bookcase for example. This is the bookcase’s sprite:

Image

This is the bookcase’s surface area, which we will use as the object’s base:

Image

In this case, we only need to adjust the upper boundary of the object’s base. This is done using the base_offset_y_start property, which should be set to the pixel height at which the object’s base should start. As such, the bookcase’s properties in the tileset end up looking like this:

Image

And with that, we can move behind the bookcases.

Image

Sprite collections also have bases, and can use base properties. It is strongly advised to never give the player a sprite collection with a base larger than the grid size, since it will mean that the player occupies several coordinates at once, which makes pathing and events a hassle to design. However, thanks to the base-adjusting properties, you can still give the player an image that is larger than the grid. I’m personally a big fan of using player sprites that are more than one grid tile tall, since it strongly enhances the illusion of perspective for orthogonal maps. As such, we’ll be adjusting the player character to be slightly taller:

Image

The player’s shadow is essentially equivalent to their surface area, so we’ll be adjusting the sprite collection's base to match it.

Image

For this, we’ll need to use all four base-offsetting properties. Open up the sprite collection editor again, load the player sprite collection, and add four new properties to it: base_offset_x_start, base_offset_x_end, base_offset_y_start and base_offset_y_end. base_offset_x_start is to be set to the x coordinate of the left boundary, base_offset_x_end is to be set to the x coordinate of the right boundary, base_offset_y_start is to be set to the y coordinate of the upper boundary, base_offset_y_end is to be set to the y coordinate of the lower boundary. This results in the following properties section:

Image

Sprite collections properties are set per animation, so you will have to add each of these properties to each of its animations. I've included a specific button for this in the sprite collection editor, so as to make things easier.

When putting the player on a map, the pink engine is designed to center the player sprite’s base on the occupied tile. This was done so that you can use bases significantly smaller than your grid size without adjustment. This means that in addition to the height boost from having a taller picture, our player character will move slightly upwards in his grid square (if you want to prevent this, you can create a base that matches the grid size).

Image

And now our handsome stick figure protagonist can stand behind and in front of a bookcase. Truly, there is no end to his awesome power.

Section C: Adding some shadows
Another great way of adding a feeling of perspective to your map is by adding shadows. The sprite itself is very easy to create, being a black rectangle with half transparency. This used to be kinda tricky, but thanks to the addition of object scaling is now simple as pie.

Image

Shadows have been added to this map using a new object layer. This object's layer type is `dynamic`, while it's z_layer value is set to 101. This means that the shadow renders in front of the player if the player is occupying the same tile as the bottom of the shadow (or any higher tile), and renders behind the player if the player is standing any lower. Each of the four shadowy areas you see is a single object, scaled using Tiled's built in object scaling. Scaled objects automatically render the same in the Pink Engine as they do in Tiled. The pink engine will even scale the object's base for you, not that it matters much for these shadows.

And with that, we've finished our tutorial. Like with the first tutorial, I've attached the 'game' created as part of this tutorial. Our protagonist can now on a grand epic quest of 2 entire rooms. In our next tutorial, we will focus on using sprite collections in our map design. This will include adding our game's first few NPCs.
Brickroomandthequestforthebutton2-1.0-pc.zip
(51.84 MiB) Downloaded 49 times
Last edited by ijffdrie on Wed Sep 22, 2021 12:46 pm, edited 1 time in total.

ijffdrie
Regular
Posts: 32
Joined: Mon Apr 13, 2020 1:11 pm
itch: pink-productions
Contact:

Re: Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

#19 Post by ijffdrie »

Okay, I announced that the NPC tutorial would come next, but we’re actually gonna go on a small sidetrack first. Not too long after the pink engine was first released, I also released a tool for it by the name of ‘autotile translator’. The autotile translator was created to turn RPGMaker-style autotiles into Tiled wang sets, since this was quite a lot of work to do manually.

However, the program I created then was not at all convenient to use. Since I’ve been practice tkinter to create a sprite collection editor, I thought I’d test myself by making a convenient interface for the autotile translator. I think I succeeded, so today I’m going to give a brief tutorial on how to use the autotile translator in our existing tutorial maps.

Note: This tutorial was updated on 2021/09/27 for Autotile Translator v2.1

Tutorial 2.5: The Autotile Translator
Section A: Creating the tileset
The first thing we should do is actually create the autotiles. Back in the first tutorial, we created a wooden floor, a brick wall and a black-as-the-void ceiling sprite for our maps. They looked like this:

Image

I’ve now created autotiled versions of each of the three images. These autotiles look like this.

Image

If you’re familiar with RPGMaker, you’ll recognize the template behind these images right away:
-The first image is a 128x128 pixel wall, consisting of what will be the four corner tiles of our autotile.
-The second and third image are a 128x192 pixel floor and ceiling. In addition to having the four corners, they also come with a single lone tile on the top left, and a crossing tile on the top right.

For a more detailed explanation of how autotiles work, here is a good explanation

Now, we start the autotile translator. You can find it under the downloads section on the pink engine itch.io page. When starting up the translator, you get a Graphical User Interface that looks like this:

Image

On the left hand of the screen is the list of autotiles to be translated. It is currently empty. To add a new tile, press the '+' button on the bottom left.

Image

Auto-tiles have a number of attributes that you can set prior to translating.
  • Autotile prefix: The autotile prefix serves as a unique identifier for the terrain set that the autotile translator will produce. All images created by the autotile translator will include the autotile prefix in their name, ensuring unique image names. You will also see this as the name of the terrain set created from this autotile when working with Tiled.
  • The image: The actual image to be translated. Any .png files that can be broken into appropriately-sized blocks can serve as input.
  • Dimensions: The dimensions setting determines how the autotile translator interprets the input image.
    • 2x2 results in the image being interpreted as if it were an RPGMaker MV wall autotile.
    • 2x3 results in the image being interpreted as if it were an RPGMaker MV floor or ceiling autotile.
    • 3x3 results in the image being interpreted as if it were an RPGMaker XP wall autotile.
    • 3x4 results in the image being interpreted as if it were an RPGMaker XP floor or ceiling autotile.
  • Movement: Movement determines which 'move_to' and 'move_from' properties will be generated for each tile.
    • Allowed: The 'move_to' and 'move_from' properties of each tile will be set to '1111', allowing free movement across the resulting tiles. Suitable for floors and such.
    • Blocked: The 'move_to' and 'move_from' property of each tile will be set to '0000', preventing any movement across the resulting tiles. Suitable for walls and ceilings.
    • Bounded: The 'move_to' and 'move_from' properties of each tile will be set to prevent any movement across any side that makes use of the 'edge' terrain. This is suitable for cliff sides and accessible roofs and such, preventing characters from walking over the edge.
    • Center Only: The 'move_to' and 'move_from' properties for each tile that contains any edge whatsoever will be set to '0000', while those of the lone edgeless tile will be set to '1111'. Suitable for enclosed environments, like ditched or trenches.
  • Animated: The animated toggle only becomes available once you select an image. Enabling animation on a tile will bring up a frame selection interface.
So, this is what the autotile translation settings for the wall would look like:

Image

This is the ceiling:

Image

And this is the floor:

Image

Our map hasn't included any animated tiles thusfar, so for the purpose of this tutorial, I drew up a disco floor:

Image

For reference, this is what those autotiles would look like animated:

Image

To translate animated autotiles, select the first frame, then tick the 'Animated' button. This will add a frame selection area to the GUI, with the first frame already added.

Image

To add more frames, press the '+' button in the frame selection area and select the appropriate image. To remove an image, select it and press the '-' button. The arrow keys can be used to adjust the order of frames.

The animation speed is the amount of seconds between the frames. So the lower you set this number, the faster the resulting animation will be. It defaults to 0.25, but we want our disco floor to have a slightly higher tempo, so I've instead set it to 0.15.

Image

Now we only need to set our name, and our autotiles will be ready for exporting.

Image

Then, we press the ‘export’ button and select the ‘game’ folder for our tutorial game.

Image

And that’s it. The autotile translator has now placed the image files in the images/tilesets/ tutorial_autotiles folder, and the new tileset file under pink_engine/tilesets/. The tileset is now fully compatible with both Tiled and the Pink Engine.

One minor thing you should know is that Tiled tilesets are created with ‘tile_width’ and ‘tile_height’ traits. While individual images within a tileset can diverge from that (as we saw in our previous tutorial), tilesets are still expected to be designed for specific grid sizes. For that reason, the autotile translator will throw an error if you try to export a tileset where the different autotiles have different grid sizes.

Section B: Using Terrain Set
And now, a brief demonstration of using terrain sets in the tiled editor. First, we open the tileset created by the export process in the Tiled editor. Then, open one of the old maps. Tilesets that you have opened in one of your Tiled tabs will automatically become available in any maps you are currently editing. If the terrain screen hasn't opened automatically, press the button yourself. It's this icon, at the top of the screen:

Image

The terrain set interface will look something like this. At the top you will see listed the different Terrain sets, at the bottom you will see the terrains within each of those sets. The autotile translator only ever generates two terrains: 'open' and 'edge'.

Image

Before we start applying the terrain sets, we should replace our old tiles with the ones from the terrain set. Finding the correct tile in the tileset screen can be kind of a hassle, but you can also place tiles without that. Simply hold the 'ctrl' key while having a terrain set and a terrain selected, and it will put down a tile that consists entirely of that terrain.

Image

Now we can start applying the terrain set. Select the ceiling terrain set, select the 'edge' terrain, and apply the edge to the edge of the ceiling.

Image

Now do the same for the other tiles as well.

Image

For our lovely new animated tile, I built an entirely new room. In addition to the animated 'tutorial_floor_2' terrain set, you will also see 'tutorial_floor_2_1', 'tutorial_floor_2_2' and 'tutorial_floor_2_3' terrain sets. These are non-animated terrain sets, representing frames of the tutorial_floor_2 terrain sets. Frame tilesets are usually not that useful, but are included because Tiled insists on having all frames of an animation having their own tileset tiles.

Image

And that’s it. As always, I’ve attached my example output from this tutorial.
Brickroomandthequestforthebutton2.5-1.0-pc.zip
(52.24 MiB) Downloaded 39 times
Last edited by ijffdrie on Mon Sep 27, 2021 10:25 am, edited 2 times in total.

ijffdrie
Regular
Posts: 32
Joined: Mon Apr 13, 2020 1:11 pm
itch: pink-productions
Contact:

Re: Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

#20 Post by ijffdrie »

Hey everyone. I’ve been sick for a bit, so the releases have cooled down for a short while. However, now I’m back. Today, I bring you a brand new tool for the Pink Engine: the Sprite Collection Editor. Since our next tutorial was gonna be focused on sprite collections (such as NPCs), I thought it’d be a good idea if I had this thing finished rather than having to mess around with text editors for that part. You can find the new editor on the pink engine's itch.io page.

Before we get into the editor, I’d like to point out that I set up a discord for the Pink Engine. It’s a great place to ask for advice, give feedback and share ideas. I’m also using it to provide transparency into my plans for the pink engine. You can join at this link

Note: This tutorial was updated and renumbered on 2021/09/26 for Sprite Collection Editor v2.1

Tutorial 1.5: The Sprite Collection Editor. Let's go make a player character!
Section A: The Hard Way
First of all, we should talk about what a sprite collection actually is: A sprite collection is a collection of animations intended to belong to a single object, or class of objects. Animations consist of a series of frames, which the object cycles through as it plays its animation. An animation may consist of as few as a single frame, displaying a static image. There is no limit on the number of frames per animation. Objects that make use of a sprite collection are referred to as 'sprite collection objects'. Multiple sprite collection objects may make use of the same sprite collection without issue.

In a typical pink engine game, PC and NPC characters will be sprite collection objects. Their sprite collections will include stand, walk and run animations at the very least, but may also include additional animations. Doors are also common sprite collections, having animations for being 'open' and 'closed', as well as having animations to switch between the two. Screens, switches, buttons and all other objects that change their appearance based on player interaction are also typically sprite collection objects.

For this tutorial, we will be focusing on creating a sprite collection for a PC or NPC. Tutorial 3 covers instructions for creating sprite collections for non-character objects, along with controlling such sprite collections through events.

In the pink engine, sprite collections are saved as .json files. These are structured data files that can be read and edited using any text editor. However, editing .json files can be tricky and time-consuming, and it also has a tendency to introduce fatal errors in your program if you make minor mistakes. For this reason, I have created the Sprite Collection Editor, which is a Graphical User Interface for the creation of Sprite Collections. This is what the sprite collection editor looks like when you first start it up:

Image

This is the default interface of the sprite collection editor. Let me highlight a couple of areas.

On the left hand, you have the animation selection area. Here is where you will see a list of all animations that you have added to this particular sprite collection. To add a new animation, press the ‘+’ button on the bottom left. This will create a new animation and select it. If you want to remove a selected animation, press the ‘-’ button. The arrow buttons move the selected animation’s position in the list. The order of animations does not affect the resulting sprite collection in any way.

Image

This is what the screens looks like after I've pressed the left-hand '+' button, creating our sprite collection's first animation. This will be the 'stand_down' animation. This is a standing animation that will consist of a single frame. To choose that frame, press the '+' button in the frame area, in the upper right area of the editor. This will bring up a file selection screen. Select an appropriate .png for the frame, and it will be added to the animation.

Image

As you can see, the image width/height and base width/height were automatically updated after selecting a frame. Each frame in an animation must be of the same size for the animation to work. Trying to export a sprite collection where this is not the case will result in an error. Because properties are set on a per-animation basis rather than a per-frame basis, each animation will also have a consistent base size. There is no mechanical limitation on different animations having different image and base sizes. However, it is strongly advised that a PC or NPC's base does not change between its various running, walking and standing. Doing otherwise can result in unexpected pathing oddities.

In addition to needing frames, each animation also needs a name. Every sprite collection can only have a single animation of the same name, allowing animation names to serve as unique identifiers for their corresponding animations. To change an animation's name, edit the upper right name bar. Animation names that end in '_left', '_right', '_up' or '_down' are considered directional animations by the pink engine. If you tell an NPC to play the 'dance' animation, and it's currently facing downwards, it will check for an animation by the name of 'dance_down' in addition to checking for an animation by the name 'dance'.

Image

The sprite collection editor supports properties as well. The lower-right area of the sprite collection editor is dedicated to these. To add a property, add the ‘+’ button in this area. This will bring up a dialogue for creating a property.

Image

Properties work the same (and have the same options) as they do in Tiled. Since many properties are shared between animations and it would be a pain to create them all by hand, I added the ‘apply to all animations’ button, which will copy-paste the selected property to all animations.

Four special properties are the base_offset_x_start, base_offset_x_end, base_offset_y_start and base_offset_y_send properties. These are used to set the base of your sprite collection. There is a ‘show base’ button so you can see what your base currently looks like.

Image

That's it for our first animation. We now add a second animation, by the name of 'walk_down'. So, now we add a second animation. 'walk_down'. This is a walking animation, consisting of a four-frame loop. Press the '+' button in the animation area to create a new animation, then press the '+' button in the frame area and selected an appropriate image for each of the animation's frames. The properties of this animation can be copied from the 'stand_down' animation.

If you want to remove a frame, click it to select it, and then press the '-' button. The arrow buttons change the order the frames are played in for the animation. The circular arrow key creates a copy of the currently selected frame.

Every animation has a default speed. This speed represents the amount of seconds that should pass between individual frames of the animation. The total length of the animation is thus equal to the amount of frames in the animation times its speed. As the 'default' part of the name implies, default speeds can be overridden by specifying a different speed when initating an animation.

Image

Once you’ve set your frames and speed, you should use the ‘preview’ button to make sure your animation looks like you expected it to.

With that, we move on to our third animation, the 'run_down' animation. The run_down animation is largely the same as the move_down animation, only with a different name and a higher default speed. It will safe us a lot of work if we simply copy the move_down animation and edit the copy. To do this, select the move_down animation and press the circular arrow button in the animation area. Then edit the name and animation speed.

Image

Now that you know the pattern, making animations for the other three cardinal directions should be a cinch.

Image

Finally, before exporting, we also need to give the whole sprite collection a name. Each sprite collection in a pink engine game must have a unique name.

Image

To put the sprite collection in your pink engine game, you should make use of the export button. Navigate to your game’s ‘game’ folder, then click select folder. The sprite collection editor will then automatically put the images and sprite collection .json file in the appropriate places.

With that, we've covered almost all of the buttons in the engine. The only ones we haven't talked about are the 'save', 'load' and 'translate' buttons. The first two do exactly what you'd expect them to do. And as for the translate button, well...

Section B: The Easy Way
You may have noticed that doing all this stuff was a large amount of work. What if I told you there was a simpler way? Using translation, you can instantly convert a single-image sprite template (like the ones used by RPGMaker) into a Pink Engine-ready character sprite collection. Pressing the translate button will bring up the translate screen.

Image

Use the select image button to pick the sprite template image to translate, and then select whether it's a 3x4 or 4x4 type template.

Image

Now press 'ok'.

Image

Voila! The sprite collection has been made. You will still need to add a name, adjust the base properties and perhaps make some adjustments to the default speeds, but then the new sprite collection is ready to go.
Last edited by ijffdrie on Sun Sep 26, 2021 4:42 pm, edited 1 time in total.

ijffdrie
Regular
Posts: 32
Joined: Mon Apr 13, 2020 1:11 pm
itch: pink-productions
Contact:

Re: Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

#21 Post by ijffdrie »

I have sneakily edited several of my previous posts to remove an error: PC and NPC sprite collections should not have a move_from property set. All tutorials now reflect this point.

note: This tutorial was updated on 2021/09/24 for pink engine version 0.11.2

Tutorial 3: Sprite Collections and NPCs
Section A: Adding a sprite collection to your map
We’ve talked about sprite collections quite a bit already, but thusfar the only sprite collection we’ve added to the map is the player character. Today, that will change.

Before we continue, a note: Sprite collections are distinct from animated tiles. Sprite collections are more broad in their application, being capable of moving around the map and changing their animation depending on the circumstances. Sprite collections are capable of movement or changing their animation. Animated tiles are also synchronized (so every instance of a tile on the map shows the same frame of the animation at once), whereas each sprite collection individually keeps track of its animation cycle, and can even play those animations at different speeds.

I have decided that these tutorials should not rely solely on my artistic ‘skills’, so I will be getting the artwork for today’s sprite collections from Sevahrik.

For our first tutorial, let’s add his pentagram into our game. This is what the original spritesheet looks like:

Image

The top row of the spritesheet is actually just a still image, which we will be using as our ‘off’ animation. The other three rows are animations of three frames each, which we will name (from top to bottom) ‘on’, ‘evil’ and ‘smoke’. Creating an appropriate sprite collection is done through the sprite collection editor, which was detailed in the previous tutorial.

Image

As you can see, I’ve included base offset properties in this sprite collection. The reason for this is not pathing (as it was in previous tutorials), but to ensure that attached events only trigger when you interact with the center of the pentagram, rather than with every square that the whole image intersects.

Whether or not a particular tile is a sprite collection is determined by the presence of the ‘sprite_collection_path’ property. If this property is set, and the tile is added to an object layer, it functions as a sprite collection. To add the pentagram to the game, I added a single representative frame (the ‘off’ frame) to the tileset, and then assigned it properties as follows:

Image

In addition to adding the aforementioned ‘sprite_collection_path’ property, I also added a ‘stand_animation’ property. When a sprite collection is not moving, it plays its ‘stand’ animation. By default, a sprite collection looks for an animation by the name of ‘stand’. Since we didn't give the pentagram any animations with that that name, I instead explicitly assigned the ‘off’ animation as the stand animation. Assigning a new movement animation (the default being ‘walk’) is similarly done through the ‘move_animation’ property. In this case, that’s not necessary, since the pentagram isn’t supposed to wander about.

With that, we now have a functional sprite collection object. Adding it to the game is as simple as putting the tile in an appropriate object layer.

Image

While the sprite collection is now in the game, we still haven’t coded a mechanism for actually changing the animations. This is something we’re going to do in an event. However, to actually use our pentagram in an event, we must first assign a variable name to it. To do that, we make use of yet another property: ‘ref_name’. This property gives a name to your object, assigning it to a ren’py variable. This means that you can reference it from any ren’py label. Because they are added to the global variable store, each and every ref_name should be wholly unique.

Image

You can see that I’ve also assigned an ‘event_on_activate’ property to the pentagram object. Here’s the corresponding event:

Code: Select all

default pentagram_choice = 0
label tutorial_pentagram_event:
    $ pink.otm.start_dynamic_event()
    if pentagram_choice == 0:
        """The quest has been long and arduous, but its completion now lies close at hand. """
        menu:
            "For what purpose do you seek the button?"
            "To better the lives of all mankind!":
                $ pentagram_choice = 1
                $ tutorial_room2_pentagram.stand_animation = "on"
            "To obtain power and riches!":
                $ pentagram_choice = 2
                $ tutorial_room2_pentagram.stand_animation = "evil"
    elif pentagram_choice == 1:
        menu:
            "The candles of Ahzikkar glow brightly with noble purpose."
            "Douse the candles":
                $ pentagram_choice = 0
                $ tutorial_room2_pentagram.stand_animation = "smoke"
            "Do nothing":
                pass
    elif pentagram_choice == 2:
        menu:
            "The candles of Ahzikkar glow with unnatural light, and the voice of X'zanthorik whispers from his forbidden tome."
            "Douse the candles":
                $ pentagram_choice = 0
                $ tutorial_room2_pentagram.stand_animation = "smoke"
            "Do nothing":
                pass
    $ pink.otm.end_dynamic_event()
Most of this code should be plainly readable to all you ren’py gurus. The $ pink.otm.start_dynamic_event() and $ pink.otm.end_dynamic_event() are the mandatory lines for pink engine events that we introduced in our first tutorial. You can see the usage of the object refname in lines like $ tutorial_room2_pentagram.stand_animation = "evil".

(A sidenote: Assigning a ref_name to an object also has a secondary effect: It makes your object persistent. That means that the object will be kept in memory once you leave the map, and it will be restored to the way it was once you enter. So our pentagram will still be playing the ‘smoke’ animation when we leave or re-enter. Objects without a ref_name will reset to their starting conditions. In the future, I’m looking to add an option for sprite collections that have a ref_name but are not persistent. I’m also considering a way to attach object reference names to specific maps, so you won’t have a gajillion pink engine map objects in your ren’py variable store.)

Section B: Adding an NPC
While our pentagram is spiffy, it’s not very mobile. Let’s create a new sprite collection that can actually wander about, also known as an NPC. Since I foolishly established an ‘artistic’ direction for characters by deciding to draw my own PC for the first tutorial, I shall do the same for our new NPC buddy. Making an NPC sprite collection is little different from making a PC sprite collection, except that ‘run’ animations aren’t strictly necessary. However, I tend to include them anyway, since that means you can also use them for PCs.

Image

Adding the NPC to our tileset isn’t much different from adding the pentagram. The only major difference is that you don’t need to assign a custom stand animation name for the NPC, since it just uses the default name of ‘stand’. Putting the NPC in the map is also the same as it was for the pentagram. Assign an 'event_on_activate' property so that your NPC has some dialogue when interacted with, and blammo!, you've got a proper NPC in the game. Interact with him to trigger the linked event. You’ll notice that the NPC will turn to face you when you interact with him. This is behaviour that’s enabled by default, though it can be overridden by assigning the ‘turn_on_interaction’ boolean property to the NPC, and setting it to False.

To make an NPC move around, you need to give him movement command instructions. In the next tutorial we’ll look at assigning movement commands as part of a command. Today, we’re just going to look at having our sprite collections start out with a list of commands that they keep executing over and over.

NPC movement makes use of the ‘control stack’, a variable that is attached to each and every sprite collection/ This variable is a list of ControlCommand objects, each of which contains movement or animation instructions. Whenever it is time to make another move (as determined by the sprite collection’s movement speed), the sprite collection consumes the top-most command in its control stack, and starts executing that command.

The ‘default_control_stack’ property is a string, but it is turned into python code, creating a list of movement commands. ControlCommand is the name of the class that gives the sprite collection movement instructions. The first variable passed to each ControlCommand is the type of movement that should be executed. Some types of movement allow for or require additional variables to alter their behavior. For this tutorial, we’re gonna stick to the gridwise movement related commands, leaving the playing of animations, the altering of movement speeds, and moving off-grid for our next tutorial:
  • Go commands. Make the character turn and move:
    • Directional. Make the character turn and move in a specific direction. Takes the form of ControlCommand("go_up")
      (swap out the ‘up’, with ‘left’, ‘down’ or ‘right’ as appropriate). If you want to separate the turning from the movement, use the form ControlCommand("go_up", turn_and_move=False).
    • Go to. Make the character move to a specific location, first trying to align on the y axis, then on the x axis. Note that I haven’t coded any pathfinding yet. Takes the form of ControlCommand("go_to", target=(8, 9)), where the target consists of the coordinates in the Tiled map. Like with directional, you can separate the turning from the movement like this: ControlCommand("go_to", target=(8, 9), turn_and_move=False). You can also make your character move towards a particular object: ControlCommand("go_to", target="tutorial_room2_pentagram"). The ref_name for the player character is pink_otm_current_pc.
    • Random. Makes the character go in a random direction within a given area. Takes the form ControlCommand("go_random", min_y=20, max_y=24, min_x=4, max_x=8)
  • Move commands. Make the character move without turning. Takes the form ControlCommand("move_up"). Random and move to have not yet been implemented.
  • Turn commands. Make the character turn in a particular direction:
    • Directional. Makes the character turn to a specific direction. Takes the form ControlCommand("turn_up").
    • Clockwise. Makes the character turn 90 degrees. Takes the form ControlCommand("turn_clockwise") or ControlCommand("turn_counter_clockwise").
    • Random. Makes the character turn in a random direction. Takes the form ControlCommand("turn_random").
  • Delay commands. Do nothing for a few seconds. Takes the form of ControlCommand("delay", quantity=3.0), wherein quantity is the time in sections.
Our tutorial NPC is gonna go to the spot in front of a bookstack, look at it for a few seconds, and then move on to the next bookstack. For that, I used the following `default_control_stack` value:

Code: Select all

[
ControlCommand("go_to", target=(2,8)), ControlCommand("turn_up"), ControlCommand("delay", quantity=3.5),
ControlCommand("go_to", target=(3,8)), ControlCommand("go_to", target=(3,6)), ControlCommand("go_to", target=(5,6)), ControlCommand("turn_up"), ControlCommand("delay", quantity=2.5),
ControlCommand("go_to", target=(2, 6)), ControlCommand("go_to", target=(2, 4)), ControlCommand("delay", quantity=4.5),
ControlCommand("turn_random"), ControlCommand("turn_random"),
ControlCommand("go_to", target=(2, 6)), ControlCommand("go_to", target=(3, 6)), ControlCommand("go_to", target=(3, 8)), ControlCommand("go_to", target=(4, 8)), ControlCommand("turn_up"), ControlCommand("delay", quantity=2.5)
]
Section C: Conditionals
Okay, we got a pentagram, and we got an NPC to give us exposition. However, if you’ve read the pentagram’s event, you’ll know that the idea is that the button will only appear after you’ve interacted with the pentagram. That means that we’ll be making use of the ‘conditional’ property. The conditional is a string that will be read as a python statement. If the statement equates to True (the default), the object will appear in the game. If the statement equates to False, the object will not appear.

What’s important to know about conditional statements is that they’re interpreted in the python context, rather than the ren’py context. On the plus side, that means that you can make full use of python functions in your conditional statements, vastly expanding your options. However, the downside is that referring to ren’py variables requires you to be a bit verbose. References to ren’py variables require you to put them in the format renpy.store.pentagram_choice. So, the conditional statement used to make the button appear would be

Code: Select all

renpy.store.pentagram_choice != 0
Similarly, you can use conditionals to make things disappear from the world. You may have noticed from the screenshot of the level that I added a table with a box on it. The first room has another such box in it. The idea is that these boxes contain the book and candles for the pentagram, so you'll have to search for them before being able to use it. To these boxes, I assigned the 'conditional' properties 'not renpy.store.got_candles' and 'not renpy.store.got_book' respectively. I assigned these variables the default value of False, and attached an 'event_on_interact' to each, with these events setting those values to True, causing the box to vanish.

And that’s that! As always, here's the build of the tutorial game, so you can check for yourself.
Brickroomandthequestforthebutton3-1.0-pc.zip
(52.23 MiB) Downloaded 67 times
Last edited by ijffdrie on Thu Sep 23, 2021 6:33 pm, edited 2 times in total.

User avatar
Morhighan
Miko-Class Veteran
Posts: 975
Joined: Sun Jun 27, 2010 12:54 pm
Completed: AIdol, When Our Journey Ends, Forgotten Not Lost
Organization: MysteryCorgi
Tumblr: MysteryCorgi
Deviantart: MysteryCorgi
Soundcloud: MysteryCorgi
itch: MysteryCorgi
Location: USA
Contact:

Re: Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

#22 Post by Morhighan »

Oh sweet, thank you for this.

User avatar
gas
Miko-Class Veteran
Posts: 842
Joined: Mon Jan 26, 2009 7:21 pm
Contact:

Re: Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

#23 Post by gas »

Your job is amazing. Are you in the RPGMaker community?
If you want to debate on a reply I gave to your posts, please QUOTE ME or i'll not be notified about. << now red so probably you'll see it.

10 ? "RENPY"
20 GOTO 10

RUN

ijffdrie
Regular
Posts: 32
Joined: Mon Apr 13, 2020 1:11 pm
itch: pink-productions
Contact:

Re: Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

#24 Post by ijffdrie »

gas wrote: Fri Oct 30, 2020 2:58 pm Your job is amazing. Are you in the RPGMaker community?
Thank you, it's indeed come quite a ways. I'm not in the RPGMaker community. I've played around with it a little when I was younger, but never actually released anything.

User avatar
Dragonstar89
Regular
Posts: 163
Joined: Mon Aug 12, 2013 11:28 pm
Projects: TBA
Organization: Self
IRC Nick: dstar89
Deviantart: senpai-jake
Skype: dstar_891
Location: West Virginia, USA
Contact:

Re: Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

#25 Post by Dragonstar89 »

Hello, thanks for the great work.

I've been messing around to try and get a feel for how this works; I have all my files (map/tileset/sprites) setup as per the program.

However, when I get to the line where you open the target map, I get an error saying no JSON object could be decoded, and that's it?
Beginning pre-production work on a project in Renpy. After being away for 5 years, it's time to get back in the game 8)

ijffdrie
Regular
Posts: 32
Joined: Mon Apr 13, 2020 1:11 pm
itch: pink-productions
Contact:

Re: Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

#26 Post by ijffdrie »

Dragonstar89 wrote: Tue Jun 22, 2021 12:15 am However, when I get to the line where you open the target map, I get an error saying no JSON object could be decoded, and that's it?
Hrm, that's an error that would be thrown if there's a syntax issue with one of the .json files. Since the map and tileset .json files are generated in Tiled, the culprit is probably one of the sprite .json files. I can't say exactly what it is without seeing the .json file at issue for myself, but these two issues in particular are quite common when working with .json files:
1. .json files should use double quotes (") instead of single quotes (').
2. If you edit a .json file with wordpad, microsoft office or libreoffice, it will often automatically replace the double quote symbol with opening and closing quote symbol(“”), which are distinct and thus cause crashes.

User avatar
Dragonstar89
Regular
Posts: 163
Joined: Mon Aug 12, 2013 11:28 pm
Projects: TBA
Organization: Self
IRC Nick: dstar89
Deviantart: senpai-jake
Skype: dstar_891
Location: West Virginia, USA
Contact:

Re: Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

#27 Post by Dragonstar89 »

ijffdrie wrote: Tue Jun 22, 2021 12:22 pm
Dragonstar89 wrote: Tue Jun 22, 2021 12:15 am However, when I get to the line where you open the target map, I get an error saying no JSON object could be decoded, and that's it?
Hrm, that's an error that would be thrown if there's a syntax issue with one of the .json files. Since the map and tileset .json files are generated in Tiled, the culprit is probably one of the sprite .json files. I can't say exactly what it is without seeing the .json file at issue for myself, but these two issues in particular are quite common when working with .json files:
1. .json files should use double quotes (") instead of single quotes (').
2. If you edit a .json file with wordpad, microsoft office or libreoffice, it will often automatically replace the double quote symbol with opening and closing quote symbol(“”), which are distinct and thus cause crashes.
I got it fixed! Your knowledge helped me pinpoint that my tileset file was saved in an xml format and not json, lol, oversight on my part.
Beginning pre-production work on a project in Renpy. After being away for 5 years, it's time to get back in the game 8)

ijffdrie
Regular
Posts: 32
Joined: Mon Apr 13, 2020 1:11 pm
itch: pink-productions
Contact:

Re: Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

#28 Post by ijffdrie »

I haven't posted in this thread for quite a while, but in that time, the development of the pink engine has not stood still. The entire engine was overhauled so that it now far, far smoother than it did before. Tilesets and sprite collections now work fine with their source images archived. A third class of event was added, one that does not interrupt the rest of the world. Control schemes were made more customizable. The ability to zoom the map unevenly on the x and y axes was added. Object scaling from Tiled was fully integrated. You can now have other characters follow the player around. And these are just a few of the changes that have been made to the engine since my last post.

That also means that it was long past time to update the tutorials that I had posted in this thread. Each of the five currently available tutorials has been revised, its instructions updated and expanded to reflect the current engine version.

User avatar
Gabmag
Regular
Posts: 75
Joined: Wed Sep 19, 2018 10:49 pm
Completed: A Date with Death, The Divine Speaker, start;again, Amelie, The Sun and the Moon
Projects: Dreambound
Organization: Two and a Half Studios
IRC Nick: Gabmag
Location: Australia
Contact:

Re: Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

#29 Post by Gabmag »

Hello!
This is super interesting and I'll definitely be playing around with it.
I wanted to ask - with the way the sprites/characters are set up, is there a way to let players customize characters (aka, skin tone, hair styles, etc.)?

Thank you!
i make games sometimes, other times i cry.

ijffdrie
Regular
Posts: 32
Joined: Mon Apr 13, 2020 1:11 pm
itch: pink-productions
Contact:

Re: Pink Engine: A framework for using Tiled-created orthogonal maps in Ren'py

#30 Post by ijffdrie »

Gabmag wrote: Tue Dec 13, 2022 12:24 pm Hello!
This is super interesting and I'll definitely be playing around with it.
I wanted to ask - with the way the sprites/characters are set up, is there a way to let players customize characters (aka, skin tone, hair styles, etc.)?

Thank you!
You could let players choose between predefined sprites, but there's currently no way to mix-and-match sprites for a greater level of customization.

Post Reply

Who is online

Users browsing this forum: No registered users