Resetting animations within a live composite

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.
Message
Author
User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Resetting animations within a live composite

#61 Post by xela »

Onishion wrote:1. In the case example of (taken from the larger example code above):

Code: Select all

 DisplayableSwitcher(displayable={
                    "Rolling": At("BallImage", Rolling()),   
                    "Bouncing": At("BallImage", Bouncing()),
                    },
It's important that "rolling" and "bouncing" tags are two different names, because that's how later in the switcher it decides what to do with each of those objects when the conditions change, right? But say I have two completely different switchers active at a time, switcherA and switcherB, each doing different animations that I want to behave in sync with each other. Is it important that the tags used in switcherA be different than the ones in switcherB? If they are the same, would they share properties or would they conflict with each other preventing one from working right? Or is it a case that each tag is completely internal to its own animation and cannot impact the other?
In this case, it's most definitely the latter, separate ATL displayable objects will be created. There are some exceptions to this rule, for example if ball image is atl with an end state as well and you create the animation "on the run" instead of in the init but: 1) You never do that in any of your example. 2) It would not go "out of sync", it would freeze at it's end state and would not reset (so it would be clear what's going on).
Onishion wrote:2. In the example of:

Code: Select all

                    ("BallState == 1 and AnimVariable == 0", ("Rolling", )),
                    ("BallState == 1 and AnimVariable == 1", ("Rolling", "reset")),
                    ("BallState == 1 and AnimVariable == 2", ("Rolling", "reset")),
I'm using Animvariable to decide whether the animation is active or not. Now, should I have a unique variable for each different switcher, or can I use one variable that applies to all switchers? I've been trying to use only one, but I keep running into issues where swapping between animations causes them to desync with each other, or reset to stop functioning properly and wonder if this is the cause.
No. This is perfectly fine, using different variables should not change anything. Is "BallImage" a simple image binding? Or is there ATL involved there as well?
Onishion wrote:3. Is it only possible to update the "pause/resume/rest" status of an animation after it has been displayed, or can it be changed while the image is still hidden?
I thought we agreed that nothing happens when the image is "hidden"? We also reset pause/start st that we keep for changing states at 0 st (when the image is shown using the renpy.show() (as opposed to showing it in a screen using if/showif forks which will complicated the matter)).

So that's a no, at least when normal show/hide functionality is used to display these animations to player.
Like what we're doing? Support us at:
Image

Onishion
Veteran
Posts: 295
Joined: Mon Apr 20, 2015 10:36 am
Contact:

Re: Resetting animations within a live composite

#62 Post by Onishion »

No. This is perfectly fine, using different variables should not change anything. Is "BallImage" a simple image binding? Or is there ATL involved there as well?
Ok, I'll try to figure out what's causing the issues then. At least this narrows down some things.
So that's a no, at least when normal show/hide functionality is used to display these animations to player.
Ok, that'll work then.

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Resetting animations within a live composite

#63 Post by xela »

Try using solids, you can test you animations really quickly that way and it's easy to debug once the problem is understood.
Like what we're doing? Support us at:
Image

Onishion
Veteran
Posts: 295
Joined: Mon Apr 20, 2015 10:36 am
Contact:

Re: Resetting animations within a live composite

#64 Post by Onishion »

Ok, so I played with this a bit more.

1. I tried putting a function at the end of an animation block that would cause it to repeat by triggering a reset, but it wouldn't work because there was no interaction. It would change the variables, but since there was no interaction it would then just stop. Is there a way to "fake" an interaction so that the change to the variable would occur instantly without requiring the player to click something else?

2. I think I'm narrowing down the desynching issues, it has to do with cases where I have two or more different switches running, each controlling a different layer of the animation and using separate, but deliberately synchronized transforms, and I pause on one of them, then swap to a different case (ie Ballstate = 1 to Ballstate = 2) and resume, then the animations will tend to fall out of sync, with perhaps one rising as the other falls, when they should be rising in unison. Using the "reset" condition typically resolves this, but that would mean having to add a reset condition each time the variable is changed.

3. There seems to be some issue with resetting. I have the line "$ AniState = 1 if AniState != 1 else 2" in my testing controls, and basically if the last interaction with the Dynamic Switcher was not a reset, like a pause or resume, then activating this element works fine. If, however, the last thing done was a reset, then on some animations (but not all) have weird irregularities, like the object jumps to an entirely different part of the screen. It also does this when I hot shift-d to open the developer menu. Activating pause or resume returns it to normal, for some reason, so a dirty fix for it would be to always resume before resetting, but since changes don't take place without an interaction (see issue #1), this does not actually work, although using a resume, then a line of dialog, then a reset works fine.

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Resetting animations within a live composite

#65 Post by xela »

Onishion wrote:Ok, so I played with this a bit more.

1. I tried putting a function at the end of an animation block that would cause it to repeat by triggering a reset, but it wouldn't work because there was no interaction. It would change the variables, but since there was no interaction it would then just stop. Is there a way to "fake" an interaction so that the change to the variable would occur instantly without requiring the player to click something else?

2. I think I'm narrowing down the desynching issues, it has to do with cases where I have two or more different switches running, each controlling a different layer of the animation and using separate, but deliberately synchronized transforms, and I pause on one of them, then swap to a different case (ie Ballstate = 1 to Ballstate = 2) and resume, then the animations will tend to fall out of sync, with perhaps one rising as the other falls, when they should be rising in unison. Using the "reset" condition typically resolves this, but that would mean having to add a reset condition each time the variable is changed.

3. There seems to be some issue with resetting. I have the line "$ AniState = 1 if AniState != 1 else 2" in my testing controls, and basically if the last interaction with the Dynamic Switcher was not a reset, like a pause or resume, then activating this element works fine. If, however, the last thing done was a reset, then on some animations (but not all) have weird irregularities, like the object jumps to an entirely different part of the screen. It also does this when I hot shift-d to open the developer menu. Activating pause or resume returns it to normal, for some reason, so a dirty fix for it would be to always resume before resetting, but since changes don't take place without an interaction (see issue #1), this does not actually work, although using a resume, then a line of dialog, then a reset works fine.
1) You can write to log, I am not sure what you mean by "faking" an interaction.

2) and 3) require testing cases. Use solids clean project for it.
Like what we're doing? Support us at:
Image

