Dynamically building an image

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
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.
Post Reply
Message
Author
trajano
Regular
Posts: 60
Joined: Sun Jun 16, 2019 7:59 pm
Github: trajano
Contact:

Dynamically building an image

#1 Post by trajano »

I have images defined as an animation like this

Code: Select all

image composite zoe casual body:
    "zoe casual/0269.png"
    pause 0.05
    "zoe casual/0270.png"
    pause 0.05
    "zoe casual/0271.png"
    pause 0.05
    "zoe casual/0272.png"
    pause 0.05
    "zoe casual/0273.png"
    pause 0.05
    "zoe casual/0274.png"
    pause 0.05
    ...
    repeat
I was wondering how do I build it using a python method? For example

Code: Select all

image composite zoe casual body = Anim("zoe casual", 269, 399, 0.05);
My guess is it is something like

Code: Select all

def Anim(path, range_start, range_end, pause):
    class Something(renpy.Displayable):
        ...
    return Something(path, range_start, range_end, pause);

trajano
Regular
Posts: 60
Joined: Sun Jun 16, 2019 7:59 pm
Github: trajano
Contact:

Re: Dynamically building an image

#2 Post by trajano »

Here's the solution

Code: Select all

init python:
    def ImageSequence(path, start, end, pause=0.05, reverse=False, repeat=True):
        frames = ["{:s}/{:04d}.png".format(path, x) for x in xrange(start, end + 1)]
        if (reverse):
            frames += ["{:s}/{:04d}.png".format(path, x) for x in reversed(xrange(start+1, end))]
        def seq(st, at, **kwargs):
            """
            This determines which frame from frames.
            :param st: The amount of time the displayable has been shown for (in seconds)
            :param at: The amount of time any displayable with the same tag has been shown for.
            :param kwargs: Any positional or keyword arguments supplied to DynamicDisplayable.
            :return: Displayable, pause
            """
            index = int(st / pause) % len(frames)
            d = frames[index]
            if index == len(frames) and not repeat:
                return d, None
            else:
                return d, pause
        return DynamicDisplayable(seq)
To use

Code: Select all

image zoe casual = ImageSequence("zoe casual", 269, 299)

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: Dynamically building an image

#3 Post by Remix »

An alternative approach...

Code: Select all

init python:

    def get_anim(format="", fmin=0, fmax=0, duration=0.05, trans=None):
        if "{" in format:
            poss_images = [ format.format(r) for r in range(fmin, fmax) ]
            real_images = [ k for k in renpy.list_files() if k in poss_images ]
        else:
            real_images = [ k for k in renpy.list_files() 
                            if k.startswith(format) ]
        return [ j for l in 
                 [ [k, duration, trans] for k in real_images ] 
                 for j in l ]

image zoe casual = renpy.display.anim.TransitionAnimation(
    *get_anim(
        "images/zoe casual{:04d}.png", 
        fmin=269,
        fmax=399,
        duration=0.05,
        trans=None) # it makes no sense to use transitions if each frame is so brief (could use dissolve etc if longer)
    )

label start:

    show zoe casual
Frameworks & Scriptlets:

trajano
Regular
Posts: 60
Joined: Sun Jun 16, 2019 7:59 pm
Github: trajano
Contact:

Re: Dynamically building an image

#4 Post by trajano »

@Remix nice i'll try yours out. I never noticed "TransitionAnimation" before. I do use transitions like dissolve on mine e.g

Code: Select all

show zoe casual at right with dissolve
. One slight optimization I may do is use xrange (since we're still on Python 2.x) I do notice you don't have the repeat loop though.

I can't even find any documentation about TransitionAnimation in https://www.renpy.org/doc/html/py-funct ... html#cap-T

trajano
Regular
Posts: 60
Joined: Sun Jun 16, 2019 7:59 pm
Github: trajano
Contact:

Re: Dynamically building an image

#5 Post by trajano »

Your code made me look at the Ren'py source code so I changed the implementation based on FilmStrip. Seems smoother too.

Code: Select all

    def ImageSequence(path, start, end, pause=1.0/30.0, reverse=False, repeat=True, **properties):
        frames = ["{:s}/{:04d}.png".format(path, x) for x in xrange(start, end + 1)]
        if (reverse):
            frames += ["{:s}/{:04d}.png".format(path, x) for x in reversed(xrange(start+1, end))]

        # Arguments to Animation
        args = [ ]

        for frame in frames:
            args.append(frame)
            args.append(pause)

        if not repeat:
            args.pop()

        return renpy.display.anim.Animation(*args, **properties)

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: Dynamically building an image

#6 Post by Remix »

I think all the animation stuff is hidden far away (almost to the point of deprecated) as it is rarely used sensibly...

In most cases a webm movie is going to look better and run to a much smaller filesize... image strip animation should really only be used for short sequences of small images (or to spoof a part screen movie in Android maybe)

TransitionAnimation iirc pushes its frames into SMAnimation (State Machine Animation) and tbh I do not know how well that performs even if it does sound clever.
It basically holds each frame as 3 values, image filename, duration, transition to use when showing... so you *could* (if each frame stayed for long enough) have different transitions between every frame...

On an aside ... flattening a list using python list comprehension:

Code: Select all

list_of_lists = [ (0,1), (2,3), (4,5) ]
flat_list = [ j for k in list_of_lists for j in k ]
>>> [ 0, 1, 2, 3, 4, 5 ]

# So you *could* do:
args = [ j for k in [ [f, pause] for f in frames ] for j in k ]
# rather than the for loop
Frameworks & Scriptlets:

trajano
Regular
Posts: 60
Joined: Sun Jun 16, 2019 7:59 pm
Github: trajano
Contact:

Re: Dynamically building an image

#7 Post by trajano »

WebM seems to blow up the memory profile for me when I was doing my earlier experiments. Ren'py is 32-bit so having large WebM sprites where I pick parts and zoom in / crop cause issues.

trajano
Regular
Posts: 60
Joined: Sun Jun 16, 2019 7:59 pm
Github: trajano
Contact:

Re: Dynamically building an image

#8 Post by trajano »

According to PyTom it those animations be deprecated in the future so it's better to not use them if you're starting now.

Post Reply

Who is online

Users browsing this forum: No registered users