How to ATL falling snow?
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
-
- Regular
- Posts: 104
- Joined: Sun Dec 13, 2015 2:06 pm
- Projects: Detroit.exe
- Discord: Happiness+#1168
- Contact:
How to ATL falling snow?
I have the sprite, but how do I animate snowflakes falling down until the scene ends?
Re: How to ATL falling snow?
You can look for SnowBlossom (without ATL), I don't really like how it's made but it works
Re: How to ATL falling snow?
These are the two decent ways we have at the moment, one is guided manually by recalculating positions and is (I think) the original SnowBlossom recoded by Nyaatrap. The other is guided by ATL function which can be provided as one of the arguments to the UDD, that simplifies the code a bit and should allow faster modifications if desired:
Code: Select all
# Image definitions for snow particles:
image solid_snow_small = Transform(Solid("FFF", xysize=(3, 3)), rotate=45)
image solid_snow_normal = Transform(Solid("FFF", xysize=(5, 5)), rotate=45)
image solid_snow_large = Transform(Solid("FFF", xysize=(7, 7)), rotate=45)
# Definition for SnowBlossom2 particles by Nyaatrap (or at least used in his cool dress-up demo):
image snow = Fixed(
SnowBlossom2("solid_snow_large", 50, xspeed=(20, 50), yspeed=(100, 200), start=100, fluttering=10),
SnowBlossom2("solid_snow_normal", 75, xspeed=(15, 35), yspeed=(75, 150), start=100, fluttering=7),
SnowBlossom2("solid_snow_small", 100, xspeed=(10, 25), yspeed=(50, 100), start=100, fluttering=5))
# Definition for Snowing UDD:
image snowing = Fixed(
Snowing("solid_snow_large", speed=(5.0, 5.8), slow_start=(7, (0.6, 0.9))),
Snowing("solid_snow_normal", speed=(4.8, 5.2), slow_start=(7, (0.8, 1.2))),
Snowing("solid_snow_small", speed=(4.3, 4.7), slow_start=(5, (0.5, 0.7))))
# This bit is required for the SnowBlossom2 effect by Nyaatrap (or at least used in his cool dress-up demo)::
init -100 python:
import random, math
class SnowBlossomFactory2(renpy.python.NoRollback):
rotate = False
def __setstate__(self, state):
self.start = 0
vars(self).update(state)
self.init()
def __init__(self, image, count, xspeed, yspeed, border, start, fluttering, flutteringspeed, fast, rotate=False):
self.image = renpy.easy.displayable(image)
self.count = count
self.xspeed = xspeed
self.yspeed = yspeed
self.border = border
self.start = start
self.fluttering = fluttering
self.flutteringspeed = flutteringspeed
self.fast = fast
self.rotate = rotate
self.init()
def init(self):
self.starts = [ random.uniform(0, self.start) for _i in xrange(0, self.count) ] # W0201
self.starts.append(self.start)
self.starts.sort()
def create(self, particles, st):
def ranged(n):
if isinstance(n, tuple):
return random.uniform(n[0], n[1])
else:
return n
if not particles and self.fast:
rv = [ ]
for _i in xrange(0, self.count):
rv.append(SnowBlossomParticle(self.image,
ranged(self.xspeed),
ranged(self.yspeed),
self.border,
st,
self.fluttering,
self.flutteringspeed,
random.uniform(0, 100),
fast=True,
rotate=self.rotate))
return rv
if particles is None or len(particles) < self.count:
# Check to see if we have a particle ready to start. If not,
# don't start it.
if particles and st < self.starts[len(particles)]:
return None
return [ SnowBlossomParticle2(self.image,
ranged(self.xspeed),
ranged(self.yspeed),
self.border,
st,
self.fluttering,
self.flutteringspeed,
random.uniform(0, 100),
fast=False,
rotate=self.rotate) ]
def predict(self):
return [ self.image ]
class SnowBlossomParticle2(renpy.python.NoRollback):
def __init__(self, image, xspeed, yspeed, border, start, fluttering, flutteringspeed, offset, fast, rotate):
# safety.
if yspeed == 0:
yspeed = 1
self.image = image
self.xspeed = xspeed
self.yspeed = yspeed
self.border = border
self.start = start
self.fluttering = fluttering
self.flutteringspeed = flutteringspeed
self.offset = offset
self.rotate = rotate
self.angle = 0
if not rotate:
sh = renpy.config.screen_height
sw = renpy.config.screen_width
else:
sw = renpy.config.screen_height
sh = renpy.config.screen_width
if self.yspeed > 0:
self.ystart = -border
else:
self.ystart = sh + border
travel_time = (2.0 * border + sh) / abs(yspeed)
xdist = xspeed * travel_time
x0 = min(-xdist, 0)
x1 = max(sw + xdist, sw)
self.xstart = random.uniform(x0, x1)
if fast:
self.ystart = random.uniform(-border, sh + border)
self.xstart = random.uniform(0, sw)
def update(self, st):
to = st - self.start
self.angle += self.flutteringspeed
xpos = self.xstart + to * self.xspeed + math.sin(self.angle)*self.fluttering
ypos = self.ystart + to * self.yspeed
if not self.rotate:
sh = renpy.config.screen_height
else:
sh = renpy.config.screen_width
if ypos > sh + self.border:
return None
if ypos < -self.border:
return None
if not self.rotate:
return int(xpos), int(ypos), to + self.offset, self.image
else:
return int(ypos), int(xpos), to + self.offset, self.image
def SnowBlossom2(d,
count=10,
border=50,
xspeed=(20, 50),
yspeed=(100, 200),
start=0,
fluttering=0,
flutteringspeed=0.01,
fast=False,
horizontal=False):
"""
:doc: sprites_extra
The snowblossom effect moves multiple instances of a sprite up,
down, left or right on the screen. When a sprite leaves the screen, it
is returned to the start.
`d`
The displayable to use for the sprites.
`border`
The size of the border of the screen. The sprite is considered to be
on the screen until it clears the border, ensuring that sprites do
not disappear abruptly.
`xspeed`, `yspeed`
The speed at which the sprites move, in the horizontal and vertical
directions, respectively. These can be a single number or a tuple of
two numbers. In the latter case, each particle is assigned a random
speed between the two numbers. The speeds can be positive or negative,
as long as the second number in a tuple is larger than the first.
`start`
The delay, in seconds, before each particle is added. This can be
allows the particles to start at the top of the screen, while not
looking like a "wave" effect.
'fluttering'
The width of fluttering in pixel.
'flutteringspeed'
The speed of fluttering.
`fast`
If true, particles start in the center of the screen, rather than
only at the edges.
`horizontal`
If true, particles appear on the left or right side of the screen,
rather than the top or bottom.
"""
# If going horizontal, swap the xspeed and the yspeed.
if horizontal:
xspeed, yspeed = yspeed, xspeed
return Particles(SnowBlossomFactory2(image=d,
count=count,
border=border,
xspeed=xspeed,
yspeed=yspeed,
start=start,
fluttering=fluttering,
flutteringspeed=flutteringspeed,
fast=fast,
rotate=horizontal))
# This bit is required for the Snowing effect:
transform particle(d, delay, startpos, endpos, speed):
subpixel True
pause delay
d
pos startpos
linear speed pos endpos
init python:
class Snowing(renpy.Displayable, NoRollback):
def __init__(self, d, interval=(0.2, 0.3), start_pos=((-200, config.screen_width), 0), end_pos=({"offset": (100, 200)}, config.screen_height), speed=4.0, slow_start=False, transform=particle, **kwargs):
"""Creates a 'stream' of displayable...
@params:
-d: Anything that can shown in Ren'Py.
-interval: Time to wait before adding a new particle. Expects a tuple with two floats.
-start_pos: x, y starting positions. This expects a tuple of two elements containing either a tuple or an int each.
-end_pos: x, y end positions. Same rule as above but in addition a dict can be used, in such a case:
*empty dict will result in straight movement
*a dict containing an "offset" key will offset the ending position by the value. Expects an int or a tuple of two ints. Default is (100, 200) and attempts to simulate a slight wind to the right (east).
-speed: A time before particle eaches the end_pos. Expects float or a tuple of floats.
-slow_start: If not the default False, this will expect a tuple of (time, (new_interval_min, new_interval_max)):
*This will override the normal interval when the Displayable is first shown for the "time" seconds with the new_interval.
-transform: ATL function to use for the particles.
The idea behind the design is to enable large amounts of the same displayable guided by instructions from a specified ATL function to
reach end_pos from start_pos in speed amount of seconds (randomized if needs be). For any rotation, "fluff" or any additional effects different ATL funcs with parallel can be used to achieve the desired effect.
"""
super(Snowing, self).__init__(**kwargs)
self.d = renpy.easy.displayable(d)
self.interval = interval
self.start_pos = start_pos
self.end_pos = end_pos
self.speed = speed
self.slow_start = slow_start
self.transform = transform
self.next = 0
self.shown = {}
def render(self, width, height, st, at):
rp = store.renpy
if not st:
self.next = 0
self.shown = {}
render = rp.Render(width, height)
if self.next <= st:
speed = rp.random.uniform(self.speed[0], self.speed[1]) if isinstance(self.speed, (list, tuple)) else self.speed
posx = self.start_pos[0]
posx = rp.random.randint(posx[0], posx[1]) if isinstance(posx, (list, tuple)) else posx
posy = self.start_pos[1]
posy = rp.random.randint(posy[0], posy[1]) if isinstance(posy, (list, tuple)) else posy
endposx = self.end_pos[0]
if isinstance(endposx, dict):
offset = endposx.get("offset", 0)
endposx = posx + rp.random.randint(offset[0], offset[1]) if isinstance(offset, (list, tuple)) else offset
else:
endposx = rp.random.randint(endposx[0], endposx[1]) if isinstance(endposx, (list, tuple)) else endposx
endposy = self.end_pos[1]
if isinstance(endposy, dict):
offset = endposy.get("offset", 0)
endposy = posy + randint.randint(offset[0], offset[1]) if isinstance(offset, (list, tuple)) else offset
else:
endposy = rp.random.randint(endposy[0], endposy[1]) if isinstance(endposy, (list, tuple)) else endposy
self.shown[st + speed] = self.transform(self.d, st, (posx, posy), (endposx, endposy), speed)
if self.slow_start and st < self.slow_start[0]:
interval = self.slow_start[1]
self.next = st + rp.random.uniform(interval[0], interval[1])
else:
self.next = st + rp.random.uniform(self.interval[0], self.interval[1])
for d in self.shown.keys():
if d < st:
del(self.shown[d])
else:
d = self.shown[d]
render.blit(d.render(width, height, st, at), (d.xpos, d.ypos))
rp.redraw(self, 0)
return render
def visit(self):
return [self.d]
label start:
scene black
menu:
"Pick one"
"Test SnowBlossom":
show snow
"Test Snowing":
show snowing
pause
-
- Regular
- Posts: 104
- Joined: Sun Dec 13, 2015 2:06 pm
- Projects: Detroit.exe
- Discord: Happiness+#1168
- Contact:
Re: How to ATL falling snow?
What am I doing wrong here?
I want to use my snowflake sprites, but what am I doing wrong here?
Code: Select all
I'm sorry, but errors were detected in your script. Please correct the
errors listed below, and try again.
File "game/script.rpy", line 4: invalid syntax
("snowflake1.png", xysize= (3, 3), rotate=45)
^
File "game/script.rpy", line 5: invalid syntax
("snowflake2.png", xysize= (5, 5), rotate=45)
^
File "game/script.rpy", line 6: invalid syntax
("snowflake3.png", xysize= (7, 7), rotate=45)
^
Ren'Py Version: Ren'Py 6.99.8.949
Who is online
Users browsing this forum: Yone28