Onishion
Veteran
Posts: 295
Joined: Mon Apr 20, 2015 10:36 am
Contact:

Re: Resetting animations within a live composite

#66 Post by Onishion »


1) You can write to log, I am not sure what you mean by "faking" an interaction.
Well, what I mean is, the Displayable switcher doesn't update until something happens, like a line of dialog, right? I was wondering if there was a way to force that without the player having to do anything, like

Code: Select all

$ AniState = 1 #reset
#insert something here
$ AniState = 3 #pause
"dialog"
So that it would shift through state 1, react according to that change, then go to state 3 and move forward. If I just ran the code like that then it would completely ignore that the reset had been attempted. If I put a line of dialog in the "insert something here" bit, then that would make the animation work right, but force the player to get involved when I'd rather it be fluid and automatic.

I'll try on the other stuff.

Onishion
Veteran
Posts: 295
Joined: Mon Apr 20, 2015 10:36 am
Contact:

Re: Resetting animations within a live composite

#67 Post by Onishion »

Ok, I've created a test case using solids, it is pretty damned long, so sorry about that.

So there are two different problems with this, one that is easy to replicate, and one that takes a little work.

Instructions:
Hit "reshow" to display the objects. Hitting it again hides and then shows the objects again, allowing you to refresh them. pause/reset/resume changes the Dynamic Switcher values, the other commands are for shifting to different animation sequences.

Problem 1. If you are in either the Static or Diagonal animations, and hit reset more than once in a row, it causes the yellow and blue blocks to hop to the bottom right of the screen. This is never intended to happen, and does not happen while the other animations are up, nor does it happen if you alternate between reset and pause/resume, only if you attempt a reset when reset was the last thing that you did. I need to have a way where I can put a "reset" command in the code without needing to know what the previous state was, so that I can reliably reset the animation when re-showing it.

Problem 2. There is a light green block that is prominently visible. There is also a darker green block behind it, which I've made slightly larger so you can see it's there, but normally is identical in size. These two objects should always be perfectly synchronized, so that the background one would never be visible if everything is working right. At times, however, they can fall out of sync, wherein the background object is making it's movements a few seconds before or after the foreground one. This happens with other objects in the actual version but I've pared it down to just these two for the test case. Getting it to do this is a bit trial and error though, I do not know an exact sequence of movements that will cause it to "break," it basically just involves spamming the different animations a few times, maybe pausing, switching animations, resuming, and repeating this process several times, and it should "break" eventually. I can resolve this using "reset," and could ignore this issue if I could reliably "reset" the animations every time I switched between them, but due to Problem 1 that is not currently an easy option.

Again, sorry for the code dump:

Code: Select all

default AniState = 0
default Movement = 0

label SwitcherTest:
    while 1:
        menu:     
            "What do you want?"
            "Reshow":
                hide Test_Animation
                show Test_Animation at SpriteLocation
            "Reset":
                $ AniState = 1 if AniState != 1 else 2 
            "Pause":
                $ AniState = 3 
            "Resume":
                $ AniState = 5
                
            "Static":
                $ Movement = 0
            "Diagonal":
                $ Movement = 1
            "Pulse":
                $ Movement = 2
            "Mid":
                $ Movement = 3
            "Low":
                $ Movement = 4    
            
image Test_Animation:                                   #This is the primary image, the one that will get shown directly                                                
    LiveComposite(    
        (787,913),      
        (0,0), "Switcher1",                                                             # base layer  
        (0,0), "Switcher3",                                                             # top layer
        (0,0), "SwitcherMask",                                                          # mask layer
        (0,0), AlphaMask("Switcher4", "SwitcherMask"),                                  # alphaed layer
        )
    zoom .55
    offset (-290,210)
    
