Exemplo n.º 1
0
 def __init__(self):
     Sprite.__init__(self, Img.mario)
     self.gravity_constant = GRAVITY_CONSTANT
     self.vertical_velocity = VERTICAL_VELOCITY
     self.alive = 1
     self.reloading = 1
     self.rect.centerx = SCREENRECT.centerx
     self.rect.bottom = SCREENRECT.bottom - 10
     self.jumping = 0
Exemplo n.º 2
0
    def __init__(self):
        Sprite.__init__(self, Img.tube)
        self.alive = 1
        self.reloading = 0
        self.rect.centerx = SCREENRECT.centerx + 100
        self.rect.bottom = SCREENRECT.bottom - 10

        def update(self, ):
            global SCREENRECT
            self.rect[0] = self.rect[0].clamp(SCREENRECT)
            self.rect.bottom = SCREENRECT.bottom - 30
Exemplo n.º 3
0
    def __init__(self):
        Sprite.__init__(self, Img.goomba)
        self.alive = 1
        self.reloading = 0
        self.rect.centerx = SCREENRECT.centerx + 400
        self.rect.bottom = SCREENRECT.bottom - 10
        self.facing = random.choice((-1, 1)) * GOOMBA_SPEED
        if self.facing < 0:

            self.rect.centerx += 5
            self.rect.bottom = SCREENRECT.bottom
        else:
            self.rect.centerx -= 50
            self.rect.bottom = SCREENRECT.bottom
Exemplo n.º 4
0
    def draw(self,
             center_x: float,
             center_y: float,
             width: float,
             height: float,
             angle: float = 0,
             alpha: float = 1,
             transparent: bool = True,
             repeat_count_x=1,
             repeat_count_y=1):

        from arcade.sprite import Sprite
        from arcade.sprite_list import SpriteList

        if self._sprite is None:
            self._sprite = Sprite()
            self._sprite._texture = self
            self._sprite.textures = [self]

            self._sprite_list = SpriteList()
            self._sprite_list.append(self._sprite)

        self._sprite.center_x = center_x
        self._sprite.center_y = center_y
        self._sprite.width = width
        self._sprite.height = height
        self._sprite.angle = angle

        self._sprite_list.draw()
Exemplo n.º 5
0
    def _create_cached_sprite(self):
        from arcade.sprite import Sprite
        from arcade.sprite_list import SpriteList

        if self._sprite is None:
            self._sprite = Sprite()
            self._sprite.texture = self
            self._sprite.textures = [self]

            self._sprite_list = SpriteList()
            self._sprite_list.append(self._sprite)
Exemplo n.º 6
0
    def draw(self,
             center_x: float,
             center_y: float,
             width: float,
             height: float,
             angle: float = 0,
             alpha: int = 255,
             transparent: bool = True,
             repeat_count_x=1,
             repeat_count_y=1):
        """

        Args:
            center_x:
            center_y:
            width:
            height:
            angle:
            alpha: Currently unused.
            transparent:  Currently unused.
            repeat_count_x: Currently unused.
            repeat_count_y:  Currently unused.

        Returns:

        """

        from arcade.sprite import Sprite
        from arcade.sprite_list import SpriteList

        if self._sprite is None:
            self._sprite = Sprite()
            self._sprite._texture = self
            self._sprite.textures = [self]

            self._sprite_list = SpriteList()
            self._sprite_list.append(self._sprite)

        self._sprite.center_x = center_x
        self._sprite.center_y = center_y
        self._sprite.width = width
        self._sprite.height = height
        self._sprite.angle = angle
        self._sprite.alpha = alpha

        self._sprite_list.draw()
