transitions
— A quick and easy way to automate transforming your nodes¶
When writing a game you’ll often want to apply a set of known transformations to a nodes.Node
. For example, you want your
Node to move 100 pixels to the right, then wait 3 seconds and return 100 pixels to the left. Or you’ll want the node
to pulsate (smoothly change its scale between some min and max values), or rotate back and forth. YOu may want to have
any combination of those effects applied (either one after another or parallel). There’s an unlimited number of such
visual transformations and their combinations, that you may want to have in your game.
You can of course implement all this, by having a set of boolean flags, time trackers, etc. and use all those helper variables to manually change the desired properties of your nodes from within the update() method. But there is an easier way: the mechanism is called Transitions. A single Transition object is a recipe of how a given property of a Node (position, scale, rotation, color, sprite, etc.) should change over time. Transition can be played once, given number of times or in a loop. You can also chains transitions to run one after another or in parallel.
Transitions are the primary way of creating animations. Since animation is nothing else than just changing Node’s sprite over time, the transition mechanism comes useful for that purpose.
Common transition parameters¶
Note: All transitions are immutable.
To create a Transition you’ll typically need to pass the following parameters:
advance_value
- advance value for given transition type (e.g. target position forNodePositionTransition
).duration
- transition duration time, in secondsadvance_method
- an enum value ofAttributeTransitionMethod
type which determines how theadvance_value
will be applied to modify the appropriate node property.AttributeTransitionMethod.set
- node’s property will be changed towards the advance_value over timeAttributeTransitionMethod.add
- node’s property will be changed towards the current value + advance_value over timeAttributeTransitionMethod.multiply
- node’s property will be changed towards the current value * advance_value over time
loops
- Optional. How many times the transition should “play”. Set to 0 to play infinite number of times. Default is 1.back_and_forth
- Optional. If set toTrue
, the transition will be played back and forth (that counts as one “loop”). Default is False.easing
- Optional. An enum value ofeasings.Easing
- specifies the rate of change of a value over time. Default is Easing.none which really means a linear easing.
Note
The duration
parameter always refers to one loop, one direction. So for example, transition
with the following set of parameters: duration=1., loops=3, back_and_forth=True
will take 6 seconds.
1 second played back and forth is 2 seconds, and it will be played 3 times, hence a total time
of 6 seconds.
Note
If back_and_forth
is set to True
, the transition will play back and forth which counts as one loop.
All transitions use linear easing. More built-in easing types are to be added soon.
Examples¶
Change position of a node, from (100,100) to (30, 70) over 2 seconds.
node = Node(position=Vector(100, 100), sprite=Sprite('image.png'))
node.transition = NodePositionTransition(Vector(30, 70), 2.)
Change position of a node, from (100,100) by (30, 70), i.e. to (130, 170) over 2 seconds.
node = Node(position=Vector(100, 100), sprite=Sprite('image.png'))
node.transition = NodePositionTransition(Vector(30, 70), 2., advance_method=AttributeTransitionMethod.add)
Change position of a node, from (100, 100) by (x30, x70), i.e. to (3000, 7000) over 2 seconds.
node = Node(position=Vector(100, 100), sprite=Sprite('image.png'))
node.transition = NodePositionTransition(Vector(30, 70), 2., advance_method=AttributeTransitionMethod.multiply)
Change position of a node, from (100,100) to (30, 70) then back to the initial position (100,100) over 2 seconds.
node = Node(position=Vector(100, 100), sprite=Sprite('image.png'))
node.transition = NodePositionTransition(Vector(30, 70), 2., back_and_forth=True)
Change position of a node, from (100,100) to (30, 70) then get back to the initial position over 2 seconds. Repeat it 3 times.
node = Node(position=Vector(100, 100), sprite=Sprite('image.png'))
node.transition = NodePositionTransition(Vector(30, 70), 2., loops=3, back_and_forth=True)
Change the scale of a node (twice on the X axis and three times on the Y axis) over 1 second.
node = Node(position=Vector(100, 100), sprite=Sprite('image.png'))
node.transition = NodeScaleTransition(Vector(2, 3), 1.)
Change the scale of a node (twice on the X axis and three times on the Y axis) over 1 second. Repeat indefinitely (creating pulsation effect).
node = Node(position=Vector(100, 100), sprite=Sprite('image.png'))
node.transition = NodeScaleTransition(Vector(2, 3), 1., loops=0)
Rotate the node 90 degrees clockwise over 3 seconds
node = Node(position=Vector(100, 100), sprite=Sprite('image.png'))
node.transition = NodeRotationTransition(math.pi/2, 3.)
Change position of a node by (150, 100) over 2 seconds, then enlarge it twice over 1 second, then do nothing for 2 seconds, finally rotate it 180 degrees over 3 seconds. Play the whole sequence two times, back and forth.
node = Node(position=Vector(100, 100), sprite=Sprite('image.png'))
transitions = [
NodePositionTransition(Vector(150, 100), 2., advance_method=AttributeTransitionMethod.add),
NodeScaleTransition(Vector(2, 2), 1.),
NodeTransitionDelay(2.),
NodeRotationTransition(math.pi, 3.)
]
node.transition = NodeTransitionsSequence(transitions, loops=2, back_and_forth=True)
Do everything the same like in previous example but have the node simultaneously change its color to red, back and forth in 1500 milisecond intervals.
node = Node(position=Vector(100, 100), sprite=Sprite('image.png'))
transitions = [
NodePositionTransition(Vector(150, 100), 2., advance_method=AttributeTransitionMethod.add),
NodeScaleTransition(Vector(2, 2), 1.),
NodeTransitionDelay(2.),
NodeRotationTransition(math.pi, 3.)
]
color_transition = NodeColorTransition(Color(1,0,0,1), 1.5, loops=0, back_and_forth=True)
node.transition = NodeTransitionsParalel([
color_transition,
NodeTransitionsSequence(transitions, loops=2, back_and_forth=True)
])
Change position of a node, from (100,100) to (30, 70) over 2 seconds and call function my_func when the transition ends.
def my_func(transitioning_node):
print('Function called!')
node = Node(position=Vector(100, 100), sprite=Sprite('image.png'))
node.transition = NodeTransitionSequence([
NodePositionTransition(Vector(30, 70), 2.),
NodeTransitionCallback(my_func)])
Change sprite of a node, creating an animation effect:
spritesheet = Sprite(os.path.join('assets', 'gfx', 'spritesheet.png')
frames = split_spritesheet(spritesheet, Vector(100,100)) # cut the spritesheet into <Sprite> instances
animation = NodeSpriteTransition(frames, duration=2., loops=0, back_and_forth=False)
node = Node(position=Vector(100, 100), transition=animation)
Change z_index of a node over time:
node = Node(position=Vector(100, 100), sprite=Sprite('image.png'))
node.transition = NodeZIndexSteppingTransition([1,2,3,4,5,6,10,100], 1000)
NodePositionTransition
reference¶
-
class
transitions.
NodePositionTransition
(advance_value, duration, advance_method=AttributeTransitionMethod.set, loops=1, back_and_forth=False, easing=Easing.none)¶ Use this transition to change Node’s position gradually over time, towards given advance_value or by given advance_value.
The
advance_value
param must be ageometry.Vector
and is the target position value (or position change value)Refer to the Common transition parameters and Examples sections for information on other parameters used by the transition.
NodeRotationTransition
reference¶
-
class
transitions.
NodeRotationTransition
(advance_value, duration, advance_method=AttributeTransitionMethod.set, loops=1, back_and_forth=False, easing=Easing.none)¶ Use this transition to change Node’s rotation gradually over time, towards given advance_value or by given advance_value.
The
advance_value
param must be a float and is the target rotation value (or rotation change value), in radians.Refer to the Common transition parameters and Examples sections for information on other parameters used by the transition.
NodeScaleTransition
reference¶
-
class
transitions.
NodeScaleTransition
(value, duration, advance_method=AttributeTransitionMethod.set, loops=1, back_and_forth=False, easing=Easing.none)¶ Use this transition to change Node’s scale gradually over time, towards given advance_value or by given advance_value.
The
advance_value
param must be ageometry.Vector
and is the target scale value (or scale change value) for X and Y axis respectively.Refer to the Common transition parameters and Examples sections for information on other parameters used by the transition.
NodeColorTransition
reference¶
-
class
transitions.
NodeColorTransition
(value, duration, advance_method=AttributeTransitionMethod.set, loops=1, back_and_forth=False, easing=Easing.none)¶ Use this transition to change Node’s scale gradually over time, towards given advance_value or by given advance_value.
The
advance_value
param must be acolors.Color
and is the target color value (or color change value).Note that each component of the color (R, G, B, and A) is trimmed to a 0-1 range, so when using
advance_method=AttributeTransitionMethod.set
oradvance_method=AttributeTransitionMethod.multiply
which would result in R G B or A going above 1 or below 0 - the value will be capped at 1 and 0 respectively.Refer to the Common transition parameters and Examples sections for information on other parameters used by the transition.
BodyNodeVelocityTransition
reference¶
-
class
transitions.
BodyNodeVelocityTransition
(value, duration, advance_method=AttributeTransitionMethod.set, loops=1, back_and_forth=False, easing=Easing.none)¶ Use this transition to change BodyNode’s velocity gradually over time, towards given advance_value or by given advance_value.
The
advance_value
param must be ageometry.Vector
and is the target velocity value (or velocity change value).Refer to the Common transition parameters and Examples sections for information on other parameters used by the transition.
BodyNodeAngularVelocityTransition
reference¶
-
class
transitions.
BodyNodeAngularVelocityTransition
(value, duration, advance_method=AttributeTransitionMethod.set, loops=1, back_and_forth=False, easing=Easing.none)¶ Use this transition to change BodyNode’s angular velocity gradually over time, towards given advance_value or by given advance_value.
The
advance_value
param must be a number and is the target angular velocity value (or angular velocity change value), in radiansRefer to the Common transition parameters and Examples sections for information on other parameters used by the transition.
NodeSpriteTransition
reference¶
-
class
transitions.
NodeSpriteTransition
(sprites, duration, loops=1, back_and_forth=False, easing=Easing.none)¶ Use this transition to create animations. The transition will change Node’s sprite over time specified by the
duration
parameter, iterating through sprites list specified by thesprites
parameter.The
sprites
must be an iterable holdingsprites.Sprite
instances. To cut a spritesheet file into individual sprites (individual frames) use the utility functionsprites.split_spritesheet()
The
loops
andback_and_forth
parameters work normally - refer to the Common transition parameters section for more information on those parameters.
NodeZIndexSteppingTransition reference
¶
-
class
transitions.
NodeZIndexSteppingTransition
(z_index_list, duration, loops=1, back_and_forth=False, easing=Easing.none)¶ Allows to change z_index of a node over time.
The
z_index_list
must be an iterable with z_index values.
NodeTransitionsSequence
reference¶
-
class
transitions.
NodeTransitionSequence
(transitions, loops=1, back_and_forth=False)¶ A wrapping container used to chain transitions into a sequence. The sequence will run one transition at a time, next one being executed when the previous one finishes.
The
transitions
parameter is an iterable of transitions.The iterable can include a list of ‘atomic’ transitions such as
NodePositionTransition
,NodeScaleTransition
,NodeColorTransition
etc. as well as otherNodeTransitionSequence
, orNodeTransitionsParallel
thus building a more complex structure.The loops and back_and_forth parameters work normally, but are applied to the whole sequence.
See the Examples sections for a sample code using NodeTransitionSequence.
NodeTransitionsParallel
reference¶
-
class
transitions.
NodeTransitionsParallel
(transitions, loops=1, back_and_forth=False)¶ A wrapping container used to make transitions run in parallel.
The
transitions
parameter is an iterable of transitions which will be executed simultaneously.The iterable can include a list of ‘atomic’ transitions such as
NodePositionTransition
,NodeScaleTransition
,NodeColorTransition
etc. as well as otherNodeTransitionSequence
, orNodeTransitionsParallel
thus building a more complex structure.You may have two contradictory transitions running in parallel, for example two
NodePositionTransition
trying to change node position in opposite directions. Contrary to intuition, they won’t cancel out (regardless of advance_method beingadd
orset
). If there are two or more transitions of the same type running in paralel, then the one which is later in the list will be used and all the preceding ones will be ignored.Since transitions runing in parallel may have different durations, the
loops
parameter is using the following logic: The longest duration is considered the “base” duration. Transitions whose duration is shorter than the base duration will wait (doing nothing) when they complete, until the one with the “base” duration ends. When the “base” transition ends, the new loop begins and all transitions start running in parallel again.The
back_and_forth=True
is using the same logic: the engine will wait for the longest transition to end before playing all parallel transitions backwards.See the Examples sections for a sample code using NodeTransitionsParallel.
Like all other transitions, NodeTransitionsParallel is immutable. That causes problems when you want transitions to be managed independently. Consider a situation where you want to have a Node with sprite animation (NodeSpriteTransition) and some other transition (e.g. NodePositionTransition), both running simuntaneously. Suppose you do that by wrapping the two transitions in
NodeTransitionsParallel
. Now, if you want to change just the sprite animation transition without changing the state of the position transition (a perfectly valid case in many 2D games), you won’t be able to do that because NodeTransitionsParallel is immutable!To solve that problem, you should use
NodeTransitionsManager
- it allows running and managing multiple simultaneous transitions on a Node truly independently from each other.
NodeTransitionDelay
reference¶
NodeTransitionCallback
reference¶
-
class
transitions.
NodeTransitionCallback
(callback_func)¶ Use this transition to get your own function called at a specific moment in a transitions sequence. A typical use case is to find out that a transition has ended.
The
callback_func
must be a callable.See the Examples sections for a sample code using NodeTransitionCallback
NodeCustomTransition
reference¶
-
class
transitions.
NodeCustomTransition
(prepare_func, evaluate_func, duration, loops=1, back_and_forth=False, easing=Easing.none)¶ Use this class to write your own transition.
prepare_func
must be a callable. It will be called once, before the transition is played. It receives one parameter - a node. It can return any value, which will later be used as input toevaluate_func
evaluate_func
must be a callable. It will be called on each frame and it’s the place where you should implement the transition logic. It will receive three parameters:state
,node
andt
. Thestate
is a value you have returned in theprepare_func
callable. Thenode
is a node which is transitioning. Thet
parameter is a value between 0 and 1 which indicates transition time duration progress.The
loops
andback_and_forth
paramters behave normally - see the Common transition parameters section.custom_transition = NodeCustomTransition( lambda node: {'positions': [ Vector(random.uniform(-100, 100), random.uniform(-100, 100)) for _ in range(10) ]}, lambda state, node, t: setattr( node, 'position', state['positions'][min(int(t * 10), 9)], ), 10., loops=5, )
NodeTransitionsManager
reference¶
-
class
transitions.
NodeTransitionsManager
¶ Node Transitions Manager is accessed by the transitions_manager property on a
nodes.Node
. It allows to run multiple transitions on a node at the same time. UnlikeNodeTransitionsParallel
, which also runs multiple transitions simultaneously, the transitions managed by the NodeTransitionsManager are truly isolated. It means you can manage them (stop or replace them) individually not affecting other running transitions. This is not possible with transitions insideNodeTransitionsParallel
, because the wrapper is immutable.The manager offers a simple dictionary-like interface with two methods:
get()
andset()
to access and set transitions by a string key.Note that the transition manager is used when you set transition on a Node via the transition property. That transition can be accessed via
get('__default__')
Similarly to
NodeTransitionsParallel
when you set two contradictory transitions of the same type to run on the manager (for example position transitions that pull the node in two opposite direction) - they will not cancel out. One of them will ‘dominate’. It is undetermined which one will dominate therefore it’s recommended not to compose transitions that way (why would you want to do it anyway?).
-
NodeTransitionsManager.
get
(transition_name)¶ Gets a transition by name (a string).
Node.transitions_manager.get('__default__')
is an equivalent of Node.transition getter.
-
NodeTransitionsManager.
set
(transition_name, transition)¶ Sets a transition with a specific name (a string). The
transition
object can be any transition, either ‘atomic’ or a serial / parallel combo.Node.transitions_manager.set('__default__', transition)
is an equivalent of Node.transition setter.node = Node(position=Vector(15, 60)) node.transitions_manager.set('my_transition', NodePositionTransition(Vector(100,100), duration=0.300, loops=0)) node.transitions_manager.set('other_transition', NodeRotationTransition(math.pi/2)) node.transitions_manager.set('can_use_sequence_coz_why_not', NodeTransitionsSequence([ NodeScaleTransition(Vector(2, 2), 1.), NodeTransitionDelay(2.), NodeColorTransition(Color(0.5, 1, 0, 1), 3.)], loops=2, back_and_forth=True))
AttributeTransitionMethod
reference¶
-
class
transitions.
AttributeTransitionMethod
¶
Enum type used to identify value advance method when using transitions
Available values are:
AttributeTransitionMethod.set
AttributeTransitionMethod.add
AttributeTransitionMethod.multiply