image Switcher1 = DisplayableSwitcher(displayable={                                     #Shows a darker green block      
                    "Static": At("Switcher1_Object", Switcher1_Static()), 
                    "Diagonal": At("Switcher1_Object", Switcher1_Diagonal()),    
                    "Pulse": At("Switcher1_Object", Switcher1_Pulse()),
                    "Mid": At("Switcher1_Object", Switcher1_Mid()),
                    "Low": At("Switcher1_Object", Switcher1_Low())
                    }, 
                conditions=(
                    
                    ("Movement == 1 and AniState == 0", ("Diagonal", )),
                    ("Movement == 1 and AniState == 1", ("Diagonal", "reset")),
                    ("Movement == 1 and AniState == 2", ("Diagonal", "reset")),
                    ("Movement == 1 and AniState == 3", ("Diagonal", "pause")),
                    ("Movement == 1 and AniState == 4", ("Diagonal", "show_paused")),
                    ("Movement == 1 and AniState == 5", ("Diagonal", "resume")),
                    ("Movement == 1 and AniState > 5", ("default", )),
                                        
                    ("Movement == 2 and AniState == 0", ("Pulse", )),
                    ("Movement == 2 and AniState == 1", ("Pulse", "reset")),
                    ("Movement == 2 and AniState == 2", ("Pulse", "reset")),
                    ("Movement == 2 and AniState == 3", ("Pulse", "pause")),
                    ("Movement == 2 and AniState == 4", ("Pulse", "show_paused")),
                    ("Movement == 2 and AniState == 5", ("Pulse", "resume")),
                    ("Movement == 2 and AniState > 5", ("default", )),
                    
                    ("Movement == 3 and AniState == 0", ("Mid", )),
                    ("Movement == 3 and AniState == 1", ("Mid", "reset")),
                    ("Movement == 3 and AniState == 2", ("Mid", "reset")),
                    ("Movement == 3 and AniState == 3", ("Mid", "pause")),
                    ("Movement == 3 and AniState == 4", ("Mid", "show_paused")),
                    ("Movement == 3 and AniState == 5", ("Mid", "resume")),
                    ("Movement == 3 and AniState > 5", ("default", )),
                    
                    ("Movement >= 4 and AniState == 0", ("Low", )),                    
                    ("Movement >= 4 and AniState == 1", ("Low", "reset")),
                    ("Movement >= 4 and AniState == 2", ("Low", "reset")),
                    ("Movement >= 4 and AniState == 3", ("Low", "pause")),
                    ("Movement >= 4 and AniState == 4", ("Low", "show_paused")),
                    ("Movement >= 4 and AniState == 5", ("Low", "resume")),
                    ("Movement >= 4 and AniState > 5", ("default", )),
                    
                    ("Movement < 1 and AniState == 0", ("Static", )),                    
                    ("Movement < 1 and AniState == 1", ("Static", "reset")),
                    ("Movement < 1 and AniState == 2", ("Static", "reset")),
                    ("Movement < 1 and AniState == 3", ("Static", "pause")),
                    ("Movement < 1 and AniState == 4", ("Static", "show_paused")),
                    ("Movement < 1 and AniState == 5", ("Static", "resume")),
                    ("Movement < 1 and AniState > 5", ("default", )),
                    
                    ("True", ("default", ))
                    ))

image Switcher3 = DisplayableSwitcher(displayable={                                             #shows a lighter green block 
                    "Static": At("Switcher3_Object", Switcher1_Static()), 
                    "Diagonal": At("Switcher3_Object", Switcher1_Diagonal()),    
                    "Pulse": At("Switcher3_Object", Switcher1_Pulse()),
                    "Mid": At("Switcher3_Object", Switcher1_Mid()),
                    "Low": At("Switcher3_Object", Switcher1_Low()),
                    }, 
                conditions=(
                    
                    ("Movement == 1 and AniState == 0", ("Diagonal", )),
                    ("Movement == 1 and AniState == 1", ("Diagonal", "reset")),
                    ("Movement == 1 and AniState == 2", ("Diagonal", "reset")),
                    ("Movement == 1 and AniState == 3", ("Diagonal", "pause")),
                    ("Movement == 1 and AniState == 4", ("Diagonal", "show_paused")),
                    ("Movement == 1 and AniState == 5", ("Diagonal", "resume")),
                    ("Movement == 1 and AniState > 5", ("default", )),
                                        
                    ("Movement == 2 and AniState == 0", ("Pulse", )),
                    ("Movement == 2 and AniState == 1", ("Pulse", "reset")),
                    ("Movement == 2 and AniState == 2", ("Pulse", "reset")),
                    ("Movement == 2 and AniState == 3", ("Pulse", "pause")),
                    ("Movement == 2 and AniState == 4", ("Pulse", "show_paused")),
                    ("Movement == 2 and AniState == 5", ("Pulse", "resume")),
                    ("Movement == 2 and AniState > 5", ("default", )),
                    
                    ("Movement == 3 and AniState == 0", ("Mid", )),
                    ("Movement == 3 and AniState == 1", ("Mid", "reset")),
                    ("Movement == 3 and AniState == 2", ("Mid", "reset")),
                    ("Movement == 3 and AniState == 3", ("Mid", "pause")),
                    ("Movement == 3 and AniState == 4", ("Mid", "show_paused")),
                    ("Movement == 3 and AniState == 5", ("Mid", "resume")),
                    ("Movement == 3 and AniState > 5", ("default", )),
                    
                    ("Movement >= 4 and AniState == 0", ("Low", )),                    
                    ("Movement >= 4 and AniState == 1", ("Low", "reset")),
                    ("Movement >= 4 and AniState == 2", ("Low", "reset")),
                    ("Movement >= 4 and AniState == 3", ("Low", "pause")),
                    ("Movement >= 4 and AniState == 4", ("Low", "show_paused")),
                    ("Movement >= 4 and AniState == 5", ("Low", "resume")),
                    ("Movement >= 4 and AniState > 5", ("default", )),
                    
                    ("Movement < 1 and AniState == 0", ("Static", )),                    
                    ("Movement < 1 and AniState == 1", ("Static", "reset")),
                    ("Movement < 1 and AniState == 2", ("Static", "reset")),
                    ("Movement < 1 and AniState == 3", ("Static", "pause")),
                    ("Movement < 1 and AniState == 4", ("Static", "show_paused")),
                    ("Movement < 1 and AniState == 5", ("Static", "resume")),
                    ("Movement < 1 and AniState > 5", ("default", )),
                    
                    ("True", ("default", ))
                    ))

