Question about syncing up two animated sequences

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
Alem
Regular
Posts: 38
Joined: Wed Mar 15, 2017 7:53 am
Contact:

Question about syncing up two animated sequences

#1 Post by Alem »

Hello! I have a question about synching two animated sprites. The idea is to wait for the first animated sequence to end properly, signal that it reached the ending somehow, and trigger the second part of it. To help visualize it, think of a palm tree under a light breeze on the first animated sequence, and the second one it’s under a storm.

The code right now looks something like this:

Code: Select all

show palm_calm

“What a nice day!”

show palm_storm

“Oh, no! It’s a storm!”
The problem is, I don’t know how long the player will be on the first text block and can’t sync up the second animated sequence. It works great if timed properly since the starting frames of both animations are the same. If the change is timed wrong, there’s a visual jerk to the starting point.

Just to be clear, animated sequences look like this:

Code: Select all

image palm_calm:

    “palm_calm1.png” with Dissolve(0.2)

    pause 0.3

    “palm_calm2.png” with Dissolve(0.2)

    pause 0.3

    repeat
The real sequence is longer, but the code is the same for all other frames.

I’m not good with the code and looking up a solution in Renpy’s manuals, but didn’t find a way to sync up the transactions between two animated sequences. Is there such an option at all? I tried using boolean switches with $ sync_flag = True before the last pause, yet I get syntax errors and am not really sure what to do next.

Any help with be greatly appreciated! Thanks!

User avatar
Ocelot
Lemma-Class Veteran
Posts: 2384
Joined: Tue Aug 23, 2016 10:35 am
Github: MiiNiPaa
Discord: MiiNiPaa#4384
Contact:

Re: Question about syncing up two animated sequences

#2 Post by Ocelot »

You can use animation statement there.

Code: Select all

image palm calm: # it is important that replaced images shared the same tag
    animation
    "palm_calm1.png" with Dissolve(0.2)
    pause 0.3
    "palm_calm2.png" with Dissolve(0.2)
    pause 0.3
    repeat

image palm storm: # another thing to look for is duration of both animations
    animation
    "palm_storm1.png" with Dissolve(0.2)
    pause 0.3
    "palm_storm2.png" with Dissolve(0.2)
    pause 0.3
    repeat

# . . .
show palm calm
"What a nice day!"
show palm storm # Should be displayed on the same step that original image was
"Oh, no! It’s a storm!"
< < insert Rick Cook quote here > >

Alem
Regular
Posts: 38
Joined: Wed Mar 15, 2017 7:53 am
Contact:

Re: Question about syncing up two animated sequences

#3 Post by Alem »

Ocelot wrote: Mon Jan 17, 2022 8:42 am You can use animation statement there.
Thanks for the idea and the image tag advice! Sadly, I tested it out and the visual jerk is still there. As I understand it from the manual's example, this helps with switching images before moving the image. My animated sequence remains stationary between both options and retains the same coordinates. Or did I just misunderstand something?

The whole animation is in the frames labeled from 0 to 15 both for the calm and stormy versions. The visual jerk comes from switching to the second animation in the non-zero frame. This happens because all frames except the zero are different between themselves in both animations. That's why I want to start the "stormy" animation in the zero frame position.

User avatar
plastiekk
Regular
Posts: 111
Joined: Wed Sep 29, 2021 4:08 am
Contact:

Re: Question about syncing up two animated sequences

#4 Post by plastiekk »

Alem wrote: Mon Jan 17, 2022 9:29 am
The whole animation is in the frames labeled from 0 to 15 both for the calm and stormy versions. The visual jerk comes from switching to the second animation in the non-zero frame. This happens because all frames except the zero are different between themselves in both animations. That's why I want to start the "stormy" animation in the zero frame position.

Either this is not possible or you have to find out where the animation is and wait (maybe with a function) until it is finished. Normally you use boleans/flags, True/False for this. Since I am new to Renpy and Python, I can only point you in this direction.
Why on earth did I put the bread in the fridge?

User avatar
plastiekk
Regular
Posts: 111
Joined: Wed Sep 29, 2021 4:08 am
Contact:

Re: Question about syncing up two animated sequences

#5 Post by plastiekk »

Alem wrote: Mon Jan 17, 2022 9:29 am That's why I want to start the "stormy" animation in the zero frame position.
Hi Alem,
I couldn't get the idea (of synchronizing) out of my head and since I found a little time today, I tried it this way.

+ pro
- it is not necessary to define images, because we only have to change a few variables
- can be used with any animated sequences

+ cons
- there will be a small delay before the actual synchronization
(due to the defined timer) and unfortunately I have no idea how to fix it

I add an example as an attachment.

Code: Select all

