Easy Blinking for Ren’Py includes several features to make blinking as simple as possible in Ren’Py. Pick up the tool from itch.io if you haven’t already:
EasyBlink Attributes
The EasyBlink class has several attributes you can customize to suit how your blinking works.
path
The path where the eye images are found, so the image path can be put together with path + image names. It should include the substitution {img}
which will be replaced with the image name. e.g. "characters/eileen/{img}.webp"
If numbered=True
, it should also include a {num}
substitution, which will be replaced with the number of the image. e.g. "characters/eileen/{img}{num}.webp"
. If it doesn’t include the {img}
substitution, it must be a direct image path on its own.
It is also possible for the path to be any kind of Displayable, in which case the mid_eye_frames
are expected to be displayables or direct image paths, and you cannot use numbered=True
.
e.g.
path="eileen_eyes_{img}"
img
This is a string which is substituted into the path
‘s {img}
format. In most cases, this is the name of an eye attribute in a layered image e.g. happy_e
which, if given a path of eileen_eyes_{img}
would result in the final image eileen_eyes_happy_e
.
e.g.
img="sad_e"
blink_framerate
The length of time between each blink frame. You can do 1.0/60.0
if you want this to be 60fps, for example. This can also be a list of times, which should be the same length as the number of frames your blink animation has.
e.g.
blink_framerate = 0.04
e.g.
blink_framerate = [0.04, 0.02, 0.02, 0.04]
blink_repeat
How many seconds to wait before blinking again, in the format: (min time, max time)
e.g.
blink_repeat = (1.8, 4.5)
double_blink_pct
How often the character should blink twice in quick succession. 0.1 is 10%. If this is 0.0 then the character will never blink twice in a row.
e.g.
double_blink_pct = 0.1
numbered
If True, the sequence of eye images is expected to be numbered. e.g. “happy_eyes0.webp”, “happy_eyes1.webp”, “happy_eyes2.webp” etc. It will keep looking for images until it can’t find any more. Note that the path should have a {num}
substitution in it if using this.
e.g.
numbered = False
start_no_num
If True, and numbered=True
, then the first image in a numbered sequence will not have any number in it i.e. it will go: “happy_eyes.webp”, “happy_eyes1.webp”, “happy_eyes2.webp” etc.
e.g.
start_no_num = False
mid_eye_frames
The naming convention of additional eye images. Used only if numbered=False
. So, if this was ["half_closed", "closed"]
then a path of "eileen/{img}_eyes.webp"
and an img of "happy"
would look for:
“eileen/happy_eyes.webp”, “eileen/half_closed_eyes.webp”, “eileen/closed_eyes.webp”
If the path doesn’t have an {img}
substitution, then these should be direct image paths like ["eileen/half_closed_eyes.webp", "eileen/closed_eyes.webp"]
e.g.
mid_eye_frames = ["closed"]
automatic_blink_frames
If not empty, this is a list of yzoom numbers to use for automatically generated blink frames. This works by squishing the open eye frame. For this to work, the image should have all transparency below the eyes trimmed away, so that the bottom of the eye illustration is at the bottom of the image. This image will be squished down starting from the top, so the bottom always stays in the same place. It does not look good for all eye images. Looks best if the character is facing the viewer or close to it.
The eye image for the above effect looks like so:
Notice how there is no transparent space below the eyes.
e.g.
automatic_blink_frames = [0.9, 0.8]
e.g.
automatic_blink_frames = [ ]
reverse
If True, the animation will play in reverse after it’s done e.g. going from happy_eyes0 -> happy_eyes1 -> happy_eyes2 -> happy_eyes1 -> happy_eyes0
Otherwise it would go happy_eyes0 -> happy_eyes1 -> happy_eyes2 -> happy_eyes0
If you have a loop_start_frame
(see below), then only frames starting from the start_frame are reversed (i.e. it does not reverse the “startup animation” frames).
e.g.
reverse = False
loop_start_frame
This is the frame the animation should begin on when looping. For most cases this will be 0 (the first frame), but if you have 3 frames of “startup” before it starts looping, then you would set this to 3. Note that if reverse=True
, the non-looping frames won’t be reversed. So, if frames 0, 1, 2 were “startup” and frames 3, 4, 5 were the loop, then it would play out as 0, 1, 2, 3, 4, 5, 4, 3, 4, 5, 4, 3 etc.
e.g.
loop_start_frame = 0
transitions
This is the transition, or a list of such transitions, which should be used when switching between blink frames, or None
for no transition. If it’s a list of transitions, it should be the same length as the number of blink images, *or* one less than the number of blink images if you’d like reverse=True
to handle the transitions.
In the case that reverse=True
, a list of transitions is reversed as follows: Say you have frames 0, 1, 2, 3, which will be reversed to get a full looping sequence of 0, 1, 2, 3, 2, 1, 0. Say your transitions are A, B, C – there are 3 of them because there are 4 total frames before they get reversed, so you need 3 transitions. reverse=True
will set up the order to be 0 -> A -> 1 -> B -> 2 -> C -> 3 -> C -> 2 -> B -> 1 -> A -> 0, or in short, 0-A-1-B-2-C-3-C-2-B-1-A-0. You can see that the transition from 0->1 uses A, and so does the transition from 1->0.
e.g.
transitions = Dissolve(0.1)
e.g.
transitions = [Dissolve(0.2), Dissolve(0.25), Dissolve(0.2), None, None]
block_during_transition
Determines whether the game should block eye blinking while a transition is occurring. Note that this does not include transitions between eye images (as specified using transitions
above); only transitions which are used for show
statements and similar. If True, eyes will be shown in their open state only until the transition is completed.
e.g.
block_during_transition = True
sequence
sequence
provides an alternative way of providing information on transitions
, blink_framerate
, and mid_blink_frames
to EasyBlink. It takes a list, which should have information in one of the following formats:
(img, framerate, transition)
– This is a tuple with three items. The first is the image to use for this frame, the second is how long to hold on that frame for, and the third is the transition to use when transitioning to the next image.- e.g.
sequence=[("open", 0.04, Dissolve(0.1)), ("semi", 0.04, Dissolve(0.1)), ("closed", 0.04, Dissolve(0.1))]
- e.g.
(img, framerate)
– This is a tuple with two items. Like before, the first item is the image to use for this frame, and the second is how long to hold that frame for. The transition is assumed to be None.- e.g.
sequence=[("agustina_cry0", 0.1), ("agustina_cry1", 0.1), ("agustina_cry2", 0.1)]
- e.g.
img
– You can also just provide an image name, or optionally a list of numbers which will be used forautomatic_blink_frames
- e.g.
sequence=["agustina_eyes_happy", [0.85], "agustina_eyes_closed"]
- This will create a sequence where the second frame is the frame before it (“agustina_eyes_happy”) squished to 85% of its original height.
- e.g.
Note that you can mix and match these formats; for example, the following is valid:
e.g.
sequence=[("normal", 0.1, Dissolve(0.1)), ("surprised", 0.2, Dissolve(0.1)), "normal", "side", [0.85], "closed"]
If you don’t provide a framerate for a given frame, it will be taken from blink_framerate
, and if you don’t provide a transition, it will be taken from transitions
. Note that if you supply sequence
, then the value of img
will be ignored – you should include it as the first item in the sequence.
Preference Variables
Easy Blinking also takes the following persistent variable into account:
default persistent.blinking_on = True
This is a persistent variable which determines whether blinking is on or off. You can adjust it as part of an animation or accessibility toggle. e.g.
textbutton "Toggle Blink Animations" action ToggleField(persistent, "blinking_on")