image Switcher4 = DisplayableSwitcher(displayable={                                             #shows a yellow block, which gets alphaed   
                    "Static": At("Switcher4_Object", Switcher4_Static()), 
                    "Diagonal": At("Switcher4_Object", Switcher4_Diagonal()),    
                    "Pulse": At("Switcher4_Object", Switcher4_Mid()),
                    "Mid": At("Switcher4_Object", Switcher4_Mid()),
                    "Low": At("Switcher4_Object", Switcher4_Mid())
                    }, 
                conditions=(
                    
                    ("Movement == 1 and AniState == 0", ("Diagonal", )),
                    ("Movement == 1 and AniState == 1", ("Diagonal", "reset")),
                    ("Movement == 1 and AniState == 2", ("Diagonal", "reset")),
                    ("Movement == 1 and AniState == 3", ("Diagonal", "pause")),
                    ("Movement == 1 and AniState == 4", ("Diagonal", "show_paused")),
                    ("Movement == 1 and AniState == 5", ("Diagonal", "resume")),
                    ("Movement == 1 and AniState > 5", ("default", )),
                                        
                    ("Movement == 2 and AniState == 0", ("Pulse", )),
                    ("Movement == 2 and AniState == 1", ("Pulse", "reset")),
                    ("Movement == 2 and AniState == 2", ("Pulse", "reset")),
                    ("Movement == 2 and AniState == 3", ("Pulse", "pause")),
                    ("Movement == 2 and AniState == 4", ("Pulse", "show_paused")),
                    ("Movement == 2 and AniState == 5", ("Pulse", "resume")),
                    ("Movement == 2 and AniState > 5", ("default", )),
                    
                    ("Movement > 1 and AniState == 0", ("Mid", )),
                    ("Movement > 1 and AniState == 1", ("Mid", "reset")),
                    ("Movement > 1 and AniState == 2", ("Mid", "reset")),
                    ("Movement > 1 and AniState == 3", ("Mid", "pause")),
                    ("Movement > 1 and AniState == 4", ("Mid", "show_paused")),
                    ("Movement > 1 and AniState == 5", ("Mid", "resume")),
                    ("Movement > 1 and AniState > 5", ("default", )),
                    
                    ("Movement >= 3 and AniState == 0", ("Low", )),                    
                    ("Movement >= 3 and AniState == 1", ("Low", "reset")),
                    ("Movement >= 3 and AniState == 2", ("Low", "reset")),
                    ("Movement >= 3 and AniState == 3", ("Low", "pause")),
                    ("Movement >= 3 and AniState == 4", ("Low", "show_paused")),
                    ("Movement >= 3 and AniState == 5", ("Low", "resume")),
                    ("Movement >= 3 and AniState > 5", ("default", )),
                    
                    ("Movement < 1 and AniState == 0", ("Static", )),                    
                    ("Movement < 1 and AniState == 1", ("Static", "reset")),
                    ("Movement < 1 and AniState == 2", ("Static", "reset")),
                    ("Movement < 1 and AniState == 3", ("Static", "pause")),
                    ("Movement < 1 and AniState == 4", ("Static", "show_paused")),
                    ("Movement < 1 and AniState == 5", ("Static", "resume")),
                    ("Movement < 1 and AniState > 5", ("default", )),
                    
                    ("True", ("default", ))
                    ))