#######################################################
# newbish animation syncer                            #
#                                                     #
# - plastiekk                                         #
#######################################################

##################
# variables
# change them here and/or at any place in your script

 
default start_seq = 1               # start number of the image or sprite
default end_seq = 3                 # last image. In your case it should be 15  (tested with 3 only)
                                    
default seq_timer = 0.5             # change this to slow down or speed up the animation sequence
                                    
default x_pos = 0.5                 # xpos of the image
default y_pos = 0.5                 # ypos of the image                   
default image_path = "images/"      # the path to your sequences like "images/seq1/*" etc.
default image_seq =  "palm_calm"    # image name of the sequence
default image_ext = ".jpg"          # the format of the picture e.g. ".png .jpg"
                                    # make sure to name your images e.g: palm_calm1.png, palm_calm2.png...


####################
# screen vars 

default seq_count = start_seq        # the seq. counter used in the sequencer screen
default seq_image = ""               # our image to display

####################
# function to play animation til end_seq

init python:        
    def my_sequencer(n):
        global start_seq, end_sec, seq_timer, image_path, image_seq, image_ext, seq_event, seq_count, seq_image, x_pos, y_pos
        
        seq_count += n                                               # next image
        if seq_count > end_seq:                                      # end reached? -> reset
            seq_count = start_seq                                    # counter
           
        seq_c_string = str(seq_count)                                # assemble image path
        seq_image = image_path+image_seq+seq_c_string+image_ext      # and name
        renpy.hide_screen("my_animation")                            # hide normal animation screen
        renpy.show_screen("my_animation_end",x_pos,y_pos)            # show sync screen
        renpy.pause (seq_timer)                                      # pause
        if seq_count == end_seq:                                     # end of animation? -> then
            renpy.hide_screen("my_animation_end")                    # hide screen and return
            return
        my_sequencer(1)                                              # next image (loop)
      
####################
# shown by function my_sequencer()      
screen my_animation_end(x_pos =0,y_pos =0):
        modal True                                                   # player can't click
        add "[seq_image]" xalign x_pos yalign y_pos                  # add a transform here (optional)
        text "[seq_image] syncing..."                                # debug, comment this line out

####################
# normal animation        
screen my_animation(x_pos =0,y_pos =0):      
        
        if seq_count > end_seq:                                      # last image reached?
          $ seq_count = start_seq                                    # then set to start_seq
        $ seq_c_string = str(seq_count)                              # integer seq_count to string
        $ seq_image = image_path+image_seq+seq_c_string+image_ext    # the image name
        add "[seq_image]" xalign x_pos yalign y_pos                  # add a transform here (optional)
        text "[seq_image]"                                           # debug, comment this line out
        timer seq_timer repeat True action [                         # wait seq_timer (seconds)
        SetVariable('seq_count', seq_count + 1),                     # next image
        Show('my_animation', x_pos =x_pos, y_pos =y_pos)             # redraw screen
        ] 
        
####################        
label anim_sync:
    
# if you have a large amount of images you maybe want Renpy to predict them                                    
    $ image_path_predict=image_path+"*.*"
    $ renpy.start_predict(image_path_predict)
 
    $ image_seq = "palm_calm"                                        # image name
    $ seq_count = start_seq                                          # set counter to start (usualy 1)
    show screen my_animation(x_pos,y_pos)                            # show the normal screen
    "What a nice day."                                               # and say something
    $ my_sequencer(0)                                                # player clicked and we wait  
                                                                     # for sync
                                                                     
    $ image_seq = "palm_storm"                                       # name of new image sequence
    $ seq_count = start_seq                                          # set counter to start
    show screen my_animation (y_pos,y_pos)                           # show normal animation
    "Oh no a storm!"                                                 # say again something
    $ my_sequencer(0)                                                # wait for sync
    "The storm ended."
    return
    
Attachments
game.zip
(151.61 KiB) Downloaded 22 times
Why on earth did I put the bread in the fridge?

Alem
Regular
Posts: 38
Joined: Wed Mar 15, 2017 7:53 am
Contact:

Re: Question about syncing up two animated sequences

#6 Post by Alem »

plastiekk wrote: Sat Jan 22, 2022 9:08 am
Alem wrote: Mon Jan 17, 2022 9:29 am That's why I want to start the "stormy" animation in the zero frame position.
Hi Alem,
I couldn't get the idea (of synchronizing) out of my head and since I found a little time today, I tried it this way.

+ pro
- it is not necessary to define images, because we only have to change a few variables
- can be used with any animated sequences

+ cons
- there will be a small delay before the actual synchronization
(due to the defined timer) and unfortunately I have no idea how to fix it
Whoa, thank you very much! I'll try it out tomorrow and post the feedback.

