Skip to content

Commit 812a1a4

Browse files
Merge pull request #3321 from MarcellPerger1/group-draw-special-flags
Add `special_flags` to `Group.draw()`
1 parent 158b227 commit 812a1a4

File tree

4 files changed

+65
-31
lines changed

4 files changed

+65
-31
lines changed

buildconfig/stubs/pygame/sprite.pyi

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ class AbstractGroup(Generic[_TSprite]):
165165
self, *sprites: Union[_TSprite, AbstractGroup[_TSprite], Iterable[_TSprite]]
166166
) -> bool: ...
167167
def update(self, *args: Any, **kwargs: Any) -> None: ...
168-
def draw(self, surface: Surface) -> list[Union[FRect, Rect]]: ...
168+
def draw(self, surface: Surface, bgd: Optional[Surface] = None, special_flags: int = 0) -> list[Union[FRect, Rect]]: ...
169169
def clear(
170170
self,
171171
surface: Surface,
@@ -226,7 +226,7 @@ class LayeredUpdates(AbstractGroup[_TSprite]):
226226
class LayeredDirty(LayeredUpdates[_TDirtySprite]):
227227
def __init__(self, *sprites: _TDirtySprite, **kwargs: Any) -> None: ...
228228
def draw(
229-
self, surface: Surface, bgd: Optional[Surface] = None
229+
self, surface: Surface, bgd: Optional[Surface] = None, special_flags: Optional[int] = None
230230
) -> list[Union[FRect, Rect]]: ...
231231
# clear breaks Liskov substitution principle in code
232232
def clear(self, surface: Surface, bgd: Surface) -> None: ... # type: ignore[override]

docs/reST/ref/sprite.rst

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -291,14 +291,18 @@ Sprites are not thread safe. So lock them yourself if using threads.
291291
.. method:: draw
292292

293293
| :sl:`blit the Sprite images`
294-
| :sg:`draw(Surface) -> list[Rect]`
294+
| :sg:`draw(Surface, bgd=None, special_flags=0) -> list[Rect]`
295295
296296
Draws the contained Sprites to the Surface argument. This uses the
297297
``Sprite.image`` attribute for the source surface, and ``Sprite.rect``
298-
for the position.
298+
for the position. ``special_flags`` is passed to ``Surface.blit()``.
299+
``bgd`` is unused in this method but ``LayeredDirty.draw()`` uses
300+
it.
299301

300302
The Group keeps sprites in the order they were added, they will be drawn in this order.
301303

304+
.. versionchanged:: 2.5.4 Added the ``bgd`` and ``special_flags`` arguments
305+
302306
.. ## Group.draw ##
303307
304308
.. method:: clear
@@ -347,18 +351,22 @@ Sprites are not thread safe. So lock them yourself if using threads.
347351
.. method:: draw
348352

349353
| :sl:`blit the Sprite images and track changed areas`
350-
| :sg:`draw(surface) -> Rect_list`
354+
| :sg:`draw(surface, bgd=None, special_flags=0) -> Rect_list`
351355
352356
Draws all the Sprites to the surface, the same as ``Group.draw()``. This
353357
method also returns a list of Rectangular areas on the screen that have
354358
been changed. The returned changes include areas of the screen that have
355-
been affected by previous ``Group.clear()`` calls.
359+
been affected by previous ``Group.clear()`` calls. ``special_flags`` is
360+
passed to ``Surface.blit()``. ``bgd`` is unused in this method but
361+
``LayeredDirty.draw()`` uses it.
356362

357363
The returned Rect list should be passed to ``pygame.display.update()``.
358364
This will help performance on software driven display modes. This type of
359365
updating is usually only helpful on destinations with non-animating
360366
backgrounds.
361367

368+
.. versionchanged:: 2.5.4 Added the ``bgd`` and ``special_flags`` arguments
369+
362370
.. ## RenderUpdates.draw ##
363371
364372
.. ## pygame.sprite.RenderUpdates ##
@@ -403,7 +411,9 @@ Sprites are not thread safe. So lock them yourself if using threads.
403411
.. method:: draw
404412

405413
| :sl:`draw all sprites in the right order onto the passed surface.`
406-
| :sg:`draw(surface) -> Rect_list`
414+
| :sg:`draw(surface, bgd=None, special_flags=0) -> Rect_list`
415+
416+
.. versionchanged:: 2.5.4 Added the ``bgd`` and ``special_flags`` arguments
407417

408418
.. ## LayeredUpdates.draw ##
409419
@@ -551,10 +561,13 @@ Sprites are not thread safe. So lock them yourself if using threads.
551561
.. method:: draw
552562

553563
| :sl:`draw all sprites in the right order onto the passed surface.`
554-
| :sg:`draw(surface, bgd=None) -> Rect_list`
564+
| :sg:`draw(surface, bgd=None, special_flags=None) -> Rect_list`
555565
556566
You can pass the background too. If a background is already set, then the
557-
bgd argument has no effect.
567+
bgd argument has no effect. ``special_flags`` is passed to
568+
``Surface.blit()``.
569+
570+
.. versionchanged:: 2.5.4 Added the ``special_flags`` argument
558571

559572
.. ## LayeredDirty.draw ##
560573

src_c/doc/sprite_doc.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@
1515
#define DOC_SPRITE_GROUP_REMOVE "remove(*sprites) -> None\nremove Sprites from the Group"
1616
#define DOC_SPRITE_GROUP_HAS "has(*sprites) -> bool\ntest if a Group contains Sprites"
1717
#define DOC_SPRITE_GROUP_UPDATE "update(*args, **kwargs) -> None\ncall the update method on contained Sprites"
18-
#define DOC_SPRITE_GROUP_DRAW "draw(Surface) -> list[Rect]\nblit the Sprite images"
18+
#define DOC_SPRITE_GROUP_DRAW "draw(Surface, bgd=None, special_flags=0) -> list[Rect]\nblit the Sprite images"
1919
#define DOC_SPRITE_GROUP_CLEAR "clear(Surface_dest, background) -> None\ndraw a background over the Sprites"
2020
#define DOC_SPRITE_GROUP_EMPTY "empty() -> None\nremove all Sprites"
2121
#define DOC_SPRITE_RENDERUPDATES "RenderUpdates(*sprites) -> RenderUpdates\nGroup sub-class that tracks dirty updates."
22-
#define DOC_SPRITE_RENDERUPDATES_DRAW "draw(surface) -> Rect_list\nblit the Sprite images and track changed areas"
22+
#define DOC_SPRITE_RENDERUPDATES_DRAW "draw(surface, bgd=None, special_flags=0) -> Rect_list\nblit the Sprite images and track changed areas"
2323
#define DOC_SPRITE_LAYEREDUPDATES "LayeredUpdates(*sprites, **kwargs) -> LayeredUpdates\nLayeredUpdates is a sprite group that handles layers and draws like RenderUpdates."
2424
#define DOC_SPRITE_LAYEREDUPDATES_ADD "add(*sprites, **kwargs) -> None\nadd a sprite or sequence of sprites to a group"
2525
#define DOC_SPRITE_LAYEREDUPDATES_SPRITES "sprites() -> sprites\nreturns an ordered list of sprites (first back, last top)."
26-
#define DOC_SPRITE_LAYEREDUPDATES_DRAW "draw(surface) -> Rect_list\ndraw all sprites in the right order onto the passed surface."
26+
#define DOC_SPRITE_LAYEREDUPDATES_DRAW "draw(surface, bgd=None, special_flags=0) -> Rect_list\ndraw all sprites in the right order onto the passed surface."
2727
#define DOC_SPRITE_LAYEREDUPDATES_GETSPRITESAT "get_sprites_at(pos) -> colliding_sprites\nreturns a list with all sprites at that position."
2828
#define DOC_SPRITE_LAYEREDUPDATES_GETSPRITE "get_sprite(idx) -> sprite\nreturns the sprite at the index idx from the groups sprites"
2929
#define DOC_SPRITE_LAYEREDUPDATES_REMOVESPRITESOFLAYER "remove_sprites_of_layer(layer_nr) -> sprites\nremoves all sprites from a layer and returns them as a list."
@@ -38,7 +38,7 @@
3838
#define DOC_SPRITE_LAYEREDUPDATES_GETSPRITESFROMLAYER "get_sprites_from_layer(layer) -> sprites\nreturns all sprites from a layer, ordered by how they where added"
3939
#define DOC_SPRITE_LAYEREDUPDATES_SWITCHLAYER "switch_layer(layer1_nr, layer2_nr) -> None\nswitches the sprites from layer1 to layer2"
4040
#define DOC_SPRITE_LAYEREDDIRTY "LayeredDirty(*sprites, **kwargs) -> LayeredDirty\nLayeredDirty group is for DirtySprite objects. Subclasses LayeredUpdates."
41-
#define DOC_SPRITE_LAYEREDDIRTY_DRAW "draw(surface, bgd=None) -> Rect_list\ndraw all sprites in the right order onto the passed surface."
41+
#define DOC_SPRITE_LAYEREDDIRTY_DRAW "draw(surface, bgd=None, special_flags=None) -> Rect_list\ndraw all sprites in the right order onto the passed surface."
4242
#define DOC_SPRITE_LAYEREDDIRTY_CLEAR "clear(surface, bgd) -> None\nused to set background"
4343
#define DOC_SPRITE_LAYEREDDIRTY_REPAINTRECT "repaint_rect(screen_rect) -> None\nrepaints the given area"
4444
#define DOC_SPRITE_LAYEREDDIRTY_SETCLIP "set_clip(screen_rect=None) -> None\nclip the area where to draw. Just pass None (default) to reset the clip"

src_py/sprite.py

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -555,22 +555,29 @@ def update(self, *args, **kwargs):
555555
for sprite in self.sprites():
556556
sprite.update(*args, **kwargs)
557557

558-
def draw(self, surface):
558+
def draw(self, surface, bgd=None, special_flags=0): # noqa pylint: disable=unused-argument; bgd arg used in LayeredDirty
559559
"""draw all sprites onto the surface
560560
561-
Group.draw(surface): return Rect_list
561+
Group.draw(surface, bgd=None, special_flags=0): return Rect_list
562562
563563
Draws all of the member sprites onto the given surface.
564564
565565
"""
566566
sprites = self.sprites()
567567
if hasattr(surface, "blits"):
568568
self.spritedict.update(
569-
zip(sprites, surface.blits((spr.image, spr.rect) for spr in sprites))
569+
zip(
570+
sprites,
571+
surface.blits(
572+
(spr.image, spr.rect, None, special_flags) for spr in sprites
573+
),
574+
)
570575
)
571576
else:
572577
for spr in sprites:
573-
self.spritedict[spr] = surface.blit(spr.image, spr.rect)
578+
self.spritedict[spr] = surface.blit(
579+
spr.image, spr.rect, None, special_flags
580+
)
574581
self.lostsprites = []
575582
dirty = self.lostsprites
576583

@@ -685,14 +692,14 @@ class RenderUpdates(Group):
685692
686693
"""
687694

688-
def draw(self, surface):
695+
def draw(self, surface, bgd=None, special_flags=0):
689696
surface_blit = surface.blit
690697
dirty = self.lostsprites
691698
self.lostsprites = []
692699
dirty_append = dirty.append
693700
for sprite in self.sprites():
694701
old_rect = self.spritedict[sprite]
695-
new_rect = surface_blit(sprite.image, sprite.rect)
702+
new_rect = surface_blit(sprite.image, sprite.rect, None, special_flags)
696703
if old_rect:
697704
if new_rect.colliderect(old_rect):
698705
dirty_append(new_rect.union(old_rect))
@@ -854,10 +861,10 @@ def sprites(self):
854861
"""
855862
return self._spritelist.copy()
856863

857-
def draw(self, surface):
864+
def draw(self, surface, bgd=None, special_flags=0):
858865
"""draw all sprites in the right order onto the passed surface
859866
860-
LayeredUpdates.draw(surface): return Rect_list
867+
LayeredUpdates.draw(surface, bgd=None, special_flags=0): return Rect_list
861868
862869
"""
863870
spritedict = self.spritedict
@@ -868,7 +875,7 @@ def draw(self, surface):
868875
init_rect = self._init_rect
869876
for spr in self.sprites():
870877
rec = spritedict[spr]
871-
newrect = surface_blit(spr.image, spr.rect)
878+
newrect = surface_blit(spr.image, spr.rect, None, special_flags)
872879
if rec is init_rect:
873880
dirty_append(newrect)
874881
else:
@@ -1127,13 +1134,16 @@ def add_internal(self, sprite, layer=None):
11271134

11281135
LayeredUpdates.add_internal(self, sprite, layer)
11291136

1130-
def draw(self, surface, bgd=None): # noqa pylint: disable=arguments-differ; unable to change public interface
1137+
def draw(self, surface, bgd=None, special_flags=None):
11311138
"""draw all sprites in the right order onto the given surface
11321139
1133-
LayeredDirty.draw(surface, bgd=None): return Rect_list
1140+
LayeredDirty.draw(surface, bgd=None, special_flags=0): return Rect_list
11341141
11351142
You can pass the background too. If a self.bgd is already set to some
11361143
value that is not None, then the bgd argument has no effect.
1144+
Passing a value to special_flags will pass that value as the
1145+
special_flags argument to all Surface.blit calls, overriding
1146+
the sprite.blendmode attribute.
11371147
11381148
"""
11391149
# functions and classes assigned locally to speed up loops
@@ -1173,21 +1183,29 @@ def draw(self, surface, bgd=None): # noqa pylint: disable=arguments-differ; una
11731183

11741184
# clear using background
11751185
if local_bgd is not None:
1186+
flags = 0 if special_flags is None else special_flags
11761187
for rec in local_update:
1177-
surf_blit_func(local_bgd, rec, rec)
1188+
surf_blit_func(local_bgd, rec, rec, flags)
11781189

11791190
# 2. draw
11801191
self._draw_dirty_internal(
1181-
local_old_rect, rect_type, local_sprites, surf_blit_func, local_update
1192+
local_old_rect,
1193+
rect_type,
1194+
local_sprites,
1195+
surf_blit_func,
1196+
local_update,
1197+
special_flags,
11821198
)
11831199
local_ret = list(local_update)
11841200
else: # flip, full screen mode
11851201
if local_bgd is not None:
1186-
surf_blit_func(local_bgd, (0, 0))
1202+
flags = 0 if special_flags is None else special_flags
1203+
surf_blit_func(local_bgd, (0, 0), None, flags)
11871204
for spr in local_sprites:
11881205
if spr.visible:
1206+
flags = spr.blendmode if special_flags is None else special_flags
11891207
local_old_rect[spr] = surf_blit_func(
1190-
spr.image, spr.rect, spr.source_rect, spr.blendmode
1208+
spr.image, spr.rect, spr.source_rect, flags
11911209
)
11921210
# return only the part of the screen changed
11931211
local_ret = [rect_type(latest_clip)]
@@ -1209,8 +1227,11 @@ def draw(self, surface, bgd=None): # noqa pylint: disable=arguments-differ; una
12091227
return local_ret
12101228

12111229
@staticmethod
1212-
def _draw_dirty_internal(_old_rect, _rect, _sprites, _surf_blit, _update):
1230+
def _draw_dirty_internal(
1231+
_old_rect, _rect, _sprites, _surf_blit, _update, _special_flags
1232+
):
12131233
for spr in _sprites:
1234+
flags = spr.blendmode if _special_flags is None else _special_flags
12141235
if spr.dirty < 1 and spr.visible:
12151236
# sprite not dirty; blit only the intersecting part
12161237
if spr.source_rect is not None:
@@ -1238,12 +1259,12 @@ def _draw_dirty_internal(_old_rect, _rect, _sprites, _surf_blit, _update):
12381259
clip[2],
12391260
clip[3],
12401261
),
1241-
spr.blendmode,
1262+
flags,
12421263
)
12431264
else: # dirty sprite
12441265
if spr.visible:
12451266
_old_rect[spr] = _surf_blit(
1246-
spr.image, spr.rect, spr.source_rect, spr.blendmode
1267+
spr.image, spr.rect, spr.source_rect, flags
12471268
)
12481269
if spr.dirty == 1:
12491270
spr.dirty = 0

0 commit comments

Comments
 (0)