image SwitcherMask = DisplayableSwitcher(displayable={                                          #shows the blue alpha masking object
                    "Static": At("SwitcherMask_Object", Switcher4_StaticMask()), 
                    "Diagonal": At("SwitcherMask_Object", Switcher4_StaticMask()), 
                    "Pulse": At("SwitcherMaskB", Switcher1_Pulse()),         #note how this one uses a different base object
                    "Mid": At("SwitcherMask_Object", Switcher1_Mid()),
                    "Low": At("SwitcherMask_Object", Switcher1_Low())
                    }, 
                conditions=(
                    
                    ("Movement == 1 and AniState == 0", ("Diagonal", )),
                    ("Movement == 1 and AniState == 1", ("Diagonal", "reset")),
                    ("Movement == 1 and AniState == 2", ("Diagonal", "reset")),
                    ("Movement == 1 and AniState == 3", ("Diagonal", "pause")),
                    ("Movement == 1 and AniState == 4", ("Diagonal", "show_paused")),
                    ("Movement == 1 and AniState == 5", ("Diagonal", "resume")),
                    ("Movement == 1 and AniState > 5", ("default", )),
                                        
                    ("Movement == 2 and AniState == 0", ("Pulse", )),
                    ("Movement == 2 and AniState == 1", ("Pulse", "reset")),
                    ("Movement == 2 and AniState == 2", ("Pulse", "reset")),
                    ("Movement == 2 and AniState == 3", ("Pulse", "pause")),
                    ("Movement == 2 and AniState == 4", ("Pulse", "show_paused")),
                    ("Movement == 2 and AniState == 5", ("Pulse", "resume")),
                    ("Movement == 2 and AniState > 5", ("default", )),
                    
                    ("Movement == 3 and AniState == 0", ("Mid", )),
                    ("Movement == 3 and AniState == 1", ("Mid", "reset")),
                    ("Movement == 3 and AniState == 2", ("Mid", "reset")),
                    ("Movement == 3 and AniState == 3", ("Mid", "pause")),
                    ("Movement == 3 and AniState == 4", ("Mid", "show_paused")),
                    ("Movement == 3 and AniState == 5", ("Mid", "resume")),
                    ("Movement == 3 and AniState > 5", ("default", )),
                    
                    ("Movement >= 4 and AniState == 0", ("Low", )),                    
                    ("Movement >= 4 and AniState == 1", ("Low", "reset")),
                    ("Movement >= 4 and AniState == 2", ("Low", "reset")),
                    ("Movement >= 4 and AniState == 3", ("Low", "pause")),
                    ("Movement >= 4 and AniState == 4", ("Low", "show_paused")),
                    ("Movement >= 4 and AniState == 5", ("Low", "resume")),
                    ("Movement >= 4 and AniState > 5", ("default", )),
                    
                    ("Movement < 1 and AniState == 0", ("Static", )),                    
                    ("Movement < 1 and AniState == 1", ("Static", "reset")),
                    ("Movement < 1 and AniState == 2", ("Static", "reset")),
                    ("Movement < 1 and AniState == 3", ("Static", "pause")),
                    ("Movement < 1 and AniState == 4", ("Static", "show_paused")),
                    ("Movement < 1 and AniState == 5", ("Static", "resume")),
                    ("Movement < 1 and AniState > 5", ("default", )),
                    
                    ("True", ("default", ))
                    ))

