Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyscroll/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ def reload_animations(self) -> None:
"""
self._update_time()
self._animation_queue = list()
self._animated_tile = dict()
self._tracked_gids = set()
self._animation_map = dict()

Expand Down
68 changes: 56 additions & 12 deletions pyscroll/orthographic.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import time
from collections.abc import Callable
from itertools import chain, product
from typing import TYPE_CHECKING
from typing import Any, Callable, Optional, TYPE_CHECKING, Union

import pygame
from pygame import Rect, Surface
Expand All @@ -16,6 +16,7 @@
if TYPE_CHECKING:
from .data import PyscrollDataAdapter


log = logging.getLogger(__file__)


Expand Down Expand Up @@ -74,6 +75,9 @@ def __init__(
self.tall_sprites = tall_sprites
self.sprite_damage_height = sprite_damage_height
self.map_rect = None
self.blit_list_sort_key: Optional[
Callable[[tuple[int, int, int, int, int, Surface, Optional[int]]], Any]
] = None

# internal private defaults
if colorkey and alpha:
Expand Down Expand Up @@ -216,7 +220,14 @@ def center(self, coords: Vector2D) -> None:
self._tile_view.move_ip(dx, dy)
self.redraw_tiles(self._buffer)

def draw(self, surface: Surface, rect: RectLike, surfaces: list[Surface] = None):
def draw(
self,
surface: Surface,
rect: RectLike,
surfaces: Optional[
list[Union[tuple[Surface, Rect, int], tuple[Surface, Rect, int, int]]]
] = None,
):
"""
Draw the map onto a surface.

Expand Down Expand Up @@ -399,7 +410,12 @@ def translate_rects(self, rects: list[Rect]) -> list[Rect]:
return retval

def _render_map(
self, surface: Surface, rect: RectLike, surfaces: list[Surface]
self,
surface: Surface,
rect: RectLike,
surfaces: Optional[
list[Union[tuple[Surface, Rect, int], tuple[Surface, Rect, int, int]]]
],
) -> None:
"""
Render the map and optional surfaces to destination surface.
Expand Down Expand Up @@ -439,7 +455,14 @@ def _clear_surface(self, surface: Surface, area: RectLike = None) -> None:
)
surface.fill(clear_color, area)

def _draw_surfaces(self, surface: Surface, offset: Vector2DInt, surfaces) -> None:
def _draw_surfaces(
self,
surface: Surface,
offset: Vector2DInt,
surfaces: list[
Union[tuple[Surface, Rect, int], tuple[Surface, Rect, int, int]]
],
) -> None:
"""
Draw surfaces while correcting overlapping tile layers.

Expand Down Expand Up @@ -495,30 +518,26 @@ def _draw_surfaces(self, surface: Surface, offset: Vector2DInt, surfaces) -> Non
# equal to the damaged layer, then add the entire column of
# tiles to the blit_list. if not, then discard the column and
# do not update the screen when the damage was done.
column = list()
is_over = False
column = []
for dl, damage_rect in sprite_damage:
x, y, w, h = damage_rect
tx = x // w + left
ty = y // h + top
# TODO: heightmap
for l in tile_layers:
for l in [l for l in tile_layers if dl <= l]:
tile = get_tile(tx, ty, l)
if tile:
sx = x - ox
sy = y - oy
if dl <= l:
is_over = True
blit_op = l, 0, sx, sy, order, tile, None
column.append(blit_op)
order += 1
if is_over:
if len(column):
blit_list.extend(column)
column.clear()
is_over = False

# finally sort and do the thing
blit_list.sort()
blit_list.sort(key=self.blit_list_sort_key)
draw_list2 = list()
for l, priority, x, y, order, s, blend in blit_list:
if blend is not None:
Expand All @@ -528,6 +547,31 @@ def _draw_surfaces(self, surface: Surface, offset: Vector2DInt, surfaces) -> Non
draw_list2.append(blit_op)
surface.blits(draw_list2, doreturn=False)

def set_blit_list_sort_key(
self,
key: Optional[
Callable[[tuple[int, int, int, int, int, Surface, Optional[int]]], Any]
],
) -> None:
"""Set the key function for sorting list of blit operations on sprites
and tiles overlaying sprites in the _draw_surfaces method. The elements
in the list are 7-tuples with the following contents:
element 0 (int): layer number
element 1 (int): priority - 0 for tile, 1 for sprite
element 2 (int): x coordinate for the left corner of the surface
element 3 (int): y coordinate for the top-left corner of the surface
element 4 (int): the pre-sorted order of elements in the list
element 5 (Surface): the source image for the blit
element 6 (int): Special flags for blit operation

The default key is None, yeilding a sort first on element 0, then 1, 2, ..., 6.

To alternatinely sort first on layer, then bottom y coordinate, then priority,
the key function could be set to the following lambda function:
lambda x: (x[0], x[3]+x[5].get_height(), x[1])
"""
self.blit_list_sort_key = key

def _queue_edge_tiles(self, dx: int, dy: int) -> None:
"""
Queue edge tiles and clear edge areas on buffer if needed.
Expand Down