In order to allow the map to be larger than the screen, or shaped differently than a plain rectangle we use a CAMERA_VIEW dictionary. Just like the full map dictionary, the keys are (x,y) coordinate tuples and the values are tile type strings. But unlike the full map dictionary the CAMERA_VIEW is always the exact same size and shape 10x8 tiles in this game, which matches up with the screen size on the PyGamer and PyBadge devices.

There are two functions related to camera management: set_camera_view() and draw_camera_view().

set_camera_view() will build the CAMERA_VIEW dictionary based on the current game state. It accepts parameters for x, y starting point within the map as well as width and height. The example game will always use 10, 8 for the size so it fits perfectly on the 160x128 pixel screen. If you wanted to adapt the game code to work with a different sized screen you could change these values.

draw_camera_view() will draw the current contents of the CAMERA_VIEW dictionary onto the screen. It will also check for the existence of and draw any entities that are within the coordinates of the CAMERA_VIEW.

In this game, the camera will always stay centered on the player because we reference the player location in the x, and y value parameters when set_camera_view() is called.

Here are the set_camera_view() and draw_camera_view() function definitions:

# set the appropriate tiles into the CAMERA_VIEW dictionary
# based on given starting coords and size
def set_camera_view(startX, startY, width, height):
    global CAMERA_OFFSET_X
    global CAMERA_OFFSET_Y
    # set the offset variables for use in other parts of the code
    CAMERA_OFFSET_X = startX
    CAMERA_OFFSET_Y = startY

    # loop over the rows and indexes in the desired size section
    for y_index, y in enumerate(range(startY, startY + height)):
        # loop over columns and indexes in the desired size section
        for x_index, x in enumerate(range(startX, startX + width)):
            # print("setting camera_view[%s,%s]" % (x_index,y_index))
            try:
                # set the tile at the current coordinate of the MAP into the CAMERA_VIEW
                CAMERA_VIEW[x_index, y_index] = GAME_STATE["CURRENT_MAP"][x, y]
            except KeyError:
                # if coordinate is out of bounds set it to floor by default
                CAMERA_VIEW[x_index, y_index] = "floor"


# draw the current CAMERA_VIEW dictionary and the GAME_STATE['ENTITY_SPRITES_DICT']
def draw_camera_view():
    # list that will hold all entities that have been drawn based on their MAP location
    # any entities not in this list should get moved off the screen
    drew_entities = []
    # print(CAMERA_VIEW)

    # loop over y tile coordinates
    for y in range(0, SCREEN_HEIGHT_TILES):
        # loop over x tile coordinates
        for x in range(0, SCREEN_WIDTH_TILES):
            # tile name at this location
            tile_name = CAMERA_VIEW[x, y]

            # if tile exists in the main dictionary
            if tile_name in TILES.keys():
                # if there are entity(s) at this location
                if (x + CAMERA_OFFSET_X, y + CAMERA_OFFSET_Y) in GAME_STATE[
                    "ENTITY_SPRITES_DICT"
                ]:
                    # default background for entities is floor
                    castle[x, y] = TILES["floor"]["sprite_index"]

                    # if it's not the player
                    if tile_name != "player":
                        # loop over all entities at this location
                        for entity_obj_at_tile in GAME_STATE["ENTITY_SPRITES_DICT"][
                            x + CAMERA_OFFSET_X, y + CAMERA_OFFSET_Y
                        ]:
                            # set appropriate x,y screen coordinates 
                            # based on tile coordinates
                            ENTITY_SPRITES[
                                int(entity_obj_at_tile["entity_sprite_index"])
                            ].x = (x * 16)
                            ENTITY_SPRITES[
                                int(entity_obj_at_tile["entity_sprite_index"])
                            ].y = (y * 16)

                            # add the index of the entity sprite to the draw_entities 
                            # list so we know not to hide it later.
                            drew_entities.append(
                                entity_obj_at_tile["entity_sprite_index"]
                            )

                else:  # no entities at this location
                    # set the sprite index of this tile into the CASTLE dictionary
                    castle[x, y] = TILES[tile_name]["sprite_index"]

            else:  # tile type not found in main dictionary
                # default to floor tile
                castle[x, y] = TILES["floor"]["sprite_index"]

            # if the player is at this x,y tile coordinate accounting for camera offset
            if GAME_STATE["PLAYER_LOC"] == ((x + CAMERA_OFFSET_X, y + CAMERA_OFFSET_Y)):
                # set player sprite screen coordinates
                GAME_STATE["PLAYER_SPRITE"].x = x * 16
                GAME_STATE["PLAYER_SPRITE"].y = y * 16

    # loop over all entity sprites
    for index in range(0, len(ENTITY_SPRITES)):
        # if the sprite wasn't drawn then it's outside the camera view
        if index not in drew_entities:
            # hide the sprite by moving it off screen
            ENTITY_SPRITES[index].x = int(-16)
            ENTITY_SPRITES[index].y = int(-16)

In this game, the camera will always stay mostly centered on the player, because we reference the player location in the x, and y value parameters when set_camera_view() is called. The max and min functions are used to minimize the amount of "outside the map" area that we show.

Here is the code inside the main loop that calls set_camera_view() and draw_camera_view():

# inside main game loop:
  set_camera_view(
    max(min(GAME_STATE['PLAYER_LOC'][0]-4,GAME_STATE['MAP_WIDTH']-SCREEN_WIDTH_TILES),0),
    max(min(GAME_STATE['PLAYER_LOC'][1]-3,GAME_STATE['MAP_HEIGHT']-SCREEN_HEIGHT_TILES),0),
    10,
    8
  )
# draw the camera
draw_camera_view()

This guide was first published on Jun 10, 2020. It was last updated on Jun 10, 2020.

This page (Camera View) was last updated on Mar 16, 2021.

Text editor powered by tinymce.