image SwitcherMaskB = DisplayableSwitcher(displayable={                                         #this is an alternate alpha mask situation             
                    "Static": At("SwitcherMask_Object", Switcher4_StaticMask()), 
                    "Diagonal": At("SwitcherMask_Object", Switcher4_StaticMask()),   
                    "Pulse": At("SwitcherMask_ObjectB", Switcher1_AnimB()),                     #this is the only one actually necessary, but more problems occur without it
                    "Mid": At("SwitcherMask_Object", Switcher1_Mid()),
                    "Low": At("SwitcherMask_Object", Switcher1_Low())
                    }, 
                conditions=(        
                    ("Movement == 1 and AniState == 0", ("Diagonal", )),
                    ("Movement == 1 and AniState == 1", ("Diagonal", "reset")),
                    ("Movement == 1 and AniState == 2", ("Diagonal", "reset")),
                    ("Movement == 1 and AniState == 3", ("Diagonal", "pause")),
                    ("Movement == 1 and AniState == 4", ("Diagonal", "show_paused")),
                    ("Movement == 1 and AniState == 5", ("Diagonal", "resume")),
                    ("Movement == 1 and AniState > 5", ("default", )),
                                        
                    ("Movement == 2 and AniState == 0", ("Pulse", )),
                    ("Movement == 2 and AniState == 1", ("Pulse", "reset")),
                    ("Movement == 2 and AniState == 2", ("Pulse", "reset")),
                    ("Movement == 2 and AniState == 3", ("Pulse", "pause")),
                    ("Movement == 2 and AniState == 4", ("Pulse", "show_paused")),
                    ("Movement == 2 and AniState == 5", ("Pulse", "resume")),
                    ("Movement == 2 and AniState > 5", ("default", )),
                    
                    ("Movement == 3 and AniState == 0", ("Mid", )),
                    ("Movement == 3 and AniState == 1", ("Mid", "reset")),
                    ("Movement == 3 and AniState == 2", ("Mid", "reset")),
                    ("Movement == 3 and AniState == 3", ("Mid", "pause")),
                    ("Movement == 3 and AniState == 4", ("Mid", "show_paused")),
                    ("Movement == 3 and AniState == 5", ("Mid", "resume")),
                    ("Movement == 3 and AniState > 5", ("default", )),
                    
                    ("Movement >= 4 and AniState == 0", ("Low", )),                    
                    ("Movement >= 4 and AniState == 1", ("Low", "reset")),
                    ("Movement >= 4 and AniState == 2", ("Low", "reset")),
                    ("Movement >= 4 and AniState == 3", ("Low", "pause")),
                    ("Movement >= 4 and AniState == 4", ("Low", "show_paused")),
                    ("Movement >= 4 and AniState == 5", ("Low", "resume")),
                    ("Movement >= 4 and AniState > 5", ("default", )),
                    
                    ("Movement < 1 and AniState == 0", ("Static", )),                    
                    ("Movement < 1 and AniState == 1", ("Static", "reset")),
                    ("Movement < 1 and AniState == 2", ("Static", "reset")),
                    ("Movement < 1 and AniState == 3", ("Static", "pause")),
                    ("Movement < 1 and AniState == 4", ("Static", "show_paused")),
                    ("Movement < 1 and AniState == 5", ("Static", "resume")),
                    ("Movement < 1 and AniState > 5", ("default", )),
                    
                    ("True", ("default", ))
                    ))

image InternalSwitcher = DisplayableSwitcher(displayable={            #this controls the pulsing motion on a small blue block
                    "Pulse": At("InternalObject", Switcher1_AnimB()),                    
                    }, 
                conditions=(          
                    ("Movement == 2 and AniState == 0", ("Pulse", )),
                    ("Movement == 2 and AniState == 1", ("Pulse", "reset")),
                    ("Movement == 2 and AniState == 2", ("Pulse", "reset")),
                    ("Movement == 2 and AniState == 3", ("Pulse", "pause")),
                    ("Movement == 2 and AniState == 4", ("Pulse", "show_paused")),
                    ("Movement == 2 and AniState == 5", ("Pulse", "resume")),
                    ("Movement == 2 and AniState > 5", ("default", )),
                    
                    ("True", ("default", ))
                    ))

image Switcher1_Object:                 #this is the darker green block on the bottom
    "True", Solid("#159457", xysize=(500,500))   
    
image Switcher3_Object:                 #this is the light green block on the top layer
    LiveComposite(    
        (787,913),     
        (0,0), Solid("#47ec9d", xysize=(500,500)),
        (0,0), "InternalSwitcher",        
        ) 

image Switcher4_Object:                 #this is the yellow rectangle
    LiveComposite(                   
        (200,950),             
        (0,0), Solid("#d5f623", xysize=(200, 950)),
        )
    anchor (0.5,0.5)
    zoom 1.05
    alpha .8
    pos (150,1000)
    
image InternalObject:                   #this is the small teal block that gets animated to pulse
    contains:
        Solid("#75d7ec", xysize=(100,100)),
        anchor (0.40,0.65) 
        
image SwitcherMask_Object:              #this is the blue masking object
    Solid("#7a8aff", xysize=(787, 1489))     
    alpha 0.2

image SwitcherMask_ObjectB:             #this is the one used for the alternate mode
    alpha .2
    contains:
        Solid("#7a8aff", xysize=(787, 1489))     
        anchor (0.40, 0.4)

#Transforms:

transform Switcher4_Static():                       
    anchor (.5,.5)
    rotate -10
    
transform Switcher4_StaticMask():           
    anchor (.5,.5)
    offset (410,600)
    xzoom 1.1
    yzoom 1.05
           
transform Switcher4_Mid():                    
    anchor (.5,.5)
    rotate 0
        
transform Switcher4_Diagonal():                    
    subpixel True
    anchor (.5,.5)
    block:
        ease 2 rotate -5 #410
        pause .5
        ease 2.5 rotate 0
        repeat
        
transform Switcher1_Diagonal():                 
    subpixel True 
    ease 0.5 offset (0,-35)  #top
    block:
        ease 2.5 offset (25,100) 
        ease 2 offset (0,-35) 
        pause .5
        function AnimRepeat
        repeat
    
transform Switcher1_Pulse():          
    subpixel True 
    offset (0,-40)     #top 
    block:
        ease 1 yoffset 35               
        ease 1.5 offset (0,-40)    
        function AnimRepeat
        repeat

transform Switcher1_AnimA():
        pos (316,600)
        zoom 1.0    
            
