首页 > 解决方案 > 是否可以在 Shady 中共享动画回调?

问题描述

我正在尝试使用 Shady 来呈现一系列图像帧。在过去,我通过为stimulus.page 属性分配一个动画回调来做到这一点。在 Shady 为每个监视器帧调用一次的回调中,我首先检查一个全局变量,该变量跟踪应该显示哪个刺激帧。如果是肯定的,我将刺激的可见性设置为 True 并返回帧号;否则我将其设置为 False 并返回 0。就像一个魅力。

现在我需要扩展它,因为我需要从多个序列中选择一个来显示。由于加载序列可能需要一些时间,因此我在程序开始时将它们全部加载,并将每个序列与一个 Stimulus 对象相关联。现在,这是我的问题。我是否必须为每个序列(其数量可变,并且可能很高)创建不同的动画回调函数。或者有没有更优雅的方法来调用单个动画回调(或类似的东西),并在那里我确定要显示哪个序列的哪个帧(再次,基于全局变量的当前值)?

标签: pythonanimationshady

解决方案


首先,我想确定“动画回调”和“动态属性值”在术语上的区别。Shady 文档和此答案并未将您使用的东西称为“动画回调”。但我认为,对您的问题的最佳答案可能是使用实际的动画回调。

  • 动态属性值或“动态”:WorldStimulus实例的某些属性可以分配给它们的可调用对象。如果是这样,它们会在每一帧上被调用。你stimulus.page就是一个例子(即使page它不是一个成熟的“托管属性”,即具有与另一个实例的相应属性共享内存的能力,它确实支持这种方式的“动态分配”)。如果您希望一次只更改几个刺激的几个方面,和/或您希望一个属性的更改完全独立于另一个属性的更改,则动态属性是很好的。ts(或实际上任何其他实例)具有原型blah(self, t),因为self当您访问它时将被烘焙。该函数还必须返回一个值——应该分配给此帧上的属性的静态值。

  • 动画回调:每个Stimulus实例s(以及另外的World实例)都有一个“动画回调”,它占据属性槽s.Animate,并且可以通过s.SetAnimationCallback方法或其等效函数装饰器进行更改@s.AnimationCallback。在每一帧上,每一个WorldStimulus实例都会检查它是否有一个.Animate属性,如果有,就调用它。如果您希望对多个属性(例如s.visibles.page)的更改相互协调,那么附加到的动画回调s可能是最好的选择。与动态不同,动画回调可以是一个(未绑定的)方法,它接收对sas的引用self,因此 的属性self可以用作“全局”(但特定于刺激实例)的暂存器。(实际上,对于动画回调,您可以选择使用类似方法的原型blah(self, t)或单参数原型来定义它们blah(t),类似于动态。)动态是功能性的,动画回调是程序性的:动画回调的任何返回参数被忽略。

在任何一种情况下,确实(正如您所担心的那样)您附加回调的所有刺激都会调用它,并且所有刺激都会在每一帧上调用它们的动态,而不检查相同的可调用对象是否也被使用其他情况。如果您想确保代码不会被不必要地调用,您的选择包括:

  1. 如果一次只Stimulus应该看到一个:让每个都Stimulus遵循自己的逻辑,在自己的动画回调和/或动态属性中(以您最有意义的为准)。但是当它应该在屏幕外时,不要只设置s.visible = False: 相反,实际上让Stimulus实例s.Leave()出现在舞台上,并s.Enter()在必要时再次设置。当你在舞台上时,即使你是隐形的,你的动画回调和动态也会在每一帧上被调用。当你不在舞台上时,他们不会被召唤。这在年底得到证明python -m Shady demo sharing

  2. 或者,您可以选择在一个地方执行大部分或全部动画逻辑。最好的地方可能是World动画回调,它肯定每帧只调用一次,因为只有一个World. 对单个刺激的引用始终可以作为全局变量检索,或者通过self.stimuli容器中的名称检索:

    import Shady
    cmdline = Shady.WorldConstructorCommandLine()
    cmdline.Help().Finalize()
    
    w = Shady.World( **cmdline.opts )   
    w.Stimulus( name='bill', x=-100, size=100, color=[1,0,0] )
    w.Stimulus( name='ben',  x=+100, size=100, color=[0,0,1] )
    
    @w.AnimationCallback
    def Animate( self, t ):
        # top-down control of multiple stimuli:
    
        if self.framesCompleted % 2:
            # self.stimuli is a dict, with all the expected dict capabilities...
            self.stimuli['bill'].visible = True 
            self.stimuli['ben'].visible = False
        else:
            # ...but it supports lazier syntax too:
            self.stimuli.bill.visible = False 
            self.stimuli.ben.visible = True
    
    Shady.AutoFinish( w )
    

推荐阅读