Property Sharing
Many attributes of a Shady.World
or Shady.Stimulus
instance are what we call
“managed properties”. These are stored in arrays (even if they only contain a
single value and otherwise behave like scalars). Many of them are transferred
to the rendering engine on every frame for drawing. By default, every new
Stimulus
object you create has a fresh new set of managed property arrays
created for it, initialized to their default values. However, it is possible
to force multiple stimuli to share the memory space for their properties,
linking their behavior together at with no extra runtime computational cost.
Sharing properties in this way will cause those stimuli to be linked until you
explicitly unlink them. This allows your program to be less complex and more
CPU-efficient, since you will only have to change the property value of one
stimulus and the change will affect all the others.
The simplest way to share a property between two stimuli is to use the shorthand
convention of assigning an actual Stimulus
instance to the relevant property
value of another stimulus:
import Shady
world = Shady.World( 700, top=100, frame=True )
stim1 = world.Patch( x=-200, rotation=30 )
stim2 = world.Stimulus( x=+200, rotation=stim1 )
# now, any change to either stimulus's rotation will affect both
stim1.rotation = 45
print( stim2.rotation )
# --> 45
This technique is in fact a syntactic shorthand for the
ShareProperties
method of the first stimulus:
stim1.ShareProperties( stim2, 'rotation' )
# same effect as stim1.rotation=stim2
This more powerful method can be used to share multiple properties at a time between multiple stimuli:
import Shady
world = Shady.World( 700, top=100, frame=True )
master = world.Stimulus( size=50, y=100 )
followers = [ world.Stimulus( size=50, x=x ) for x in range( -400, 400, 100 ) ]
master.ShareProperties( followers, 'rotation', 'scale' )
Note that the name master
here may be slightly misleading, because
sharing is fully symmetric: any change to the rotation
, or scale
of
any of the Stimulus
instances in followers
will affect the remaining
contents of followers
and our master
. That said, it may be useful
to designate one stimulus as the master to indicate a convention that
this stimulus should be used to control the others, especially if you
are going to use dynamic property assignment
:
master.rotation = lambda t: t * 20
ShareProperties()
also allows you to set property values at the same time
as sharing them:
import Shady
world = Shady.World( 700, top=100, frame=True )
stim1 = world.Patch( x=-200 )
stim2 = world.Patch( x=+200 )
# share color and set that shared color to red
stim1.ShareProperties( stim2, color=( 1, 0, 0 ) )
If you want a stimulus to stop sharing properties, you can again use the
shorthand of Stimulus
-instance assignment:
stim2.color = stim2 # tell `stim2` to "be yourself"
…which is really a shortcut for stim2.MakePropertiesIndependent( 'color' )
.
The MakePropertiesIndependent
method can also simultaneously change the
value(s) of one or more properties as it unlinks them - here’s another example:
# ...
stim1.ShareProperties( stim2, position=( -100, 200 ), alpha=0.5, scale=2.5 )
stim1.Set( position=600 )
print( stim2.position )
# --> [ 600, 600 ]
print( ( stim1.scale, stim2.scale ) )
# --> ( 2.5, 2.5 )
stim2.MakePropertiesIndependent( scale=7 )
print( ( stim1.scale, stim2.scale ) )
# --> ( 2.5, 7.0 )
stim2.alpha = 0.3 # still linked
print( ( stim1.alpha, stim2.alpha ) )
# --> ( 0.3, 0.3 )
One final warning: property sharing does not work with property index
shortcuts, as two stimuli cannot share just part of a full property array.
If you want to share specific property dimensions such as x
or red
,
but not the other dimensions of that property, you should use a dynamic
function instead to ensure it is continually updated:
### WRONG ###
# ...
stim2.x = stim1
# --> ValueError: x is the name of a shortcut, not a fully-fledged
# property - cannot link it across objects
### RIGHT ###
# ...
stim2.x = lambda t: stim1.x # (although it comes at a small CPU cost)
See the demo script examples/sharing.py for more.