transform Switcher1_AnimB():
        pos (316,600)
        subpixel True
        zoom 0.70    
        block:
            pause .15
            easein .25 zoom 0.9
            linear .1 zoom 0.87
            easeout .3 zoom 0.9
            pause .5
            easein .4 zoom 0.87
            linear .1 zoom 0.9
            easeout .45 zoom 0.70
            pause .25
            repeat
                        
transform Switcher1_Mid():           
    subpixel True
    ease 0.5 offset (0,50) 
    block:
        ease 1 yoffset 120 #100
        ease 1.5 offset (0,50) 
        function AnimRepeat
        repeat    
    
transform Switcher1_Low():       
    ease .5 offset (0,100) 
    block:
        subpixel True
        ease 1 yoffset 300
        pause .5
        ease 2 yoffset 100  
        function AnimRepeat
        repeat
        
transform Switcher1_Static():      
    subpixel True 
    ease 1.5 offset (0,0)
    function AnimRepeat
    repeat

transform SpriteLocation(): 
    pos (715,50)


User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Resetting animations within a live composite

#68 Post by xela »

I'll take a look when time permits. Both issues are weird but the first one I dealt with before in a separate project, just don't remember what was causing it exactly.
Like what we're doing? Support us at:
Image

Onishion
Veteran
Posts: 295
Joined: Mon Apr 20, 2015 10:36 am
Contact:

Re: Resetting animations within a live composite

#69 Post by Onishion »

Ok, thanks. I understand that it's a weird and complex issue and appreciate you looking into it. I've tried a lot of trial and error to try to fix it on my end, but I don't understand the switcher code itself to mess with it productively.

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Resetting animations within a live composite

#70 Post by xela »

