2. Guidelines for animations in web app games

This section gives some guidelines on how to embellish one’s fully-functional and graphical CTGames web app game with animations.

There is only one subsection so far

Constructing an animation in logic.py” that explains why, for programming-style CTGames games, the animation should be calculated in the logic.py file, and gives examples.

2.1. Constructing an animation in logic.py

Some CTGames games are programming-style games, which have the property that there is more than one correct answer (potentially an unbounded amount of answers) and that it is only at the player answer submission stage (when the player’s answer is checked for correctness) that an appropriate animation can be constructed. Our experience of coding programming-style games with the CTGames framework leads us to recommend that one should construct the logic of the animation (i.e. a list of bespoke str keywords encoding the animation steps) in logic.py side-by-side with the code that tests the correctness of the player’s answer.

Tip

CTGames games that use logic.py to compute whether the player’s answer is correct or not, and then use a separate function in webapp/__init__.py to construct an animation to show why the player’s answer is correct/incorrect, are effectively repeating the same computation. This is inefficient and runs the risk (for complicated games) of a hard-to-find bug in one of the functions causing the two functions to disagree (e.g. the logic.py file says the player’s answer is wrong but the webapp/__init__.py animation fails to demonstrate this).

In file dungeonescape/logic.py, the function process_input_and_solve_task() constructs an animation sequence, consisting of a list of 'push' and 'pop' strings, with

# Note: this code has simplified from that in the game for explanatory purposes

OPEN_BRACKETS = ('[', '{', '(', '<'}
"""The mapping from open brackets to appropriate closing brackets."""

MATCHING_BRACKETS = {']': '[', '}': '{', ')': '(', '>': '<'}
"""Inverse of the mapping (closing brackets to opening brackets)."""

stack = []
"""The keys in the stack (may contain duplicates)."""

# Building up the animation based on player's selected option
animation = []
for key_type in players_answer:
    if key_type in OPEN_BRACKETS:
        stack.append(key_type)
        animation.append('push')
    else:
        if stack and stack.pop() == MATCHING_BRACKETS[key_type]:
            animation.append('pop')
        else:
            break

The code determines whether name players_answer contains appropriately matching brackets. At the point that matching brackets are not found, the animation sequence finishes. Properties of the animation sequence (including its length) can be used to determine whether the player’s answer is correct, and so this is an example of constructing the animation sequence side-by-side with checking the player’s answer.