Skip to content

Animation#

Student Transfer extends the animation templates provided by Ren'Py with some custom animations, which are documented here.

Transitions with Custom Delays#

The default transitions do not allow one to easily change their respective durations. Most prominently this occurs when hiding a character, i.e. hide john with easeoutright. In this case, the transition will always take 0.5 seconds to execute.

Student Transfer extends these transitions such that they can be given a user-defined delay like so:

1
hide <target_character:character> with st_<transition_name>(<delay:float>)
1
2
3
4
5
6
show john a_0 at center

"I'm really just stalling here."

# Will play the 'easeoutright' transition over 3.5 seconds
hide john with st_easeoutright(3.5)

The delay-capable version of the respective original transition can be accessed by adding the prefix st_ to the original name, i.e. easeouttop becomes st_easeouttop.
Note that the Student Transfer versions of these commands must be called with parenthesis, otherwise they will crash the game. Do not do this: st_easeouttop. Always do this: st_easeouttop(0.5)

These transitions are available:

  • st_ease
  • st_easeinbottom
  • st_easeinleft
  • st_easeinright
  • st_easeintop
  • st_easeoutbottom
  • st_easeoutleft
  • st_easeoutright
  • st_easeouttop

Showing the same image multiple times#

Sometimes it might become necessary to show the same image on the screen multiple times, be it for characters, backgrounds, CG's or other image assets. This can be achieved via a construct inherent to Ren'Py itself: as.
This keyword can be used in conjunction with show statements to rename an existing sprite to something different. Due to the way Ren'Py works, an image with a specific name can only be on-screen once during a specific timeframe. If that name is changed to something that is not used however, it is possible to show it multiple times. Let's see how this works with the help of a simple example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Show the original image at the center of the screen
show pillow at center

# We want to show a second pillow at left-hand-side of the screen,
# so let's try the naive approach
show pillow at left

# The pillow has changed position, but the change has affected
# the original image. Let's now accomplish this with the "as" keyword

# First, let's restore our original setup
show pillow at center

# Now, let's add a second pillow, based on the same original image
show pillow at left as pillow2

pause 1.0

# We now have two pillow images that we can move around independently
# Take care to also hide both of them when you want to get rid of them
hide pillow with easeoutright
hide pillow2 with easeoutleft

This technique also works the exact same way for characters and all other images you can display in Ren'Py. If you wanted to show john twice, for example, you could do it like this:

1
2
3
4
show john a_0 at right, faceleft
show john a_0 at left, faceright as john2

john "Hey!"

Do note that the new name you give the image has no bearing on the characters who speak the dialogue, so you will not be able to say john2 "Hey yourself!" as that will produce an error.

Skip Proofing your Animations#

Something that you might run into while doing more complex animations is that skipping or quickly clicking through the script will lead to your characters ending up at the wrong positions, half-transparent, weirdly rotated or warped into the hideous form of an eldritch horror from another dimension. These things are all results of a lack of skip proofing.
Ren'Py tries its best to predict where sprites will end up, but if the player "cancels" an animation by clicking past it before it has finished (or even worse, skips past it at ludicrous speeds), sometimes the animation just stops in the middle of whatever it was doing. Take for example this small snippet:

1
2
3
show john a_0 at center:
    alpha 0.0
    ease 3.0 xpos 0.9 alpha 1.0

While this would normally move john towards the right edge of the screen over three seconds time while fading him in, in some situations it might stop anywhere in between. This means if you're unlucky, john could end up anywhere between his original positions and xpos 0.9 and half-transparent. There are several tricks we can employ to help Ren'Py along and to ensure that after our animations have finished, the characters end up where and how they belong.

The first trick is to explicitly tell Ren'Py what the state of the image should be after the animation has finished. This means that we hard-code all final values for all statements that are animated in the same ATL block. Sounds confusing? Let's take the above example:

1
2
3
4
5
show john a_0 at center:
    alpha 0.0
    ease 3.0 xpos 0.9 alpha 1.0
    xpos 0.9
    alpha 1.0

Inspecting this snippet we can see that we added the final values as non-animated properties after the animation has finished. This helps Ren'Py in knowing where things should end up while skipping as it glances over animations but tries really hard to obey fixed, hard-coded values.

However, this does not always work. The next trick is a bit more of a blunt-force hammer approach, but it also works 100% of the time so we're not complaining. The basic idea is to build in "animation checkpoints" after (or even during) complex animation segments which force the characters into the correct positions. We'll illustrate this with the above example, though of course in actuality the setups will be more complex. However, the same concepts apply.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
show john a_0 at center:
    alpha 0.0
    ease 3.0 xpos 0.9 alpha 1.0
    xpos 0.9
    alpha 1.0

"I moved to the right at an incredibly slow pace."

# After the dialogue has played, we hard-code the position
# and the alpha value.
# Even if the player skips past the original animation,
# they will end up with the same result as soon as they
# hit this line.
show john a_0 at center:
    xpos 0.9
    alpha 1.0

Creating Custom Transitions in Scenarios#

It is possible to add custom image-based transitions using the direct path feature to directly refer to an image loaded from a scenario:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
init +100 python:
    def MyCustomTransition(image, time=1.0, reverse=False):
        return ImageDissolve(im.Tile(image), time, reverse=reverse)
    my_custom_transition = MyCustomTransition(direct_path("example_asset arrow"))

label day1:
    scene bg school exterior day
    with my_custom_transition

    "This is a test sentence."