The code example is very large, making it very hard to debug :( Code is also incomplete, I've added a dummy func and renamed the label to start to get it to work, I think controls might be messed up as well.

I don't think that most of it is needed to make a testing case.
Onishion wrote:Problem 1. If you are in either the Static or Diagonal animations, and hit reset more than once in a row, it causes the yellow and blue blocks to hop to the bottom right of the screen. This is never intended to happen, and does not happen while the other animations are up, nor does it happen if you alternate between reset and pause/resume, only if you attempt a reset when reset was the last thing that you did. I need to have a way where I can put a "reset" command in the code without needing to know what the previous state was, so that I can reliably reset the animation when re-showing it.
This is tricky, I already wrote about it (at least meant to) but finite sets of atl instructions have a "done" state and cannot really be reset in a way as repeated animation. That's why the block with the meaningless repeat is working properly while the everything else in static mode breaks down. It's prolly not worth to mess with Ren'Py further trying to make completely new instances of transforms for resets because meaningless repeats or re-showing can be used instead.

Also, that stuff really should not be ATL... I mean, you can just provide positional style properties directly to any displayable, there is not reason to use atl there at all and chances are that a normal way will work perfectly.
Onishion wrote:Problem 2. There is a light green block that is prominently visible. There is also a darker green block behind it, which I've made slightly larger so you can see it's there, but normally is identical in size. These two objects should always be perfectly synchronized, so that the background one would never be visible if everything is working right. At times, however, they can fall out of sync, wherein the background object is making it's movements a few seconds before or after the foreground one. This happens with other objects in the actual version but I've pared it down to just these two for the test case. Getting it to do this is a bit trial and error though, I do not know an exact sequence of movements that will cause it to "break," it basically just involves spamming the different animations a few times, maybe pausing, switching animations, resuming, and repeating this process several times, and it should "break" eventually. I can resolve this using "reset," and could ignore this issue if I could reliably "reset" the animations every time I switched between them, but due to Problem 1 that is not currently an easy option.
You can reset if you adjust your animation with simpler declarations or meaningless repeats. Re-showing seems to be working but I thing former is a more coherent solution.
Like what we're doing? Support us at:
Image

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Resetting animations within a live composite

#71 Post by xela »

Code: Select all

image SwitcherMask = DisplayableSwitcher(displayable={                                          #shows the blue alpha masking object
                    "Static": Transform("SwitcherMask_Object", anchor=(.5,.5), offset=(410, 600), xzoom=1.1, yzoom=1.05),
See, this works perfectly, you really shouldn't be using sets of atl instructions for stuff this simple, it's bloody pointless and adds overhead. If you have something that transforms it's properties a finite number of times, you can use the "meaningless" repeat trick I mentioned earlier, it will be an acceptable solution for such cases.

I couldn't replicate problem 2, but you mentioned a solution to it if first issue was solved.
Like what we're doing? Support us at:
Image

Onishion
Veteran
Posts: 295
Joined: Mon Apr 20, 2015 10:36 am
Contact:

Re: Resetting animations within a live composite

#72 Post by Onishion »

The code example is very large, making it very hard to debug :( Code is also incomplete, I've added a dummy func and renamed the label to start to get it to work, I think controls might be messed up as well.

I don't think that most of it is needed to make a testing case.
Sorry, I took the code I was using and pared down the bits that I definitely didn't need, I'm aware that there are more animation options than might strictly be necessary, and therefore more switcher options, but I wasn't sure exactly which animation was causing the problems.
This is tricky, I already wrote about it (at least meant to) but finite sets of atl instructions have a "done" state and cannot really be reset in a way as repeated animation. That's why the block with the meaningless repeat is working properly while the everything else in static mode breaks down. It's prolly not worth to mess with Ren'Py further trying to make completely new instances of transforms for resets because meaningless repeats or re-showing can be used instead.
Ok, so just add "repeats" to the end of all my switcher-based animations whether they traditionally need them or not? I can do that.
Also, that stuff really should not be ATL... I mean, you can just provide positional style properties directly to any displayable, there is not reason to use atl there at all and chances are that a normal way will work perfectly.
I can test it, I think my concern was that whenever I had something that was "different" than the rest of the switcher options, it caused issues. Like I believe at once point I had four options that were like ""Static": At("SwitcherMask_Object", Switcher4_StaticMask())," and then one option of the bunch that was ""Static": "Switcher_Object"," or something along those lines, and it threw back a blue screen error. It did not like me maxing At functions and self-contained animated images in a single Switcher.
See, this works perfectly, you really shouldn't be using sets of atl instructions for stuff this simple, it's bloody pointless and adds overhead. If you have something that transforms it's properties a finite number of times, you can use the "meaningless" repeat trick I mentioned earlier, it will be an acceptable solution for such cases.
Ok, I'll give it a shot. I'm sure a lot of it just comes down to me only understanding a subset of the potential options available to me, I'm constantly learning new ways to declare the same sort of outcomes.

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Resetting animations within a live composite

#73 Post by xela »

Onishion wrote:Ok, I'll give it a shot. I'm sure a lot of it just comes down to me only understanding a subset of the potential options available to me, I'm constantly learning new ways to declare the same sort of outcomes.
I've tested that codebit, it fixed the issue instantly. For a finite number of repeats (you don't have that in code but it's a possibility), you can just add "meaningless" repeat after those are done. It'll work! :)

Edit: It doesn't have to be a Transform, you can add simple positional properties to almost everything in Ren'Py.
Like what we're doing? Support us at:
Image

User avatar
Arowana
Miko-Class Veteran
Posts: 531
Joined: Thu May 31, 2012 11:17 pm
Completed: a2 ~a due~
Projects: AXIOM.01, The Pirate Mermaid
Organization: Variable X, Navigame
Tumblr: navigame-media
itch: navigame
Contact:

Re: Resetting animations within a live composite

#74 Post by Arowana »

xela, thanks so much for sharing your DisplayableSwitcher code. I found it to be extremely useful! :D

However, I ran into a problem. If you have interactions with tooltips or hotkeys before the animation is finished playing, this will cause the animation to reset. Below is an example to demonstrate.

First, I created a tooltip on the quick menu:

Code: Select all

screen quick_menu():

    ## Ensure this appears on top of other screens.
    zorder 100
    default tt = Tooltip("")
    
    if quick_menu:

        hbox:
            style_prefix "quick"

            xalign 0.5
            yalign 1.0

            textbutton _("Back") action Rollback() 
            textbutton _("History") action ShowMenu('history')
            textbutton _("Skip") action Skip() alternate Skip(fast=True, confirm=True)
            textbutton _("Auto") action Preference("auto-forward", "toggle")
            textbutton _("Save") action ShowMenu('save')
            textbutton _("Q.Save") action QuickSave()
            textbutton _("Q.Load") action QuickLoad()
            textbutton _("Prefs") action ShowMenu('preferences') hovered tt.Action("test") unhovered tt.Action("") ###### tooltip added here
 
    text tt.value xalign 0.9 yalign 0.9   
Then I copied all the code exactly as posted here, but changed the Rolling transform to:

Code: Select all

transform Rolling():           
    xoffset -100 alpha 0 
    linear 3 xoffset 100 alpha 1
When you run the game, try hovering over the Prefs button on the quick menu before the animation is finished playing. When the tooltip pops up, the animation restarts. You can also get the animation to restart by using a hotkey - for example, hitting "h" to hide the textbox - before the animation is finished playing. Is it possible to keep these interactions from making the animation restart?
Complete: a2 ~a due~ (music, language, love)
In progress: The Pirate Mermaid (fairytale otome)
On hold: AXIOM.01 (girl detective game)

Image

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Resetting animations within a live composite

#75 Post by xela »

It's explicitly set to reset on interactions under that setup:

Code: Select all

default AnimVariable = 2

Code: Select all

("BallState == 1 and AnimVariable == 2", ("Rolling", "reset")),
If you want just the normal behavior:

Code: Select all

default AnimVariable = 0
==================>>>
Original idea behind the class was to allow controlling atl timings to overcome limitations posed by renpy screens and change displayable state using a class method so it can be done without user interactions.

We went into a weird place using it to control complex animations :)
Like what we're doing? Support us at:
Image

Post Reply

Who is online

Users browsing this forum: Bing [Bot], Tony_Tan