Animating AI Player Actions
Animating AI player actions is handled by the AIPlayerActionAnimationManager, referred to as AIPAAM
. This manager implements the IAsyncActionProcessor interface.
When the GameCore
processes an action, it checks if the current player is an AI player. If so, it passes the action to AIPAAM
, which animates the action and waits until the animation is complete.
To animate actions, various classes implement the IAIPlayerActionAnimator generic interface, which defines the AnimateAsync
method. The AIPAAM
uses these animators to perform the animations. Additionally, several IDisposable
helper classes are used to keep the code organized and safe.
Example: Animating a ChangeTetrominoAction
First, the player needs to click on the Change Tetromino button in the action zone.
The AIPAAM
uses a ActionZonesManager.DisposableButtonSelector to do so.
Then it redirects the job to the PieceZoneManager, which implements the IAIPlayerActionAnimator<ChangeTetrominoAction>
interface. It uses two disposables to animate the action.
- The TetrominoButton.DisposableButtonSelector to visually select the piece to give away and the piece to take.
- The (private)
PieceZoneManager.DisposableButtonHighlighter
to highlight the possible trade options.
Animating Reward Selection
Reward selection is a bit different. With regular actions, the GameSessionManager
calls GameAction.AcceptAsync(AIPAAM)
before GameCore.ProcessActionAsync(GameAction)
, so the AIPAAM
can animate the action before it is processed and the game graphics respond to it.
However, reward selection takes place inside the GameCore.ProcessActionAsync
method. When a player completes a puzzle, the GameActionProcessor processing the action calls the player's GetRewardAsync
method. This method returns the piece the player wants to take as a reward. We need to animate this selection before the GameCore.ProcessActionAsync
method returns — otherwise, the graphics would already reflect the updated game state after the reward is chosen, making the animation ineffective.
Thankfully, the Project L Core library provides a bunch of game listener interfaces, one of which is the IPlayerStatePuzzleFinishedAsyncListener. When a puzzle is finished by a player, the OnPuzzleFinishedAsync(FinishedPuzzleInfo)
method of all listeners subscribed to his PlayerState
is called and awaited. This happens before any changes are made to his PlayerState and the GameState.
The AIPAAM
implements this interface to animate the reward selection using the PieceZoneManager
in a very similar way as with the ChangeTetrominoAction
.