Module pyboy.api.sprite

This class presents an interface to the sprites held in the OAM data on the Game Boy.

Expand source code
#
# License: See LICENSE.md file
# GitHub: https://github.com/Baekalfen/PyBoy
#
"""
This class presents an interface to the sprites held in the OAM data on the Game Boy.
"""

from pyboy.core.lcd import LCDCRegister

from .constants import LCDC_OFFSET, OAM_OFFSET, SPRITES
from .tile import Tile


class Sprite:
    def __init__(self, mb, sprite_index):
        """
        This class presents an interface to the sprites held in the OAM data on the Game Boy.

        The purpose is to make it easier to interpret events on the screen, in order to program a bot, or train an AI.

        Sprites are used on the Game Boy for enemy and player characters, as only sprites can have transparency, and can
        move at pixel-precision on the screen. The other method of graphics -- tile maps -- can only be placed in a
        grid-size of 8x8 pixels precision, and can have no transparency.

        Sprites on the Game Boy are tightly associated with tiles. The sprites can be seen as "upgraded" tiles, as the
        image data still refers back to one (or two) tiles. The tile that a sprite will show, can change between each
        call to `pyboy.PyBoy.tick`, so make sure to verify the `Sprite.tile_identifier` hasn't changed.

        By knowing the tile identifiers of players, enemies, power-ups and so on, you'll be able to search for them
        using `pyboy.sprite_by_tile_identifier` and feed it to your bot or AI.
        """
        assert 0 <= sprite_index < SPRITES, f"Sprite index of {sprite_index} is out of range (0-{SPRITES})"
        self.mb = mb
        self._offset = sprite_index * 4

        self._sprite_index = sprite_index
        """
        The index of the sprite itself. Beware, that this only represents the index or a "slot" in OAM memory.
        Many games will change the image data of the sprite in the "slot" several times per second.

        Returns
        -------
        int:
            unsigned tile index
        """

        # Documentation states the y coordinate needs to be subtracted by 16
        self.y = self.mb.getitem(OAM_OFFSET + self._offset + 0) - 16
        """
        The Y-coordinate on the screen to show the Sprite. The (x,y) coordinate points to the top-left corner of the sprite.

        Returns
        -------
        int:
            Y-coordinate
        """

        # Documentation states the x coordinate needs to be subtracted by 8
        self.x = self.mb.getitem(OAM_OFFSET + self._offset + 1) - 8
        """
        The X-coordinate on the screen to show the Sprite. The (x,y) coordinate points to the top-left corner of the sprite.

        Returns
        -------
        int:
            X-coordinate
        """

        # Sprites can only use unsigned tile indexes in the lower tile data.
        self.tile_identifier = self.mb.getitem(OAM_OFFSET + self._offset + 2)
        """
        The identifier of the tile the sprite uses. To get a better representation, see the method
        `pyboy.api.sprite.Sprite.tiles`.

        For double-height sprites, this will only give the identifier of the first tile. The second tile will
        always be the one immediately following the first (`tile_identifier + 1`).

        Returns
        -------
        int:
            unsigned tile index
        """

        attr = self.mb.getitem(OAM_OFFSET + self._offset + 3)
        self.attr_obj_bg_priority = _bit(attr, 7)
        """
        To better understand this values, look in the [Pan Docs: VRAM Sprite Attribute Table
        (OAM)](https://gbdev.io/pandocs/OAM.html).

        Returns
        -------
        bool:
            The state of the bit in the attributes lookup.
        """

        self.attr_y_flip = _bit(attr, 6)
        """
        To better understand this values, look in the [Pan Docs: VRAM Sprite Attribute Table
        (OAM)](https://gbdev.io/pandocs/OAM.html).

        Returns
        -------
        bool:
            The state of the bit in the attributes lookup.
        """

        self.attr_x_flip = _bit(attr, 5)
        """
        To better understand this values, look in the [Pan Docs: VRAM Sprite Attribute Table
        (OAM)](https://gbdev.io/pandocs/OAM.html).

        Returns
        -------
        bool:
            The state of the bit in the attributes lookup.
        """

        self.attr_palette_number = 0
        """
        To better understand this values, look in the [Pan Docs: VRAM Sprite Attribute Table
        (OAM)](https://gbdev.io/pandocs/OAM.html).

        Returns
        -------
        int:
            The state of the bit(s) in the attributes lookup.
        """

        self.attr_cgb_bank_number = 0
        """
        To better understand this values, look in the [Pan Docs: VRAM Sprite Attribute Table
        (OAM)](https://gbdev.io/pandocs/OAM.html).

        Returns
        -------
        bool:
            The state of the bit in the attributes lookup.
        """

        if self.mb.cgb:
            self.attr_palette_number = attr & 0b111
            self.attr_cgb_bank_number = _bit(attr, 3)
        else:
            self.attr_palette_number = _bit(attr, 4)

        LCDC = LCDCRegister(self.mb.getitem(LCDC_OFFSET))
        sprite_height = 16 if LCDC._get_sprite_height() else 8
        self.shape = (8, sprite_height)
        """
        Sprites can be set to be 8x8 or 8x16 pixels (16 pixels tall). This is defined globally for the rendering
        hardware, so it's either all sprites using 8x16 pixels, or all sprites using 8x8 pixels.

        Returns
        -------
        (int, int):
            The width and height of the sprite.
        """

        self.tiles = [Tile(self.mb, self.tile_identifier)]
        """
        The Game Boy support sprites of single-height (8x8 pixels) and double-height (8x16 pixels).

        In the single-height format, one tile is used. For double-height sprites, the Game Boy will also use the tile
        immediately following the identifier given, and render it below the first.

        More information can be found in the [Pan Docs: VRAM Sprite Attribute Table
        (OAM)](https://gbdev.io/pandocs/OAM.html)

        Returns
        -------
        list:
            A list of `pyboy.api.tile.Tile` object(s) representing the graphics data for the sprite
        """
        if sprite_height == 16:
            self.tiles += [Tile(self.mb, self.tile_identifier + 1)]

        self.on_screen = (-sprite_height < self.y < 144 and -8 < self.x < 160)
        """
        To disable sprites from being rendered on screen, developers will place the sprite outside the area of the
        screen. This is often a good way to determine if the sprite is inactive.

        This check doesn't take transparency into account, and will only check the sprite's bounding-box of 8x8 or 8x16
        pixels.

        Returns
        -------
        bool:
            True if the sprite has at least one pixel on screen.
        """

    def __eq__(self, other):
        return self._offset == other._offset

    def __repr__(self):
        tiles = ", ".join([str(t) for t in self.tiles])
        return f"Sprite [{self._sprite_index}]: Position: ({self.x}, {self.y}), Shape: {self.shape}, Tiles: ({tiles}), On screen: {self.on_screen}"