Exemplo n.º 7
0
    def draw(self,
             center_x: float,
             center_y: float,
             width: float = None,
             height: float = None,
             angle: float = 0,
             alpha: int = 255):
        """
        Draw the texture

        :param center_x: x location of where to draw the texture
        :param center_y: y location of where to draw the texture
        :param width: width to draw rectangle. If none, calculated from image size and scale
        :param height: height to draw rectangle. If none, calculated from image size and scale
        :param angle: angle to rotate the texture
        :param alpha: transparency of texture. 0-255
        """

        from arcade.sprite import Sprite
        from arcade.sprite_list import SpriteList

        if self._sprite is None:
            self._sprite = Sprite()
            self._sprite._texture = self
            self._sprite.textures = [self]

            self._sprite_list = SpriteList()
            self._sprite_list.append(self._sprite)

        self._sprite.center_x = center_x
        self._sprite.center_y = center_y
        if width:
            self._sprite.width = width
        else:
            self._sprite.width = self.image.width * self.scale
        if height:
            self._sprite.height = height
        else:
            self._sprite.height = self.image.height * self.scale
        self._sprite.angle = angle
        self._sprite.alpha = alpha

        self._sprite_list.draw()
Exemplo n.º 8
0
def draw_text(text: str,
              start_x: float,
              start_y: float,
              color: Color,
              font_size: float = 12,
              width: int = 0,
              align: str = "left",
              font_name=('calibri', 'arial'),
              bold: bool = False,
              italic: bool = False,
              anchor_x: str = "left",
              anchor_y: str = "baseline",
              rotation: float = 0):
    """

    Args:
        text: Text to draw
        start_x:
        start_y:
        color:
        font_size:
        width:
        align:
        font_name:
        bold:
        italic:
        anchor_x:
        anchor_y:
        rotation:

    Returns:

    """

    # Scale the font up, so it matches with the sizes of the old code back
    # when Pyglet drew the text.
    font_size *= 1.25

    # Text isn't anti-aliased, so we'll draw big, and then shrink
    scale_up = 5
    scale_down = 5

    font_size *= scale_up

    # If the cache gets too large, dump it and start over.
    if len(draw_text.cache) > 5000:
        draw_text.cache = {}

    key = f"{text}{color}{font_size}{width}{align}{font_name}{bold}{italic}"
    if key in draw_text.cache:
        label = draw_text.cache[key]
        text_sprite = label.text_sprite_list[0]

        if anchor_x == "left":
            text_sprite.center_x = start_x + text_sprite.width / 2
        elif anchor_x == "center":
            text_sprite.center_x = start_x
        elif anchor_x == "right":
            text_sprite.right = start_x
        else:
            raise ValueError(
                f"anchor_x should be 'left', 'center', or 'right'. Not '{anchor_x}'"
            )

        if anchor_y == "top":
            text_sprite.center_y = start_y - text_sprite.height / 2
        elif anchor_y == "center":
            text_sprite.center_y = start_y
        elif anchor_y == "bottom" or anchor_y == "baseline":
            text_sprite.bottom = start_y
        else:
            raise ValueError(
                f"anchor_x should be 'left', 'center', or 'right'. Not '{anchor_y}'"
            )

        text_sprite.angle = rotation

        label.text_sprite_list.update_positions()
    else:
        label = Text()

        # Figure out the font to use
        font = None

        # Font was specified with a string
        if isinstance(font_name, str):
            try:
                font = PIL.ImageFont.truetype(font_name, int(font_size))
            except OSError:
                # print(f"1 Can't find font: {font_name}")
                pass

            if font is None:
                try:
                    temp_font_name = f"{font_name}.ttf"
                    font = PIL.ImageFont.truetype(temp_font_name,
                                                  int(font_size))
                except OSError:
                    # print(f"2 Can't find font: {temp_font_name}")
                    pass

        # We were instead given a list of font names, in order of preference
        else:
            for font_string_name in font_name:
                try:
                    font = PIL.ImageFont.truetype(font_string_name,
                                                  int(font_size))
                    # print(f"3 Found font: {font_string_name}")
                except OSError:
                    # print(f"3 Can't find font: {font_string_name}")
                    pass

                if font is None:
                    try:
                        temp_font_name = f"{font_name}.ttf"
                        font = PIL.ImageFont.truetype(temp_font_name,
                                                      int(font_size))
                    except OSError:
                        # print(f"4 Can't find font: {temp_font_name}")
                        pass

                if font is not None:
                    break

        # Default font if no font
        if font is None:
            font_names = ("arial.ttf",
                          "/usr/share/fonts/truetype/freefont/FreeMono.ttf",
                          '/System/Library/Fonts/SFNSDisplay.ttf')
            for font_string_name in font_names:
                try:
                    font = PIL.ImageFont.truetype(font_string_name,
                                                  int(font_size))
                    break
                except OSError:
                    # print(f"5 Can't find font: {font_string_name}")
                    pass

        # This is stupid. We have to have an image to figure out what size
        # the text will be when we draw it. Of course, we don't know how big
        # to make the image. Catch-22. So we just make a small image we'll trash
        text_image_size = (10, 10)
        image = PIL.Image.new("RGBA", text_image_size)
        draw = PIL.ImageDraw.Draw(image)

        # Get size the text will be
        text_image_size = draw.multiline_textsize(text, font=font)

        # Create image of proper size
        text_height = text_image_size[1]
        text_width = text_image_size[0]

        image_start_x = 0
        if width == 0:
            width = text_image_size[0]
        else:
            # Wait! We were given a field width.
            if align == "center":
                # Center text on given field width
                field_width = width * scale_up
                text_image_size = field_width, text_height
                image_start_x = (field_width - text_width) // 2
                width = field_width
            else:
                image_start_x = 0

        # If we draw a y at 0, then the text is drawn with a baseline of 0,
        # cutting off letters that drop below the baseline. This shoves it
        # up a bit.
        image_start_y = -font_size * scale_up * 0.02
        image = PIL.Image.new("RGBA", text_image_size)
        draw = PIL.ImageDraw.Draw(image)

        # Convert to tuple if needed, because the multiline_text does not take a
        # list for a color
        if isinstance(color, list):
            color = tuple(color)
        draw.multiline_text((image_start_x, image_start_y),
                            text,
                            color,
                            align=align,
                            font=font)
        image = image.resize((width // scale_down, text_height // scale_down),
                             resample=PIL.Image.LANCZOS)

        text_sprite = Sprite()
        text_sprite._texture = Texture(key)
        text_sprite._texture.image = image

        text_sprite.image = image
        text_sprite.texture_name = key
        text_sprite.width = image.width
        text_sprite.height = image.height

        if anchor_x == "left":
            text_sprite.center_x = start_x + text_sprite.width / 2
        elif anchor_x == "center":
            text_sprite.center_x = start_x
        elif anchor_x == "right":
            text_sprite.right = start_x
        else:
            raise ValueError(
                f"anchor_x should be 'left', 'center', or 'right'. Not '{anchor_x}'"
            )

        if anchor_y == "top":
            text_sprite.center_y = start_y + text_sprite.height / 2
        elif anchor_y == "center":
            text_sprite.center_y = start_y
        elif anchor_y == "bottom" or anchor_y == "baseline":
            text_sprite.bottom = start_y
        else:
            raise ValueError(
                f"anchor_x should be 'top', 'center', 'bottom', or 'baseline'. Not '{anchor_y}'"
            )

        text_sprite.angle = rotation

        from arcade.sprite_list import SpriteList
        label.text_sprite_list = SpriteList()
        label.text_sprite_list.append(text_sprite)

        draw_text.cache[key] = label

    label.text_sprite_list.draw()
Exemplo n.º 9
0
def draw_text(text: str,
              start_x: float,
              start_y: float,
              color: Color,
              font_size: float = 12,
              width: int = 0,
              align: str = "left",
              font_name: Union[str, Tuple[str, ...]] = ('calibri', 'arial'),
              bold: bool = False,
              italic: bool = False,
              anchor_x: str = "left",
              anchor_y: str = "baseline",
              rotation: float = 0) -> Sprite:

    # This is a custom version of arcade's draw_text function, because the normal one doesn't work

    global draw_text_cache

    # Scale the font up, so it matches with the sizes of the old code back
    # when Pyglet drew the text.
    font_size *= 1.25

    # Text isn't anti-aliased, so we'll draw big, and then shrink
    scale_up = 2
    scale_down = 2

    font_size *= scale_up

    # If the cache gets too large, dump it and start over.
    if len(draw_text_cache) > 5000:
        draw_text_cache = {}

    r, g, b, alpha = get_four_byte_color(color)
    cache_color = f"{r}{g}{b}"

    key = f"{text}{cache_color}{font_size}{width}{align}{font_name}{bold}{italic}"
    try:
        label = draw_text_cache[key]
    except KeyError:  # doesn't exist, create it
        label = Text()

        # Figure out the font to use
        font = None

        # Font was specified with a string
        if isinstance(font_name, str):
            font_name = font_name,

        font_names = chain(
            *[[font_string_name, f"{font_string_name}.ttf"]
              for font_string_name in font_name], DEFAULT_FONT_NAMES)

        font_found = False
        for font_string_name in font_names:
            try:
                font = ImageFont.truetype(font_string_name,
                                          int(font_size),
                                          layout_engine=ImageFont.LAYOUT_BASIC)
            except OSError:
                continue
            else:
                font_found = True
                break

        if not font_found:
            raise RuntimeError(
                "Unable to find a default font on this system. Please specify an available font."
            )

        # This is stupid. We have to have an image to figure out what size
        # the text will be when we draw it. Of course, we don't know how big
        # to make the image. Catch-22. So we just make a small image we'll trash
        text_image_size = (10, 10)
        image = PIL.Image.new("RGBA", text_image_size)
        draw = PIL.ImageDraw.Draw(image)

        # Get size the text will be
        text_image_size = draw.multiline_textsize(text, font=font)
        # Add some extra pixels at the bottom to account for letters that drop below the baseline.
        text_image_size = text_image_size[0], text_image_size[1] + int(
            font_size * 0.25)

        # Create image of proper size
        text_height = text_image_size[1]
        text_width = text_image_size[0]

        image_start_x = 0
        if width == 0:
            width = text_image_size[0]
        else:
            # Wait! We were given a field width.
            if align == "center":
                # Center text on given field width
                field_width = width * scale_up
                text_image_size = field_width, text_height
                image_start_x = (field_width - text_width) // 2
                width = field_width
            else:
                image_start_x = 0

        # Find y of top-left corner
        image_start_y = 0

        # Create image
        image = PIL.Image.new("RGBA", text_image_size)
        draw = PIL.ImageDraw.Draw(image)

        # Convert to tuple if needed, because the multiline_text does not take a
        # list for a color
        if isinstance(color, list):
            color = cast(RGBA, tuple(color))
        draw.multiline_text((image_start_x, image_start_y),
                            text,
                            color,
                            align=align,
                            font=font)
        image = image.resize(
            (max(1, width // scale_down), text_height // scale_down),
            resample=PIL.Image.LANCZOS)

        text_sprite = Sprite()
        text_sprite._texture = Texture(key)
        text_sprite.texture.image = image

        text_sprite.width = image.width
        text_sprite.height = image.height

        from arcade.sprite_list import SpriteList
        label.text_sprite_list = SpriteList()
        label.text_sprite_list.append(text_sprite)

        draw_text_cache[key] = label

    text_sprite = label.text_sprite_list[0]

    if anchor_x == "left":
        text_sprite.center_x = start_x + text_sprite.width / 2
    elif anchor_x == "center":
        text_sprite.center_x = start_x
    elif anchor_x == "right":
        text_sprite.right = start_x
    else:
        raise ValueError(
            f"anchor_x should be 'left', 'center', or 'right'. Not '{anchor_x}'"
        )

    if anchor_y == "top":
        text_sprite.center_y = start_y - text_sprite.height / 2
    elif anchor_y == "center":
        text_sprite.center_y = start_y
    elif anchor_y == "bottom" or anchor_y == "baseline":
        text_sprite.bottom = start_y
    else:
        raise ValueError(
            f"anchor_y should be 'top', 'center', 'bottom', or 'baseline'. Not '{anchor_y}'"
        )

    text_sprite.angle = rotation
    text_sprite.alpha = alpha

    label.text_sprite_list.draw()
    return text_sprite
Exemplo n.º 10
0
def draw_text(text: str,
              start_x: float,
              start_y: float,
              color: Color,
              font_size: float = 12,
              width: int = 0,
              align="left",
              font_name=('Calibri', 'Arial'),
              bold: bool = False,
              italic: bool = False,
              anchor_x="left",
              anchor_y="baseline",
              rotation: float = 0):
    """

    Args:
        :text: Text to display.
        :start_x: x coordinate of top left text point.
        :start_y: y coordinate of top left text point.
        :color: color, specified in a list of 3 or 4 bytes in RGB or
         RGBA format.

    Example:

    >>> import arcade
    >>> arcade.open_window(800, 600, "Drawing Example")
    >>> arcade.set_background_color(arcade.color.WHITE)
    >>> arcade.start_render()
    >>> arcade.draw_text("Text Example", 250, 300, arcade.color.BLACK, 10)
    >>> arcade.draw_text("Text Example", 250, 300, (0, 0, 0, 100), 10)
    >>> arcade.finish_render()
    >>> arcade.quick_run(0.25)
    """

    # Scale the font up, so it matches with the sizes of the old code back
    # when pyglet drew the text.
    font_size *= 1.25

    # Text isn't anti-aliased, so we'll draw big, and then shrink
    scale_up = 5
    scale_down = 5

    font_size *= scale_up

    # If the cache gets too large, dump it and start over.
    if len(draw_text.cache) > 5000:
        draw_text.cache = {}

    key = f"{text}{color}{font_size}{width}{align}{font_name}{bold}{italic}"
    if key in draw_text.cache:
        label = draw_text.cache[key]
        text_sprite = label.text_sprite_list[0]

        if anchor_x == "left":
            text_sprite.center_x = start_x + text_sprite.width / 2
        elif anchor_x == "center":
            text_sprite.center_x = start_x
        elif anchor_x == "right":
            text_sprite.right = start_x
        else:
            raise ValueError(
                f"anchor_x should be 'left', 'center', or 'right'. Not '{anchor_x}'"
            )

        if anchor_y == "top":
            text_sprite.center_y = start_y - text_sprite.height / 2
        elif anchor_y == "center":
            text_sprite.center_y = start_y
        elif anchor_y == "bottom" or anchor_y == "baseline":
            text_sprite.bottom = start_y
        else:
            raise ValueError(
                f"anchor_x should be 'left', 'center', or 'right'. Not '{anchor_y}'"
            )

        text_sprite.angle = rotation

        label.text_sprite_list.update_positions()
    else:
        label = Text()

        # Figure out the font to use
        font = None

        # Font was specified with a string
        if isinstance(font_name, str):
            try:
                font = PIL.ImageFont.truetype(font_name, int(font_size))
            except OSError:
                pass

            if font is None:
                try:
                    font = PIL.ImageFont.truetype(font_name + ".ttf",
                                                  int(font_size))
                except OSError:
                    pass

        # We were instead given a list of font names, in order of preference
        if font is not None:
            for font_string_name in font_name:
                try:
                    font = PIL.ImageFont.truetype(font_string_name,
                                                  int(font_size))
                except OSError:
                    pass

                if font is None:
                    try:
                        font = PIL.ImageFont.truetype(
                            font_string_name + ".ttf", int(font_size))
                    except OSError:
                        pass

                if font is not None:
                    break

        # Default font if no font
        if font is None:
            font_names = ("arial.ttf",
                          "/usr/share/fonts/truetype/freefont/FreeMono.ttf",
                          '/System/Library/Fonts/SFNSDisplay.ttf')
            for font_string_name in font_names:
                try:
                    font = PIL.ImageFont.truetype(font_string_name,
                                                  int(font_size))
                    break
                except OSError:
                    pass

        # This is stupid. We have to have an image to figure out what size
        # the text will be when we draw it. Of course, we don't know how big
        # to make the image. Catch-22. So we just make a small image we'll trash
        text_image_size = (10, 10)
        image = PIL.Image.new("RGBA", text_image_size)
        draw = PIL.ImageDraw.Draw(image)

        # Get size the text will be
        text_image_size = draw.multiline_textsize(text, font=font)

        # Create image of proper size
        text_height = text_image_size[1]
        text_width = text_image_size[0]

        image_start_x = 0
        if width == 0:
            width = text_image_size[0]
        else:
            # Wait! We were given a field width.
            if align == "center":
                # Center text on given field width
                field_width = width * scale_up
                text_image_size = field_width, text_height
                image_start_x = (field_width - text_width) // 2
                width = field_width
            else:
                image_start_x = 0

        # If we draw a y at 0, then the text is drawn with a baseline of 0,
        # cutting off letters that drop below the baseline. This shoves it
        # up a bit.
        image_start_y = -font_size * scale_up * 0.03
        image = PIL.Image.new("RGBA", text_image_size)
        draw = PIL.ImageDraw.Draw(image)
        draw.multiline_text((image_start_x, image_start_y),
                            text,
                            color,
                            align=align,
                            font=font)
        image = image.resize((width // scale_down, text_height // scale_down),
                             resample=PIL.Image.LANCZOS)

        text_sprite = Sprite()
        text_sprite.image = image
        text_sprite.texture_name = key
        text_sprite.width = image.width
        text_sprite.height = image.height

        if anchor_x == "left":
            text_sprite.center_x = start_x + text_sprite.width / 2
        elif anchor_x == "center":
            text_sprite.center_x = start_x
        elif anchor_x == "right":
            text_sprite.right = start_x
        else:
            raise ValueError(
                f"anchor_x should be 'left', 'center', or 'right'. Not '{anchor_x}'"
            )

        if anchor_y == "top":
            text_sprite.center_y = start_y + text_sprite.height / 2
        elif anchor_y == "center":
            text_sprite.center_y = start_y
        elif anchor_y == "bottom" or anchor_y == "baseline":
            text_sprite.bottom = start_y
        else:
            raise ValueError(
                f"anchor_x should be 'left', 'center', or 'right'. Not '{anchor_y}'"
            )

        text_sprite.angle = rotation

        from arcade.sprite_list import SpriteList
        label.text_sprite_list = SpriteList()
        label.text_sprite_list.append(text_sprite)

        draw_text.cache[key] = label

    label.text_sprite_list.draw()
Exemplo n.º 11
0
 def __init__(self, mario):
     Sprite.__init__(self, Img.fireball)
     self.rect.centerx = mario.rect.centerx
     self.rect.bottom = mario.rect.centerx - 10
Exemplo n.º 12
0
 def __init__(self, sprite):
     Sprite.__init__(self, Img.burn)
     self.life = EXPLODE_TIME
     self.rect.center = sprite.rect.center
Exemplo n.º 13
0
def draw_text(text: str,
              start_x: float,
              start_y: float,
              color: Color,
              font_size: float = 12,
              width: int = 0,
              align: str = "left",
              font_name: Union[str, Tuple[str, ...]] = ('calibri', 'arial'),
              bold: bool = False,
              italic: bool = False,
              anchor_x: str = "left",
              anchor_y: str = "baseline",
              rotation: float = 0):
    """

    :param str text: Text to draw
    :param float start_x:
    :param float start_y:
    :param Color color: Color of the text
    :param float font_size: Size of the text
    :param float width:
    :param str align:
    :param Union[str, Tuple[str, ...]] font_name:
    :param bool bold:
    :param bool italic:
    :param str anchor_x:
    :param str anchor_y:
    :param float rotation:
    """

    # Scale the font up, so it matches with the sizes of the old code back
    # when Pyglet drew the text.
    font_size *= 1.25

    # Text isn't anti-aliased, so we'll draw big, and then shrink
    scale_up = 5
    scale_down = 5

    font_size *= scale_up

    # If the cache gets too large, dump it and start over.
    if len(draw_text.cache
           ) > 5000:  # type: ignore # dynamic attribute on function obj
        draw_text.cache = {
        }  # type: ignore # dynamic attribute on function obj

    key = f"{text}{color}{font_size}{width}{align}{font_name}{bold}{italic}"
    if key in draw_text.cache:  # type: ignore # dynamic attribute on function obj
        label = draw_text.cache[
            key]  # type: ignore # dynamic attribute on function obj
        text_sprite = label.text_sprite_list[0]

        if anchor_x == "left":
            text_sprite.center_x = start_x + text_sprite.width / 2
        elif anchor_x == "center":
            text_sprite.center_x = start_x
        elif anchor_x == "right":
            text_sprite.right = start_x
        else:
            raise ValueError(
                f"anchor_x should be 'left', 'center', or 'right'. Not '{anchor_x}'"
            )

        if anchor_y == "top":
            text_sprite.center_y = start_y - text_sprite.height / 2
        elif anchor_y == "center":
            text_sprite.center_y = start_y
        elif anchor_y == "bottom" or anchor_y == "baseline":
            text_sprite.bottom = start_y
        else:
            raise ValueError(
                f"anchor_y should be 'top', 'center', 'bottom', or 'baseline'. Not '{anchor_y}'"
            )

        text_sprite.angle = rotation
    else:
        label = Text()

        # Figure out the font to use
        font = None

        # Font was specified with a string
        if isinstance(font_name, str):
            font_name = [font_name]

        font_names = chain(
            *[[font_string_name, f"{font_string_name}.ttf"]
              for font_string_name in font_name], DEFAULT_FONT_NAMES)

        font_found = False
        for font_string_name in font_names:
            try:
                font = PIL.ImageFont.truetype(font_string_name, int(font_size))
            except OSError:
                continue
            else:
                font_found = True
                break

        if not font_found:
            raise RuntimeError(
                "Unable to find a default font on this system. Please specify an available font."
            )

        # This is stupid. We have to have an image to figure out what size
        # the text will be when we draw it. Of course, we don't know how big
        # to make the image. Catch-22. So we just make a small image we'll trash
        text_image_size = (10, 10)
        image = PIL.Image.new("RGBA", text_image_size)
        draw = PIL.ImageDraw.Draw(image)

        # Get size the text will be
        text_image_size = draw.multiline_textsize(text, font=font)

        # Create image of proper size
        text_height = text_image_size[1]
        text_width = text_image_size[0]

        image_start_x = 0
        if width == 0:
            width = text_image_size[0]
        else:
            # Wait! We were given a field width.
            if align == "center":
                # Center text on given field width
                field_width = width * scale_up
                text_image_size = field_width, text_height
                image_start_x = (field_width - text_width) // 2
                width = field_width
            else:
                image_start_x = 0

        # If we draw a y at 0, then the text is drawn with a baseline of 0,
        # cutting off letters that drop below the baseline. This shoves it
        # up a bit.
        image_start_y = -font_size * scale_up * 0.02
        image = PIL.Image.new("RGBA", text_image_size)
        draw = PIL.ImageDraw.Draw(image)

        # Convert to tuple if needed, because the multiline_text does not take a
        # list for a color
        if isinstance(color, list):
            color = cast(RGBA, tuple(color))
        draw.multiline_text((image_start_x, image_start_y),
                            text,
                            color,
                            align=align,
                            font=font)
        image = image.resize((width // scale_down, text_height // scale_down),
                             resample=PIL.Image.LANCZOS)

        text_sprite = Sprite()
        text_sprite._texture = Texture(key)
        text_sprite.texture.image = image

        text_sprite.image = image
        text_sprite.texture_name = key
        text_sprite.width = image.width
        text_sprite.height = image.height

        if anchor_x == "left":
            text_sprite.center_x = start_x + text_sprite.width / 2
        elif anchor_x == "center":
            text_sprite.center_x = start_x
        elif anchor_x == "right":
            text_sprite.right = start_x
        else:
            raise ValueError(
                f"anchor_x should be 'left', 'center', or 'right'. Not '{anchor_x}'"
            )

        if anchor_y == "top":
            text_sprite.center_y = start_y + text_sprite.height / 2
        elif anchor_y == "center":
            text_sprite.center_y = start_y
        elif anchor_y == "bottom" or anchor_y == "baseline":
            text_sprite.bottom = start_y
        else:
            raise ValueError(
                f"anchor_y should be 'top', 'center', 'bottom', or 'baseline'. Not '{anchor_y}'"
            )

        text_sprite.angle = rotation

        from arcade.sprite_list import SpriteList
        label.text_sprite_list = SpriteList()
        label.text_sprite_list.append(text_sprite)

        draw_text.cache[
            key] = label  # type: ignore # dynamic attribute on function obj

    label.text_sprite_list.draw()
Exemplo n.º 14
0
def draw_text(text: str,
              start_x: float,
              start_y: float,
              color: Color,
              font_size: float = 12,
              width: int = 0,
              align: str = "left",
              font_name: Union[str, Tuple[str, ...]] = ('calibri', 'arial'),
              bold: bool = False,
              italic: bool = False,
              anchor_x: str = "left",
              anchor_y: str = "baseline",
              rotation: float = 0) -> Sprite:
    """

    Draws text to the screen.

    Internally this works by creating an image, and using the Pillow library to
    draw the text to it. Then use that image to create a sprite. We cache the sprite
    (so we don't have to recreate over and over, which is slow) and use it to
    draw text to the screen.

    This implementation does not support bold/italic like the older Pyglet-based
    implementation of draw_text. However if you specify the 'italic' or 'bold'
    version of the font via the font name, you will get that font. Just the booleans
    do not work.

    :param str text: Text to draw
    :param float start_x: x coordinate of the lower-left point to start drawing text
    :param float start_y: y coordinate of the lower-left point to start drawing text
    :param Color color: Color of the text
    :param float font_size: Size of the text
    :param float width: Width of the text-box for the text to go into. Used with alignment.
    :param str align: Align left, right, center
    :param Union[str, Tuple[str, ...]] font_name: Font name, or list of font names in order of preference
    :param bool bold: Bold the font (currently unsupported)
    :param bool italic: Italicize the font (currently unsupported)
    :param str anchor_x: Anchor the font location, defaults to 'left'
    :param str anchor_y: Anchor the font location, defaults to 'baseline'
    :param float rotation: Rotate the text
    """
    global draw_text_cache

    # If the cache gets too large, dump it and start over.
    if len(draw_text_cache) > 5000:
        draw_text_cache = {}

    r, g, b, alpha = get_four_byte_color(color)
    cache_color = f"{r}{g}{b}"

    key = f"{text}{cache_color}{font_size}{width}{align}{font_name}{bold}{italic}"

    try:
        label = draw_text_cache[key]
    except KeyError:  # doesn't exist, create it

        image = get_text_image(text=text,
                               text_color=color,
                               font_size=font_size,
                               width=width,
                               align=align,
                               font_name=font_name)
        text_sprite = Sprite()
        text_sprite._texture = Texture(key)
        text_sprite.texture.image = image

        text_sprite.width = image.width
        text_sprite.height = image.height

        from arcade.sprite_list import SpriteList

        label = Text()
        label.text_sprite_list = SpriteList()
        label.text_sprite_list.append(text_sprite)

        draw_text_cache[key] = label

    text_sprite = label.text_sprite_list[0]

    if anchor_x == "left":
        text_sprite.center_x = start_x + text_sprite.width / 2
    elif anchor_x == "center":
        text_sprite.center_x = start_x
    elif anchor_x == "right":
        text_sprite.right = start_x
    else:
        raise ValueError(
            f"anchor_x should be 'left', 'center', or 'right'. Not '{anchor_x}'"
        )

    if anchor_y == "top":
        text_sprite.center_y = start_y - text_sprite.height / 2
    elif anchor_y == "center":
        text_sprite.center_y = start_y
    elif anchor_y == "bottom" or anchor_y == "baseline":
        text_sprite.center_y = start_y + text_sprite.height / 2
    else:
        raise ValueError(
            f"anchor_y should be 'top', 'center', 'bottom', or 'baseline'. Not '{anchor_y}'"
        )

    text_sprite.angle = rotation
    text_sprite.alpha = alpha

    label.text_sprite_list.draw()
    return text_sprite