4. The file webapp/names.py

This file is used for boilerplate web app features such as the game tutorial and the game’s “About…” page. These names are separated to help ensure consistency from game to game in the order they are defined. This file is also used for constants, metadata, and initialisation calculations needed in many games. Overall, using this file helps to make the main web app file webapp/__init__.py a little less cluttered.

4.1. Constants

All constants the developer creates for web app version of their game should be defined in webapp/names.py. For example, in the game Just Addition, the file justaddition/webapp/names.py defines

#
# Module-level names specific to this game
#

IM_WIDTH: int = 50
"""The width of each symbol in the game instance area."""

IM_HEIGHT: int = round(IM_WIDTH * 1.5)
"""The height of each symbol in the game instance area."""

which are then imported into justaddition/webapp/__init__.py using

from .names import (
    IM_HEIGHT,
    IM_WIDTH,
    # Other imports hidden for this example
    )

4.2. The game logo, icon, and background

This subsection explains three basic images required for each game: a game logo, a game icon, and a game background.

4.2.1. The name GAME_LOGO_FNAME

(defined in webapp/names.py)

The game logo is an image that graphically displays the name of the game. It is displayed at the top of the screen when the player plays the game, and also appears under the game icon in the game menu. The game logo can use any image file format recognised by web browsers.

There are many free websites that offer generation of images from text. Make sure to choose one that allows unrestricted use of the image (for example, if it says that it is only allowed for personal use, then it is not an appropriate service). Examples include Cool Text: Logo and Graphics Generator and Text Maker +.

The default game logo file at x/resources/images/game_logo.png should be deleted (where x is the name of the game), and the new logo saved into this directory.

The name GAME_LOGO_FNAME in file webapp/names.py should be updated to reflect the new filename of the game logo, if different.

4.2.2. The name GAME_ICON_FNAME

(defined in webapp/names.py)

See also

Section “Graphics” has information about where to download SVGs to create your game’s graphics.

The game icon is an image that appears in the game menu to provide a reminder to players what the game is about. Ideally, it should re-use graphics used in the game.

The default game icon file at x/resources/images/game_icon.svg should be deleted (where x is the name of the game), and the new icon saved into this directory.

The name GAME_ICON_FNAME in file webapp/names.py should be updated to reflect the new filename of the game icon, if different.

4.2.3. The name GAME_BACKGROUND_FNAME

(defined in webapp/names.py)

See also

Section “Graphics” has information about where to download game background images.

The game background image appears in the background while the game is being played. The choice of image should in some way be related to the game, but it should not be so detailed that it makes the game’s graphics difficult to see.

The default game background image file at x/resources/images/background.svg should be deleted (where x is the name of the game), and the new image saved into this directory.

The name GAME_BACKGROUND_FNAME in file webapp/names.py should be updated to reflect the new filename of the game background, if different.

4.2.4. Example

In file justaddition/webapp/names.py:

GAME_LOGO_FNAME = 'game_logo.png'
"""The filename of the logo that appears at the top of each game round.
The logo should graphically display the game name."""

GAME_ICON_FNAME = 'game_icon.svg'
"""The filename of a small picture that represents the game in the game
menu."""

GAME_BACKGROUND_FNAME = 'background.jpg'
"""The name plus extension of the background image. The path should not
be specified."""

4.3. Other graphics

It is assumed that all other graphics used in games will be SVGs and the default graphic file extension reflects this:

_IM_EXT = '.svg'
"""Graphic filename extension."""

4.4. Creating the “About…” page

(defined in webapp/names.py)

Edit the function populate_about_page() to specify the website that was used to generate the logo image, and the website(s) used during the creation the game icon, background image, and in-game images. Even if images were created by the game author, include all websites from which component images were taken.

All other parts of the “About…” page are generated automatically.

Note

The “About…” page is created at game load time (when the player clicks the game icon in the menu) through a call in webapp/__init__.py as follows

# Populate an "About..." page in the webapp
populate_about_page(developers=__credits__, date=__date__)

It uses this slightly awkward approach to re-use the authors and modification date from webapp/__init__.py while avoiding circular import dependencies.

4.4.1. Example

In the function populate_about_page() defined in file justaddition/webapp/names.py it states that cooltext.com was used for the logo, and that pixabay.com and openclipart.org were used to source the game graphics:

logo=['cooltext'],
images=['pixabay', 'openclipart'],

4.5. Creating the tutorial

See also

Creating a tutorial requires one to construct a TextImageSeq object. Read about this class here.

The tutorial that you create for your game should be aimed at the child player. It should not be too cluttered and should not confuse a child by having pictures of buttons that a child might be fooled into clicking. Each tutorial should have two examples, a very easy one and a harder one.

A tutorial consists of interleaved passages of text and images. To create a tutorial, one must format the text and images as a TextImageSeq and assign it to name TUTORIAL_TEXT_IM_SEQ. On game startup, the CTGames framework will recognise that you game has defined this name and will use it to create an appropriate tutorial page for your game.

To create a tutorial that consists of some text, below that an image, below that some more text, and below that another image, one should create a TextImageSeq object of the following form:

TUTORIAL_TEXT_IM_SEQ = TextImageSeq(
    text_seq=['some text\n', '\nmore text\n'],
    im_seq=[
        'ctgames/x/resources/images/image.png',
        'ctgames/x/resources/images/another_image.png',
        ],
    im_height=100,
    )