def _bit(val, bit):
    # return (val & (1 << bit)) >> bit
    return (val >> bit) & 1

Classes

class Sprite (mb, sprite_index)

This class presents an interface to the sprites held in the OAM data on the Game Boy.

The purpose is to make it easier to interpret events on the screen, in order to program a bot, or train an AI.

Sprites are used on the Game Boy for enemy and player characters, as only sprites can have transparency, and can move at pixel-precision on the screen. The other method of graphics – tile maps – can only be placed in a grid-size of 8x8 pixels precision, and can have no transparency.

Sprites on the Game Boy are tightly associated with tiles. The sprites can be seen as "upgraded" tiles, as the image data still refers back to one (or two) tiles. The tile that a sprite will show, can change between each call to PyBoy.tick(), so make sure to verify the Sprite.tile_identifier hasn't changed.

By knowing the tile identifiers of players, enemies, power-ups and so on, you'll be able to search for them using pyboy.sprite_by_tile_identifier and feed it to your bot or AI.

Expand source code
class Sprite:
    def __init__(self, mb, sprite_index):
        """
        This class presents an interface to the sprites held in the OAM data on the Game Boy.

        The purpose is to make it easier to interpret events on the screen, in order to program a bot, or train an AI.

        Sprites are used on the Game Boy for enemy and player characters, as only sprites can have transparency, and can
        move at pixel-precision on the screen. The other method of graphics -- tile maps -- can only be placed in a
        grid-size of 8x8 pixels precision, and can have no transparency.

        Sprites on the Game Boy are tightly associated with tiles. The sprites can be seen as "upgraded" tiles, as the
        image data still refers back to one (or two) tiles. The tile that a sprite will show, can change between each
        call to `pyboy.PyBoy.tick`, so make sure to verify the `Sprite.tile_identifier` hasn't changed.

        By knowing the tile identifiers of players, enemies, power-ups and so on, you'll be able to search for them
        using `pyboy.sprite_by_tile_identifier` and feed it to your bot or AI.
        """
        assert 0 <= sprite_index < SPRITES, f"Sprite index of {sprite_index} is out of range (0-{SPRITES})"
        self.mb = mb
        self._offset = sprite_index * 4

        self._sprite_index = sprite_index
        """
        The index of the sprite itself. Beware, that this only represents the index or a "slot" in OAM memory.
        Many games will change the image data of the sprite in the "slot" several times per second.

        Returns
        -------
        int:
            unsigned tile index
        """

        # Documentation states the y coordinate needs to be subtracted by 16
        self.y = self.mb.getitem(OAM_OFFSET + self._offset + 0) - 16
        """
        The Y-coordinate on the screen to show the Sprite. The (x,y) coordinate points to the top-left corner of the sprite.

        Returns
        -------
        int:
            Y-coordinate
        """

        # Documentation states the x coordinate needs to be subtracted by 8
        self.x = self.mb.getitem(OAM_OFFSET + self._offset + 1) - 8
        """
        The X-coordinate on the screen to show the Sprite. The (x,y) coordinate points to the top-left corner of the sprite.

        Returns
        -------
        int:
            X-coordinate
        """

        # Sprites can only use unsigned tile indexes in the lower tile data.
        self.tile_identifier = self.mb.getitem(OAM_OFFSET + self._offset + 2)
        """
        The identifier of the tile the sprite uses. To get a better representation, see the method
        `pyboy.api.sprite.Sprite.tiles`.

        For double-height sprites, this will only give the identifier of the first tile. The second tile will
        always be the one immediately following the first (`tile_identifier + 1`).

        Returns
        -------
        int:
            unsigned tile index
        """

        attr = self.mb.getitem(OAM_OFFSET + self._offset + 3)
        self.attr_obj_bg_priority = _bit(attr, 7)
        """
        To better understand this values, look in the [Pan Docs: VRAM Sprite Attribute Table
        (OAM)](https://gbdev.io/pandocs/OAM.html).

        Returns
        -------
        bool:
            The state of the bit in the attributes lookup.
        """

        self.attr_y_flip = _bit(attr, 6)
        """
        To better understand this values, look in the [Pan Docs: VRAM Sprite Attribute Table
        (OAM)](https://gbdev.io/pandocs/OAM.html).

        Returns
        -------
        bool:
            The state of the bit in the attributes lookup.
        """

        self.attr_x_flip = _bit(attr, 5)
        """
        To better understand this values, look in the [Pan Docs: VRAM Sprite Attribute Table
        (OAM)](https://gbdev.io/pandocs/OAM.html).

        Returns
        -------
        bool:
            The state of the bit in the attributes lookup.
        """

        self.attr_palette_number = 0
        """
        To better understand this values, look in the [Pan Docs: VRAM Sprite Attribute Table
        (OAM)](https://gbdev.io/pandocs/OAM.html).

        Returns
        -------
        int:
            The state of the bit(s) in the attributes lookup.
        """

        self.attr_cgb_bank_number = 0
        """
        To better understand this values, look in the [Pan Docs: VRAM Sprite Attribute Table
        (OAM)](https://gbdev.io/pandocs/OAM.html).

        Returns
        -------
        bool:
            The state of the bit in the attributes lookup.
        """

        if self.mb.cgb:
            self.attr_palette_number = attr & 0b111
            self.attr_cgb_bank_number = _bit(attr, 3)
        else:
            self.attr_palette_number = _bit(attr, 4)

        LCDC = LCDCRegister(self.mb.getitem(LCDC_OFFSET))
        sprite_height = 16 if LCDC._get_sprite_height() else 8
        self.shape = (8, sprite_height)
        """
        Sprites can be set to be 8x8 or 8x16 pixels (16 pixels tall). This is defined globally for the rendering
        hardware, so it's either all sprites using 8x16 pixels, or all sprites using 8x8 pixels.

        Returns
        -------
        (int, int):
            The width and height of the sprite.
        """

        self.tiles = [Tile(self.mb, self.tile_identifier)]
        """
        The Game Boy support sprites of single-height (8x8 pixels) and double-height (8x16 pixels).

        In the single-height format, one tile is used. For double-height sprites, the Game Boy will also use the tile
        immediately following the identifier given, and render it below the first.

        More information can be found in the [Pan Docs: VRAM Sprite Attribute Table
        (OAM)](https://gbdev.io/pandocs/OAM.html)

        Returns
        -------
        list:
            A list of `pyboy.api.tile.Tile` object(s) representing the graphics data for the sprite
        """
        if sprite_height == 16:
            self.tiles += [Tile(self.mb, self.tile_identifier + 1)]

        self.on_screen = (-sprite_height < self.y < 144 and -8 < self.x < 160)
        """
        To disable sprites from being rendered on screen, developers will place the sprite outside the area of the
        screen. This is often a good way to determine if the sprite is inactive.

        This check doesn't take transparency into account, and will only check the sprite's bounding-box of 8x8 or 8x16
        pixels.

        Returns
        -------
        bool:
            True if the sprite has at least one pixel on screen.
        """

    def __eq__(self, other):
        return self._offset == other._offset

    def __repr__(self):
        tiles = ", ".join([str(t) for t in self.tiles])
        return f"Sprite [{self._sprite_index}]: Position: ({self.x}, {self.y}), Shape: {self.shape}, Tiles: ({tiles}), On screen: {self.on_screen}"