Alem
Regular
Posts: 38
Joined: Wed Mar 15, 2017 7:53 am
Contact:

Re: Question about syncing up two animated sequences

#7 Post by Alem »

plastiekk wrote: Sat Jan 22, 2022 9:08 am
Alem wrote: Mon Jan 17, 2022 9:29 am That's why I want to start the "stormy" animation in the zero frame position.
Hi Alem,
I couldn't get the idea (of synchronizing) out of my head and since I found a little time today, I tried it this way.

+ pro
- it is not necessary to define images, because we only have to change a few variables
- can be used with any animated sequences

+ cons
- there will be a small delay before the actual synchronization
(due to the defined timer) and unfortunately I have no idea how to fix it
Hello! I'm back with the feedback. In short, it's awesome! I've gone on a testing spree and your code works great with all animations I could think of. After testing my own animation, I've split a professional gif into 23 separate frames and your code managed to sync between two variations of the same gif almost perfectly. There was a bit of a synching lag, but fiddling with the delay changed it to almost unperceptive.

The same goes for the lower frame amount animations. The only hiccup I had with low frame amount animation. And that's not a problem with your code, it works just as well in this situation. The problem is, the frames are added without any transitions like a dissolve, and due to the low amount of frames, it's easy to see separate frames.

It's more of nitpicking since you nailed the main goal of animating in a convenient way, but I think your solution would be perfect if it could optionally accept a transformation like a dissolve with its own timer. This way, your code could truly tackle any animation.

I tried to add the dissolve effect but got rather strange results with this code added to the end of your my_animation_end and my_animation functions:

Code: Select all

on "add" action With(renpy.transition(dissolve))
The dissolve works, but it doesn't accept any timers like the show command does with Dissolve(.4). I just get errors about invalid syntaxis, so looks like I'm doing this wrong. As I understood the manual, I need to define a different kind of dissolve and state the timer there. Sadly, doing this with

Code: Select all

define my_dis = { "master" : Dissolve(0.3) }
And swapping dissolve with my_dis does nothing for me. I don't get any errors, the code just ignores the line with my custom transition. Sorry, I'm not very bright with the code ><

The other issue is that now I need to click repeatedly to advance the text and begin syncing process while the first animation plays. Commenting my line out brings the responsiveness back to a single click. Am I doing this wrong too or the code is simply not geared towards additional effects like dissolve?

Either way, thanks a lot! Even without a dissolve, your code makes complex animations possible, and to me, that's a huge boon.

User avatar
plastiekk
Regular
Posts: 111
Joined: Wed Sep 29, 2021 4:08 am
Contact:

Re: Question about syncing up two animated sequences

#8 Post by plastiekk »

Alem wrote: Sun Jan 23, 2022 5:46 am The other issue is that now I need to click repeatedly to advance the text and begin syncing process while the first animation plays. Commenting my line out brings the responsiveness back to a single click. Am I doing this wrong too or the code is simply not geared towards additional effects like dissolve?
Hi Alem,
sorry for the late reply, I am very busy at the moment. The transition you mentioned should be easy to attach with a transform, or so I thought.
Far from it. ^.^
i also tried it with a transform my_dissolve: alpha etc, but it is only triggered 1x, that is when the screen is called the first time and totally ignored after that.
An append in the timer -> Action -> With(Dissolve(0.5)) achieved the result you describe.
The Dissolve effect seems to be pushed onto a stack or added to a list, so for example I had to click 3x to interrupt the normal animation!?

The problem seems more complex than thought. I'll look at it again this weekend and post here if successful. (Maybe my approach (in the script) is also completely wrong).
-> Learning Renpy by doing is not a crime :)
Why on earth did I put the bread in the fridge?

Alem
Regular
Posts: 38
Joined: Wed Mar 15, 2017 7:53 am
Contact:

Re: Question about syncing up two animated sequences

#9 Post by Alem »

plastiekk wrote: Wed Jan 26, 2022 11:37 am
Alem wrote: Sun Jan 23, 2022 5:46 am The other issue is that now I need to click repeatedly to advance the text and begin syncing process while the first animation plays. Commenting my line out brings the responsiveness back to a single click. Am I doing this wrong too or the code is simply not geared towards additional effects like dissolve?
Hi Alem,
sorry for the late reply, I am very busy at the moment. The transition you mentioned should be easy to attach with a transform, or so I thought.
Far from it. ^.^
Hello! Sure thing, I’m not in a rush or something. Besides, your initial solution covers almost everything I’ve needed. So, I’m just providing feedback to improve the code so other developers from the community could use it too.

