blogs by Gio

Positioning things in Ren’py

  • Posted in ⚙ dev

As is common in Python, the mechanical process of displaying something on screen in Ren’py is at once easy to execute and deceptively complicated to execute correctly.

The Ren’py documentation does a fine job of defining the specifications of position properties, but intuitively understanding how to use those properties can still be hard because it doesn’t include much in the way of examples or elaboration, so here are some of those.

Your basic properties

These names come directly from atl transform on the documentation. Note that these are generally parallel with the style properties of the same names.

pos - tuple of (position, position)

The position of the anchor relative to the top-left corner of the containing area (usually the whole screen).

pos is a coordinate point in the form of (position, position). This will look like (0, 0) or (600, 300) or (0.5, 1.0) or even (-20, 0.5)

The first coordinate is the x coordinate (horizontal) and the second is the y coordinate (vertical). You can set these individually with xpos and ypos, which each take a single position.

Note that pos takes a position rather than a “number”. positions in Ren’py come in two forms, and have two different uses.

If a position is an integer (a number without a decimal point) it’s a number of pixels. (100, 200) is 100 pixels from the left, 200 pixels from the top.

If a position is a float (a number with a decimal point), it’s treated as a percentage. 1.0 is 100%, 0.0 is 0%, 0.5 is 50%. In pos, this percentage is of the total screen, so (0.5, 1.0) is 50% from the left, 100% from the top.

Note that 1.0 and 1 are treated differently! It’s critical that you understand this.

You can mix and match position types. Here’s (0.5, 20):

anchor - tuple of (position, position)

The position of the anchor relative to the displayable image itself.

anchor is a coordinate point in the form of (position, position), like pos. Again, xanchor and yanchor manipulate the two numbers separately.

For this example, let’s say we have a simple rectangle with a pos of (0.5, 0.5):

This is the default, with anchor = (0, 0). The anchor (still the red dot) is at pos = (0.5, 0.5), the displayable (the grey rectangle) is positioned with its anchor at the rectangle’s top-left anchor = (0, 0)

Here’s anchor = (0.5, 1.0):

Now it’s completely centered, both relative to the screen and itself.

A nice baseline for a visual novel might be pos = (0.5, 1.0), anchor = (0.5, 1.0), which positions the entire displayable at the bottom center:

Since yanchor = 1.0, the rectangle starts at the anchor and “goes up”, instead of “going down”.

offset - tuple of (int, int)

The last real value! offset is a simple one, it just nudges the displayable by the given number of pixels. And they’re just integers this time, no need to worry about percentages. Again, xoffset and yoffset manipulate the two components separately.

Here’s a nice little offset figure:

pos = (0.5, 0.5)
anchor = (0, 0)
xoffset = 50

The shortcut ones

Like I said, that was the last real position property! The rest are all shorthand for changing those three.

  • xcenter = x sets xpos to x and xalign to 0.5
  • ycenter = y sets ypos to y and yalign to 0.5
  • align = (x, y) sets both pos and anchor to (x, y)

You may have noticed an obvious pitfall here: there are a lot of different ways to display exactly the same image! Changing anchor by a few pixels looks the same as changing offset, but animates totally differently.

That’s why it’s critical to keep the way you animate things consistent, and think through animations carefully rather than just bashing your code with a hammer until it produces an image that looks good. If you don’t, you’ll find it very easy to write yourself into a corner where animations don’t work correctly and you can’t get ease or other interpolations to do what you want, because you’ve accidently spread a single design decision across three sets of numbers.

Here are my design recommendations, I suppose:

  • Keep a default align for characters of (0.5, 1.0)
  • Adjust xpos as needed to move them around the screen.
  • Have a default offset of (0, 20) so there’s room for the character to move up a few pixels
  • Just use offset for animations (jumping up and down, sitting, general fx). You should always be able to clamp offset back to near-zero and still have the character in the right area.
  • If your characters are standing, you probably don’t ever need to touch ypos or yanchor!