0
# Typing Support
1
2
Type hints and protocols for enhanced development experience with pygame-ce. Provides comprehensive type aliases, protocol classes, and type-safe interfaces for better IDE support and static type checking.
3
4
## Capabilities
5
6
### Core Type Aliases
7
8
Essential type aliases for common pygame data structures and parameters.
9
10
```python { .api }
11
# Geometric types
12
RectLike = Union[Rect, FRect, SequenceLike[float], SequenceLike[Point], _HasRectAttribute]
13
Point = SequenceLike[float]
14
IntPoint = SequenceLike[int]
15
Coordinate = Union[Point, int, float]
16
17
# Color types
18
ColorLike = Union[Color, SequenceLike[int], str, int]
19
RGB = tuple[int, int, int]
20
RGBA = tuple[int, int, int, int]
21
22
# File and path types
23
FileLike = Union[str, bytes, PathLike[str], PathLike[bytes], IO[bytes], IO[str]]
24
PathLike = Union[str, bytes, os.PathLike[str], os.PathLike[bytes]]
25
26
# Surface types
27
SurfaceLike = Union[Surface, SequenceLike[SequenceLike[ColorLike]]]
28
BlendMode = int
29
30
# Vector types
31
Vector2Like = Union[Vector2, SequenceLike[float], tuple[float, float]]
32
Vector3Like = Union[Vector3, SequenceLike[float], tuple[float, float, float]]
33
34
# Font types
35
FontLike = Union[Font, str, bytes, PathLike]
36
37
# Event types
38
EventType = int
39
```
40
41
### Protocol Classes
42
43
Protocol classes for duck typing and structural subtyping support.
44
45
```python { .api }
46
class SequenceLike(Protocol[T_co]):
47
"""Protocol for sequence-like objects that support indexing and length."""
48
49
def __getitem__(self, index: int) -> T_co: ...
50
def __len__(self) -> int: ...
51
52
class _HasRectAttribute(Protocol):
53
"""Protocol for objects that have a rect attribute."""
54
rect: RectLike
55
56
class _ColorCompatible(Protocol):
57
"""Protocol for color-compatible objects."""
58
def __iter__(self) -> Iterator[int]: ...
59
def __len__(self) -> int: ...
60
61
class _SupportsWrite(Protocol[T_contra]):
62
"""Protocol for file-like objects that support writing."""
63
def write(self, data: T_contra) -> int: ...
64
65
class _SupportsRead(Protocol[T_co]):
66
"""Protocol for file-like objects that support reading."""
67
def read(self, size: int = -1) -> T_co: ...
68
```
69
70
### Surface Type Support
71
72
Type annotations for surface operations and transformations.
73
74
```python { .api }
75
# Surface creation types
76
SurfaceFlags = int
77
PixelFormat = int
78
Depth = int
79
Masks = tuple[int, int, int, int]
80
81
# Surface transformation types
82
ScaleMode = Literal["nearest", "linear"]
83
FlipMode = tuple[bool, bool]
84
RotationAngle = float
85
86
# Blending types
87
BlendModeType = Union[int, str]
88
SpecialFlags = int
89
```
90
91
### Event Type Annotations
92
93
Comprehensive event type support for type-safe event handling.
94
95
```python { .api }
96
# Event type unions
97
KeyEventType = Literal[KEYDOWN, KEYUP]
98
MouseEventType = Literal[MOUSEBUTTONDOWN, MOUSEBUTTONUP, MOUSEMOTION]
99
JoystickEventType = Literal[JOYAXISMOTION, JOYBUTTONDOWN, JOYBUTTONUP, JOYHATMOTION]
100
SystemEventType = Literal[QUIT, VIDEORESIZE, VIDEOEXPOSE]
101
102
# Event data types
103
class KeyEventDict(TypedDict):
104
key: int
105
mod: int
106
unicode: str
107
scancode: int
108
109
class MouseButtonEventDict(TypedDict):
110
button: int
111
pos: tuple[int, int]
112
113
class MouseMotionEventDict(TypedDict):
114
pos: tuple[int, int]
115
rel: tuple[int, int]
116
buttons: tuple[bool, bool, bool]
117
118
class JoystickAxisEventDict(TypedDict):
119
joy: int
120
axis: int
121
value: float
122
123
class JoystickButtonEventDict(TypedDict):
124
joy: int
125
button: int
126
127
class JoystickHatEventDict(TypedDict):
128
joy: int
129
hat: int
130
value: tuple[int, int]
131
```
132
133
### Function Type Signatures
134
135
Generic type signatures for common pygame function patterns.
136
137
```python { .api }
138
# Callback types
139
DrawCallback = Callable[[Surface], None]
140
UpdateCallback = Callable[[float], None]
141
EventCallback = Callable[[Event], None]
142
143
# Iterator types
144
SpriteIterator = Iterator[Sprite]
145
RectIterator = Iterator[Rect]
146
EventIterator = Iterator[Event]
147
148
# Optional types
149
OptionalSurface = Optional[Surface]
150
OptionalRect = Optional[Rect]
151
OptionalColor = Optional[ColorLike]
152
153
# Generic collection types
154
SpriteCollection = Union[Group, Sequence[Sprite]]
155
RectCollection = Union[Sequence[Rect], Sequence[RectLike]]
156
```
157
158
### Audio Type Support
159
160
Type annotations for audio and mixer functionality.
161
162
```python { .api }
163
# Audio format types
164
AudioFormat = Literal[-16, -8, 8, 16]
165
AudioChannels = Literal[1, 2]
166
AudioFrequency = Literal[11025, 22050, 44100, 48000]
167
168
# Audio data types
169
AudioArray = Union[bytes, numpy.ndarray]
170
AudioBuffer = Union[str, bytes, IO[bytes]]
171
172
# Channel types
173
ChannelType = Union[Channel, int]
174
LoopCount = int
175
FadeTime = int
176
```
177
178
### Math Type Support
179
180
Type annotations for mathematical operations and geometry.
181
182
```python { .api }
183
# Angle types
184
Degrees = float
185
Radians = float
186
AngleUnit = Union[Degrees, Radians]
187
188
# Geometric types
189
Distance = float
190
Scale = float
191
Ratio = float
192
193
# Transform types
194
Matrix2D = tuple[tuple[float, float], tuple[float, float]]
195
Transform = Union[Matrix2D, Callable[[Point], Point]]
196
197
# Collision types
198
CollisionCallback = Callable[[Sprite, Sprite], bool]
199
CollisionMask = Union[Mask, Callable[[Sprite], Mask]]
200
```
201
202
## Usage Examples
203
204
### Type-Safe Event Handling
205
206
```python
207
import pygame
208
from pygame.typing import Event, KeyEventType, MouseEventType
209
from typing import Union
210
211
def handle_keyboard_event(event: Event) -> None:
212
"""Type-safe keyboard event handler."""
213
if event.type in (pygame.KEYDOWN, pygame.KEYUP):
214
key: int = event.key
215
mod: int = event.mod
216
unicode_char: str = getattr(event, 'unicode', '')
217
218
print(f"Key: {key}, Modifiers: {mod}, Unicode: {unicode_char}")
219
220
def handle_mouse_event(event: Event) -> None:
221
"""Type-safe mouse event handler."""
222
if event.type == pygame.MOUSEBUTTONDOWN:
223
button: int = event.button
224
pos: tuple[int, int] = event.pos
225
print(f"Mouse button {button} pressed at {pos}")
226
227
elif event.type == pygame.MOUSEMOTION:
228
pos: tuple[int, int] = event.pos
229
rel: tuple[int, int] = event.rel
230
buttons: tuple[bool, bool, bool] = event.buttons
231
print(f"Mouse moved to {pos}, relative: {rel}")
232
233
# Usage in game loop
234
pygame.init()
235
screen = pygame.display.set_mode((800, 600))
236
running = True
237
238
while running:
239
for event in pygame.event.get():
240
if event.type == pygame.QUIT:
241
running = False
242
elif event.type in (pygame.KEYDOWN, pygame.KEYUP):
243
handle_keyboard_event(event)
244
elif event.type in (pygame.MOUSEBUTTONDOWN, pygame.MOUSEMOTION):
245
handle_mouse_event(event)
246
247
pygame.quit()
248
```
249
250
### Type-Safe Surface Operations
251
252
```python
253
import pygame
254
from pygame.typing import ColorLike, RectLike, SurfaceLike
255
from typing import Optional
256
257
def create_colored_surface(
258
size: tuple[int, int],
259
color: ColorLike,
260
alpha: Optional[int] = None
261
) -> pygame.Surface:
262
"""Create a surface filled with specified color."""
263
surface = pygame.Surface(size)
264
if alpha is not None:
265
surface.set_alpha(alpha)
266
surface.fill(color)
267
return surface
268
269
def safe_blit(
270
dest: pygame.Surface,
271
source: pygame.Surface,
272
dest_rect: RectLike,
273
source_rect: Optional[RectLike] = None
274
) -> pygame.Rect:
275
"""Type-safe surface blitting."""
276
return dest.blit(source, dest_rect, source_rect)
277
278
# Usage
279
screen = pygame.display.set_mode((800, 600))
280
281
# Type-safe color specifications
282
red_surface = create_colored_surface((100, 100), "red")
283
blue_surface = create_colored_surface((50, 50), (0, 0, 255), alpha=128)
284
green_surface = create_colored_surface((75, 75), pygame.Color(0, 255, 0))
285
286
# Type-safe blitting
287
safe_blit(screen, red_surface, (100, 100))
288
safe_blit(screen, blue_surface, (200, 200))
289
safe_blit(screen, green_surface, pygame.Rect(300, 300, 75, 75))
290
```
291
292
### Type-Safe Sprite Groups
293
294
```python
295
import pygame
296
from pygame.typing import SpriteCollection
297
from typing import List, Optional
298
299
class TypedSprite(pygame.sprite.Sprite):
300
"""Sprite with type annotations."""
301
302
def __init__(self, image: pygame.Surface, position: tuple[int, int]):
303
super().__init__()
304
self.image: pygame.Surface = image
305
self.rect: pygame.Rect = image.get_rect()
306
self.rect.topleft = position
307
self.velocity: pygame.Vector2 = pygame.Vector2(0, 0)
308
309
def update(self, dt: float) -> None:
310
"""Update sprite position based on velocity."""
311
self.rect.x += int(self.velocity.x * dt)
312
self.rect.y += int(self.velocity.y * dt)
313
314
class TypedGroup(pygame.sprite.Group):
315
"""Type-safe sprite group."""
316
317
def get_sprites_at_pos(self, pos: tuple[int, int]) -> List[TypedSprite]:
318
"""Get all sprites at the given position."""
319
sprites: List[TypedSprite] = []
320
for sprite in self.sprites():
321
if isinstance(sprite, TypedSprite) and sprite.rect.collidepoint(pos):
322
sprites.append(sprite)
323
return sprites
324
325
def update_all(self, dt: float) -> None:
326
"""Update all sprites with delta time."""
327
sprite: TypedSprite
328
for sprite in self.sprites():
329
if isinstance(sprite, TypedSprite):
330
sprite.update(dt)
331
332
# Usage
333
pygame.init()
334
screen = pygame.display.set_mode((800, 600))
335
336
# Create typed sprites
337
player_image = pygame.Surface((50, 50))
338
player_image.fill((0, 255, 0))
339
player = TypedSprite(player_image, (400, 300))
340
player.velocity = pygame.Vector2(100, 0)
341
342
enemy_image = pygame.Surface((30, 30))
343
enemy_image.fill((255, 0, 0))
344
enemy = TypedSprite(enemy_image, (100, 100))
345
enemy.velocity = pygame.Vector2(50, 50)
346
347
# Create typed group
348
all_sprites = TypedGroup()
349
all_sprites.add(player, enemy)
350
351
# Type-safe operations
352
clock = pygame.time.Clock()
353
running = True
354
355
while running:
356
dt = clock.tick(60) / 1000.0 # Delta time in seconds
357
358
for event in pygame.event.get():
359
if event.type == pygame.QUIT:
360
running = False
361
elif event.type == pygame.MOUSEBUTTONDOWN:
362
clicked_sprites = all_sprites.get_sprites_at_pos(event.pos)
363
print(f"Clicked on {len(clicked_sprites)} sprites")
364
365
all_sprites.update_all(dt)
366
367
screen.fill((0, 0, 0))
368
all_sprites.draw(screen)
369
pygame.display.flip()
370
371
pygame.quit()
372
```
373
374
### Type-Safe Vector Math
375
376
```python
377
import pygame
378
from pygame.typing import Vector2Like, Vector3Like
379
from typing import Union
380
381
def normalize_vector2(vector: Vector2Like) -> pygame.Vector2:
382
"""Normalize a 2D vector, accepting various input types."""
383
if isinstance(vector, pygame.Vector2):
384
return vector.normalize()
385
elif isinstance(vector, (tuple, list)) and len(vector) >= 2:
386
v = pygame.Vector2(vector[0], vector[1])
387
return v.normalize()
388
else:
389
raise TypeError("Invalid vector type")
390
391
def distance_between_points(
392
point1: Vector2Like,
393
point2: Vector2Like
394
) -> float:
395
"""Calculate distance between two points."""
396
p1 = pygame.Vector2(point1) if not isinstance(point1, pygame.Vector2) else point1
397
p2 = pygame.Vector2(point2) if not isinstance(point2, pygame.Vector2) else point2
398
return p1.distance_to(p2)
399
400
def interpolate_vectors(
401
start: Vector2Like,
402
end: Vector2Like,
403
t: float
404
) -> pygame.Vector2:
405
"""Linear interpolation between two vectors."""
406
v1 = pygame.Vector2(start) if not isinstance(start, pygame.Vector2) else start
407
v2 = pygame.Vector2(end) if not isinstance(end, pygame.Vector2) else end
408
return v1.lerp(v2, t)
409
410
# Usage examples
411
pos1 = pygame.Vector2(100, 100)
412
pos2 = (200, 200) # Tuple also accepted
413
pos3 = [300, 300] # List also accepted
414
415
# All these work with type safety
416
normalized = normalize_vector2(pos1)
417
distance = distance_between_points(pos1, pos2)
418
midpoint = interpolate_vectors(pos1, pos3, 0.5)
419
420
print(f"Normalized: {normalized}")
421
print(f"Distance: {distance}")
422
print(f"Midpoint: {midpoint}")
423
```
424
425
### IDE Integration Example
426
427
```python
428
# mypy configuration example for pygame-ce projects
429
# mypy.ini or pyproject.toml
430
431
# [tool.mypy]
432
# python_version = "3.9"
433
# warn_return_any = true
434
# warn_unused_configs = true
435
# disallow_untyped_defs = true
436
437
import pygame
438
from pygame.typing import * # Import all type definitions
439
from typing import TYPE_CHECKING
440
441
if TYPE_CHECKING:
442
# Additional imports for type checking only
443
from typing import Any, Dict, List, Optional, Union
444
from pygame import Surface, Rect, Color
445
446
def type_safe_game_function(
447
screen: Surface,
448
sprites: List[pygame.sprite.Sprite],
449
background_color: ColorLike = (0, 0, 0),
450
fps: int = 60
451
) -> None:
452
"""Example of fully type-annotated game function."""
453
clock = pygame.time.Clock()
454
sprite_group = pygame.sprite.Group()
455
sprite_group.add(*sprites)
456
457
running: bool = True
458
while running:
459
dt: float = clock.tick(fps) / 1000.0
460
461
event: pygame.event.Event
462
for event in pygame.event.get():
463
if event.type == pygame.QUIT:
464
running = False
465
466
sprite_group.update(dt)
467
468
screen.fill(background_color)
469
sprite_group.draw(screen)
470
pygame.display.flip()
471
```
472
473
## Constants
474
475
Type-related constants and literals:
476
477
```python { .api }
478
# Literal types for common enumerations
479
BlendModes = Literal[
480
"BLENDMODE_NONE",
481
"BLENDMODE_BLEND",
482
"BLENDMODE_ADD",
483
"BLENDMODE_SUB",
484
"BLENDMODE_MULT"
485
]
486
487
SurfaceFlags = Literal[
488
"SRCALPHA",
489
"SRCCOLORKEY",
490
"RLEACCEL"
491
]
492
493
EventTypes = Literal[
494
"QUIT", "KEYDOWN", "KEYUP",
495
"MOUSEBUTTONDOWN", "MOUSEBUTTONUP", "MOUSEMOTION",
496
"JOYAXISMOTION", "JOYBUTTONDOWN", "JOYBUTTONUP"
497
]
498
499
# Type checking utilities
500
TYPE_CHECKING: bool # True during static analysis, False at runtime
501
```