where x is the directory of the game. The \n carriage return characters in the text strings ensure that the text and images appear below each other; leaving them out would put them all side-by-side, only wrapping when the width of the window.

You can leave out im_height and im_width to show each image at its full resolution. If you leave out one of them the web browser will choose a sensible value for each image that displays that image at its original aspect ratio. If you want a separate height for each image, pass a list of values. For example, im_height=[100, 200, 300] means set the first image to a height of 100, the second image to a height of 200, and the third (and all subsequent images) to a height of 300.

If you want more control over the positioning of the text and images, for example if you want the text and images to be side-by-side, and/or you wish to style the text, then you should use the attributes text_table and im_table rather than text_seq and im_seq. These two attributes should be given lists of lists, where each list is a row in the table. For example, to create a tutorial that consists of a 2x2 grid, with on each row some text on the left and an image on the right, one should create a TextImageSeq object of the following form:

TUTORIAL_TEXT_IM_SEQ = TextImageSeq(
    text_table=[['Text', None], ['''More text.''', None]],
    im_table=[
        [None, 'ctgames/x/resources/images/image.png'],
        [None, 'ctgames/x/resources/images/another_image.png'],
        ],
    im_height=100,
    cell_border=1,
    cell_padding=20,
    table_style={'font-size': '24px'},
    )

where x is the directory of the game. Here, no \n carriage return characters are needed in the text strings because the grid takes care of separating the elements. The attributes cell_border, cell_padding, and table_style change the appearance of each cell in the table, but they are optional and these lines of code can be deleted. The attribute table_style takes any dict of CSS styling directives and so is very flexible.

If a sequence is passed to im_height, e.g. im_height=[100, 200, 300], then these values will be repeated for each row in the table. If you want the image dimensions to vary between rows in a table, then rather than im_table, use the attribute dom_elem_table to specify a table of images so that dimensions can be independently specified for each image.

4.5.1. Examples

In file justreverse/webapp/names.py a tutorial is defined that consists of text and images below each other without any styling except to specify a common height for each image:

_TUT_IM_HEIGHT = 200
"""We only specify the height of each image and let the browser
determine the width from the image."""

_TUT_PATH: str = IM_PATH_TEMPLATE.format(MODULE_NAME, '{}', '.png')
"""The path in which images for the tutorial can be found, parameterised
by the image's filename."""

_TUT_TEXT_SEQ = [
    '''In Just Reverse you must put the list in reverse order.
    Starting from right to left, you need to read each block and
    click the right button.\n\n''',
    '''\n\nHere we can see from right to left the blocks are in the
    order BAABA.\n\n''',
    ]

_TUT_IM_FNAMES = ['tutorial', 'tutorial_solved']
_TUT_IM_SEQ = [_TUT_PATH.format(fn) if fn else fn for fn in _TUT_IM_FNAMES]

TUTORIAL_TEXT_IM_SEQ = TextImageSeq(
    text_seq=_TUT_TEXT_SEQ,
    im_seq=_TUT_IM_SEQ,
    im_height=_TUT_IM_HEIGHT,
    )
"""The object used to populate the tutorial section of this game."""

In file password/webapp/names.py a tutorial is defined that consists of a table of text and images. The first row of the table consists of two cells with text (the first element of _TUT_TEXT_TABLE is a list containing two strings and the first element of _TUT_IM_TABLE is a list containing None), the second row of the table has text in the first cell and an image in the second (the second element of _TUT_TEXT_TABLE is a list containing one string and None and the second element of _TUT_IM_TABLE is a list containing None and an image). The third row of the table follows the same arrangement as the second row:

_TUT_IM_HEIGHT = 300
"""We only specify the height of each image and let the browser
determine the width from the image."""

_TUT_PATH: str = IM_PATH_TEMPLATE.format(MODULE_NAME, '{}', '.png')
"""The path in which images for the tutorial can be found, parameterised
by the image's filename."""

_TUT_TEXT_TABLE = [
    [
        '''In this game, you must help Percy Pig remember the password
        to his treasure chest.''',
        '''To do this you must find the correct pattern of letters that
        match the shapes on the lock.''',
        ],
    [
        '''In this first example we see that there are 4 shapes on the
        lock. Looking at the possible answers we see they are all of
        different lengths and only one has 4 letters. So the answer must
        be B.''',
        None,
        ],
    [
        '''The second example is more complex. All of the answers have
        the correct number of letters. If we look carefully, we can see
        there are two circles. That means the answer must have two of
        the same letter in the same place the circles appear, so the
        answer must be A.''',
        None,
        ],
    ]

_TUT_IM_FNAMES = [None, 'tutorial_easy', 'tutorial']
_TUT_IM_TABLE = [
    [None, _TUT_PATH.format(fn)] if fn else [fn] for fn in _TUT_IM_FNAMES
    ]

TUTORIAL_TEXT_IM_SEQ = TextImageSeq(
    text_table=_TUT_TEXT_TABLE,
    im_table=_TUT_IM_TABLE,
    im_height=_TUT_IM_HEIGHT,
    cell_border=1,
    cell_padding=20,
    table_style={'font-size': '24px'},
    )
"""The object used to populate the tutorial section of this game."""