General information
This page contains the documentation for Spirited, a Ren’Py extension.
Usage
Screen-based usage
It’s possible to add Spirited effects to a screen like any other screen
object with the keyword spirited
. Note that if more than one image is
added to the effect, each particle will use a random one.
Create a simple ‘mystical’ effect.
image mystic_particle:
"#fff"
xysize (8, 8) alpha 0.3
screen example_spirited_sample():
spirited:
image "mystic_particle"
# Go up, direction in degrees
direction (80, 100)
Make particles avoid the cursor.
image red_particle:
"#d44"
xysize (45, 45) alpha 0.7
screen example_spirited_cursor():
# Cursor-fearing spirits
spirited:
image "red_particle"
# Move slowly
speed (5, 30)
# Configure how hard particles should be pushed back
repulsor_strength 400
# Configure how far particles should be to be affected
repulsor_radius 300
Many parameters may be used to customize the particle’s behavior for a specific scene.
image rain_particle:
"#5656b8"
xysize (7, 10) alpha 0.6
screen example_spirited_rain():
# Make it rain at the center of the screen
spirited:
image "rain_particle"
# Have rain only in the middle of the screen
xpos 0.3 xsize 0.3
# Go up, direction in degrees
direction (-100, -80)
# Make particles spawn above the screen and immediately appear at 100% opacity
spawn_box (0, -100, 0, -config.screen_height)
fadein 0
# Ensure rain particles are deleted once they are below the screen
bounding_box (None, None, None, 0)
# Spawn 500 particles per seconds, limit their total count to avoid lags on smaller configurations
renewal_rate 500
maximum_pool 1300
# Make particles fall fast to emulate rain
# and die quickly so that some despawn while still on screen.
speed (500, 800)
ttl (0.3, 5)
Image-based usage
Spirited may also be used to initialize an image by creating a new object instance.
Basic ‘wind’ effect.
image particle_wind:
"#8f8"
alpha 0.3 xysize (10, 7)
image spirited simple = Spirited(
sprite_list = ["particle_wind"],
direction = (-10, 10), # Go to the right, direction is in degrees
spawn_box = (-config.screen_width, 0, 0, 0) # Start spawning at the left of the screen
)
label spirited_example_image_simple:
show spirited simple
"Carefull, wind is blowing eastward"
hide spirited simple with dissolve
return
Multiple instances may be used to produce more complex effects.
image particle_up:
"#f88"
alpha 0.7 xysize (10, 10)
image particle_down:
"#88f"
alpha 0.7 xysize (10, 10)
image spirited_up = Spirited(
sprite_list = ["particle_up"],
direction = 90, # Reds go up, direction is in degrees
)
image spirited_down = Spirited(
sprite_list = ["particle_down"],
direction = -90, # Blues go down, direction is in degrees
)
label spirited_example_image_multi:
show spirited_up
show spirited_down
"Hot air goes up, Cold air goes down"
hide spirited_up
hide spirited_down
with dissolve
return
Create advanced effects by using the guideline or the spawn_guideline. This example uses
init python:
def cursor_spawn(sprite, st):
# Relocate particles in a circle around the cursor
import math
import random
effect_radius = 50
radius = random.uniform(0, effect_radius)
angle = random.uniform(0, 2 * math.pi)
pos = renpy.get_mouse_pos()
sprite.sprite.x = math.cos(angle) * radius + pos[0]
sprite.sprite.y = math.sin(angle) * radius + pos[1]
image particle_light:
"#fff"
alpha 0.5 xysize (10, 10)
image spirited cursor = Spirited(
sprite_list = ["particle_light"],
# Go down slowly
direction = (-100, -80),
speed = (20, 60),
# Use a custom spwn rule
spawn_guideline = cursor_spawn,
# Configure how and how long the particles are visible
ttl = (0.5, 1),
fadein = 0, fadeout = 0.3,
# Configure how particles are generated
initial_count = 0, renewal_rate = 50,
)
label spirited_example_cursor_effect:
show spirited cursor
"Magic at the tip of your cursor."
hide spirited cursor with dissolve
return
Technical documentation
Spirited
This class provides rendering for mostly-linear effects such as “mystic” particles, rain, or snow.
Arguments
Tuple arguments may be written as a single value and will be implicitly expanded. Tuple arguments with two values should be interpreted as ranges with a minimum and a maximum value.
-
sprite_list
<[Displayable]> An array of images to use as sprites -
renewal_rate
<number> On average, how many sprites should be generated per second while the minimum rate is not reached -
initial_count
<number> How many sprites should be generated at the start -
minimum_pool
<number> Minimum number of sprites that must exist at the same time -
maximum_pool
<number> Maximum number of sprites that may exist at the same time -
speed
<(number, number)> How slow/fast a sprite may move -
direction
<(number, number)> Valid direction angle for a sprite (in radians) -
roll
<(number, number)> How far from its base direction line a sprite may “wobble” -
ttl
<(number, number)> How long a sprite may live (in seconds) fadein
<(number, number)> The time it should take for a sprite to reach 100% opacity as it appears (in seconds)- This time IS part of the sprite’s lifetime (see
ttl
)
- This time IS part of the sprite’s lifetime (see
fadeout
<(number, number)> The time it should take for a sprite to reach 0% opacity as it disappears (in seconds)- This time IS NOT part of the sprite’s lifetime (see
ttl
)
- This time IS NOT part of the sprite’s lifetime (see
bounding_box
<(number, number, number, number)> If != None, border limits beyond which a sprite WILL be deleted before its lifespan expires- The tuple’s values affect the borders in the following order: (left, top, right, bottom)
- Positive values move the border right or down, negative values move it left or up
- The calculation is performed relative to the top left corner of the sprites
spawn_box
<(number, number, number, number)> The border limits within which a particle may be created- The tuple’s values affect the borders in the following order: (left, top, right, bottom)
- Positive values move the border right or down, negative values move it left or up
- The calculation is performed relative to the top left corner of the particle sprites
-
repulsor_strength
<number> How fast sprites should run away from the mouse’ cursor -
repulsor_radius
<number> How far the mouse’s position affects sprites -
repulsor_hardness
<number> How strong the repulsor is at the max distance compared to on the cursor (as a multiplicator) repulsor_mode
<number>- 0 to have a simple repulsor
- 1 to have a tornado around the cursor
- Other values are unsupported
-
alpha_levels
<int> How many transparency levels to use when fading a sprite in/out guideline
<function> A custom function that takes five parameters and handles the displacement of a sprite:- param1: A SpiritedSpriteInfo instance. Update param1.sprite.x and param1.sprite.y to set its position.
- param2: The time ellapsed since the Spirited displayable was first shown.
- param3: The time ellapsed since the last update in milliseconds.
- param4: A tuple that contains the displacement calculated based on Spirited’s parameters. This displacement must be part of the tuple returned by the function to be applied to the sprite.
- param5: A tuple that contains the displacement that would be caused by the mouse’s cursor’s position. This displacement must be part of the tuple returned by the function to be applied to the sprite.
spawn_guideline
<function> A custom function called as soon as a new sprite is created- param1: A SpiritedSpriteInfo instance.
- param2: The time ellapsed since the Spirited displayable was first shown.
SpiritedSpriteInfo
This class is a container for Ren’Py-native sprite objects.
This should only be necessary when creating a custom guideline.
Attributes
Attributes with “(from attribute
)” are calculated based on attributes
provided to Spirited
at its instanciation. Need to add attributes for
your guideline ? Prefix gl_
or guideline_
to their name. We will
never use such attribute names when updating SpiritedSpriteInfo.
sprite
The Ren’Py particle object. Its x and y attributes must be updated to make particles movecycle
In which life phase the particle is0
Particle is appearing1
Particle is at 100% opacity2
Particle is disappearing
speed
(fromspeed
) How fast the sprite moves (in pixel/second)direction
(fromdirection
) The sprite’s direction angle (in radians)roll
(fromroll
) How far from the direction’s line the sprite may roll (in pixels)opacity
The current particle opacity level if it’s appearing or disappearingduration
(fromttl
) How long this particle will stay before disappearingbirth_time
The time this particle was birthed (relative to Spirited’s time)fadein
(fromfadein
) The time the particle takes to become visiblefadeout
(fromfadeout
) The time the particle takes to become invisible and dieroll_offset
Internal variable used by Spirited to ensure that particles rolling are not syncedrid
Internal variable used by Spirited to track which image should be used
Want to do more ?
The following technical demo runs in Ren’Py. Keep in mind that dynamically changing Spirited’s parameters as is done in the demo requires extensive knowledge of its inner working at the moment. If you’d like the extension to provide the ability to do this more easily with Ren’Py-compatible patterns, let us know by opening an issue on GitHub so we can try to provide this feature if there is enough interest in it.
Need technical assistance or need something specific to be added to the extension ?
- Open an issue on GitHub
- Or contact me on twitch
- Or contact me by mail (may take a while to answer)