Yeah, I had the same problem with extra clicks >< Also, I can report a pretty strange issue with animation slowing down after playing for some time. There’s no jitter or jerking between frames, the whole thing just slows down on its own and goes back to the original speed after a bit of time.

I can’t say for sure, but increasing Renpy’s images cache (define config.image_cache_size = 100) pushed this problem back in time but didn’t fix it. For testing, I made a 23 frame animation in 1280x732 via show, pause, and repeat commands. After running it for about 10 minutes on the loop, I didn’t notice any slowing down. I can only guess that the problem is somehow tied to “add” command instead of “show”. Maybe this will give you some ideas.

Either way, thanks!

User avatar
plastiekk
Regular
Posts: 111
Joined: Wed Sep 29, 2021 4:08 am
Contact:

Re: Question about syncing up two animated sequences

#10 Post by plastiekk »

Hello,
I have not given up on this project yet and have made a few attempts to add a transformation, without success, or with the above behavior. Adding With(Dissolve(0.5)) in the function itself (outside the screen, during synchronization) brought the desired effect. Unfortunately not inside the screen during normal animation, so it's not really usable. ^.^
As luck would have it, I stumbled across a function on reddit that would be much better (for compatibility reasons) if only I understood how these animations work...
Basically, it creates a list and searches the specified location for images to add to that list, also adds a pause timer and the desired transition effet. The nice thing is, as soon as we call "show image_name" the animation is started at the first image, but we still don't know which image is currently shown, so we can't do any synchronization.
I tried to find out with the help of the console which image is currently shown:
$x = renpy.list_images()
print x
As output, a list with all images is displayed.
e.g [u'black', u'calm_palm', u_calm_palm1', u'calm_palm2', ....and so on]

So there MUST be a counter somewhere that is used to display the current image. But where? And what is its defined name?

Now that a list is shown, I tried the following (also in the console) while the animation "palm_calm" is displayed:
$x = renpy.showing("palm_calm")
print x

output:
True

and waited until calm_palm2 is visible on the screen:
$x = renpy.showing("palm_calm2")
print x

output:
None # ?!

I repeated this process a few times and I don't understand why the answer is always None.
Maybe a Renpy expert can help us with this, that would be really great.
Have a nice day and don't give up, Iam nearly sure there IS a way :)
Greetings

Code: Select all

# function found on reddit you may use google search "renpy.display.anim.TransitionAnimation"

init python:
    def Animation(prefix, fps=24, trans=None):
        
        import os
        pause = 1.0 / fps
        chain = []                                                  # creates a List "chain[]"      
        for fn in renpy.list_files():                               # for, next loop to read images from path
            if not fn.startswith(prefix):
                continue

            basename = os.path.basename(fn)
            base, ext = os.path.splitext(basename)

            if not ext.lower() in [ ".jpg", ".jpeg", ".png", ".webp" ]:
                continue

            chain.extend([fn, pause, trans])                        # append image, fps, transition

        
        return renpy.display.anim.TransitionAnimation(*chain)       # <- ┌ not documented ofc... 
                                                                    #    └ but works like a charm 
####################        
# define image-sequences with function Animation()
# change fps to slow down or speed up, same with Dissolve
image palm_calm = Animation("images/palm_calm", fps=1, trans=Dissolve(1.0)) 
image palm_storm = Animation("images/palm_storm", fps=1, trans=Dissolve(1.0)) 

####################        
label anim_test:

    
    show palm_calm:
        xalign 0.5 yalign 0.5
    with dissolve
    
    "Image seq: palm_calm - sequence starts with picture 1."
    show palm_storm:
        xalign 0.5 yalign 0.5
    hide palm_calm
    with dissolve
    "Image seq: palm_storm sequence also starts with picture 1."
    "That's great. Now we need to find out which image is displayed at the time of the player click."
    return
Alem wrote: Sat Jan 29, 2022 3:42 pm
Yeah, I had the same problem with extra clicks >< Also, I can report a pretty strange issue with animation slowing down after playing for some time. There’s no jitter or jerking between frames, the whole thing just slows down on its own and goes back to the original speed after a bit of time.
ps. I forgot to insert a quote for your notification.
Why on earth did I put the bread in the fridge?

User avatar
plastiekk
Regular
Posts: 111
Joined: Wed Sep 29, 2021 4:08 am
Contact:

Re: Question about syncing up two animated sequences

#11 Post by plastiekk »

A short feedback at this point. I have given up on synchronizing animations, instead I now use a different scheme that allows the player to move the images interactively (i.e. direct them with a mouse gesture).
To be honest, I don't have time (and mood) to reinvent the wheel. :)
Why on earth did I put the bread in the fridge?

Post Reply

Who is online

Users browsing this forum: No registered users