Instance variables

var y

The Y-coordinate on the screen to show the Sprite. The (x,y) coordinate points to the top-left corner of the sprite.

Returns

int:
Y-coordinate
var x

The X-coordinate on the screen to show the Sprite. The (x,y) coordinate points to the top-left corner of the sprite.

Returns

int:
X-coordinate
var tile_identifier

The identifier of the tile the sprite uses. To get a better representation, see the method Sprite.tiles.

For double-height sprites, this will only give the identifier of the first tile. The second tile will always be the one immediately following the first (tile_identifier + 1).

Returns

int:
unsigned tile index
var attr_obj_bg_priority

To better understand this values, look in the Pan Docs: VRAM Sprite Attribute Table (OAM).

Returns

bool:
The state of the bit in the attributes lookup.
var attr_y_flip

To better understand this values, look in the Pan Docs: VRAM Sprite Attribute Table (OAM).

Returns

bool:
The state of the bit in the attributes lookup.
var attr_x_flip

To better understand this values, look in the Pan Docs: VRAM Sprite Attribute Table (OAM).

Returns

bool:
The state of the bit in the attributes lookup.
var attr_palette_number

To better understand this values, look in the Pan Docs: VRAM Sprite Attribute Table (OAM).

Returns

int:
The state of the bit(s) in the attributes lookup.
var attr_cgb_bank_number

To better understand this values, look in the Pan Docs: VRAM Sprite Attribute Table (OAM).

Returns

bool:
The state of the bit in the attributes lookup.
var shape

Sprites can be set to be 8x8 or 8x16 pixels (16 pixels tall). This is defined globally for the rendering hardware, so it's either all sprites using 8x16 pixels, or all sprites using 8x8 pixels.

Returns

(int, int): The width and height of the sprite.

var tiles

The Game Boy support sprites of single-height (8x8 pixels) and double-height (8x16 pixels).

In the single-height format, one tile is used. For double-height sprites, the Game Boy will also use the tile immediately following the identifier given, and render it below the first.

More information can be found in the Pan Docs: VRAM Sprite Attribute Table (OAM)

Returns

list:
A list of Tile object(s) representing the graphics data for the sprite
var on_screen

To disable sprites from being rendered on screen, developers will place the sprite outside the area of the screen. This is often a good way to determine if the sprite is inactive.

This check doesn't take transparency into account, and will only check the sprite's bounding-box of 8x8 or 8x16 pixels.

Returns

bool:
True if the sprite has at least one pixel on screen.