Animations

Table of contents
  1. SequentialAnimation
  2. ParallelAnimation
  3. DelayAnimation
  4. MovementAnimation
  5. RotationAnimation
  6. FlipAnimation
  7. RandomizeAnimation
  8. DiceAnimation

In this section the different types of animations in the BGW framework are shown. Visuals are mostly used to move game elements or change their Visual. Additionally, the DelayAnimation can be used to delay code execution to enable the player to see what is happening on the table.

The full example of the gif above can be found here:

View it on GitHub.

Each Animation has a duration, a running attribute and an onFinished EventHandler that gets invoked after the animation has finished.

Note: UI changes may not be done directly from this asynchronous onFinished environment. Use BoardGameApplication#runOnGUIThread to alter properties of ComponentViews!

SequentialAnimation

A SequentialAnimation is an Animation that consists of multiple animations, that get played in sequence. This is useful to combine multiple animations into a single one. An example on how to create and play a SequentialAnimation can be found below:

gameScene.playAnimation(
    SequentialAnimation(
        DelayAnimation(duration = 1000).apply { 
            onFinished = { println("First DelayAnimation finished!") }
        },
        DelayAnimation(duration = 2000).apply { 
            onFinished = { println("Second DelayAnimation finished!") }
        },
    ).apply { 
        onFinished = { println("SequentialAnimation finished!") }
    }
)

The resulting SequentialAnimation will play for 3000ms and print some information on which Animations have finished playing.

ParallelAnimation

A ParallelAnimation is an Animation that consists of multiple animations, that get played in parallel. This is useful to combine multiple animations into a single one. An example on how to create and play a ParallelAnimation can be found below:

gameScene.playAnimation(
    ParallelAnimation(
        DelayAnimation(duration = 1000).apply { 
            onFinished = { println("First DelayAnimation finished!") }
        },
        DelayAnimation(duration = 2000).apply { 
            onFinished = { println("Second DelayAnimation finished!") }
        },
    ).apply { 
        onFinished = { println("ParallelAnimation finished!") }
    }
)

The resulting ParallelAnimation will play for 2000ms and print some information on which animations have finished playing.

DelayAnimation

A DelayAnimation does nothing in the application window besides calling onFinished after the given amount of time (duration parameter). This timer runs asynchronously, so it can run while the player is playing. To add a delay between moves in which the user should not be able to interact with the scene, the method BoardGameScene#lock has to be called before playing the animation and the method BoardGameScene#unlock in onAnimationFinished. An example for this locking mechanism can be found below:

gameScene.lock()
gameScene.playAnimation(DelayAnimation(duration = 2000).apply {
  onFinished = {
    //Do stuff here
    gameScene.unlock()
  }
})

MovementAnimation

A MovementAnimation moves a GameComponentView. The movement can be passed as fromX/toX, fromY/toY or relative to the current position with byX/byY.

NOTE: The Animation only moves the component in the current Scene and does not update its position. The Component will snap back upon next refresh if the new position is not set in onAnimationFinished, which is the suggested way of usage.

gameScene.playAnimation(
  MovementAnimation(
    componentView = component,
    byX = 0,
    byY = -50,
    duration = 1000
  ).apply { 
    onFinished = {
      component.posY -= 50
    }
  }
)

Additionally, a component can be moved to another component’s location. This is for example useful to animate moving cards onto a card stack:

gameScene.playAnimation(
  MovementAnimation.toComponentView(
    componentView = card,
    toComponentViewPosition = cardStack,
    scene = gameScene,
    duration = 1000
  ).apply { 
    onFinished = {
      card.removeFromParent()
      cardStack.add(card)
    }
  }
)

RotationAnimation

A RotationAnimation rotates a GameComponentView. The rotation can be passed as fromAngle/toAngle or relative to the current rotation with byAngle.

NOTE: The Animation only rotates the component in the current Scene and does not update its rotation. The Component will snap back upon next refresh if the new rotation is not set in onAnimationFinished, which is the suggested way of usage.

gameScene.playAnimation(
  RotationAnimation(
    componentView = component,
    byAngle = 180,
    duration = 1000
  ).apply { 
    onFinished = {
      component.rotation = (component.rotation + 180) % 360
    }
  }
)

FlipAnimation

A FlipAnimation switches between two visuals in a flipping-like animation. The animation sets the fromVisual and then switches to the toVisual.

NOTE: The Animation only switches the visuals visually. The Visual will revert to the currentVisual upon next refresh if the new visual is not set in onAnimationFinished, which is the suggested way of usage.

gameScene.playAnimation(
  FlipAnimation(
    componentView = card,
    fromVisual = backSide,
    toVisual = frontSide,
    duration = 1000
  ).apply { 
    onFinished = {
      card.visual = frontSide
    }
  }
)

RandomizeAnimation

A RandomizeAnimation randomly switches between the given visuals. The time each visual is visible can be set by passing steps, which is calculated like the following: steps: time = duration / steps. The animation sets the toVisual as the last step in order to control what the resulting visual of this animation is.

NOTE: The Animation only switches the visuals visually. The Visual will revert to the currentVisual upon next refresh if the new visual is not set in onAnimationFinished, which is the suggested way of usage.

gameScene.playAnimation(
  RandomizeAnimation(
    componentView = card,
    visual = allCardFaces,
    toVisual = allCardFaces[3],
    duration = 1000
  ).apply { 
    onFinished = {
      card.visual = allCardFaces[3]
    }
  }
)

DiceAnimation

A DiceAnimation behaves like a RandomizeAnimation specifically for dices. As the visuals got passed as parameter on Dice creation only the resulting side as zero-based index needs to be passed. The animation sets the toSide as the last step in order to control what the resulting visual of this animation is.

NOTE: The Animation only switches the visuals visually. The Visual will revert to the currentVisual upon next refresh if the new visual is not set in onAnimationFinished, which is the suggested way of usage.

gameScene.playAnimation(
  DiceAnimation(
    componentView = dice,
    toSide = 3,
    duration = 1000
  ).apply { 
    onFinished = {
      card.currentSide = 3
    }
  }
)