0
# Sprite System and Collision Detection
1
2
Complete sprite management system for game objects with support for animations, physics properties, collision detection, and efficient batch rendering through sprite lists.
3
4
## Capabilities
5
6
### Core Sprite Classes
7
8
Base sprite classes providing the foundation for all game objects in Arcade.
9
10
```python { .api }
11
class Sprite:
12
"""
13
Main sprite class for creating game objects with position, rotation, texture, and physics properties.
14
"""
15
def __init__(self, filename: str = None, scale: float = 1, image_x: float = 0, image_y: float = 0,
16
image_width: float = 0, image_height: float = 0, center_x: float = 0, center_y: float = 0,
17
repeat_count_x: int = 1, repeat_count_y: int = 1, flipped_horizontally: bool = False,
18
flipped_vertically: bool = False, flipped_diagonally: bool = False, hit_box_algorithm: str = "Simple",
19
hit_box_detail: float = 4.5, texture: arcade.Texture = None, angle: float = 0):
20
"""
21
Create a new sprite.
22
23
Args:
24
filename: Path to texture file or resource handle (e.g., ":resources:images/...")
25
scale: Scale factor for the sprite
26
image_x: X offset within source image
27
image_y: Y offset within source image
28
image_width: Width of region to use from source image
29
image_height: Height of region to use from source image
30
center_x: Initial X position
31
center_y: Initial Y position
32
repeat_count_x: Number of times to repeat texture horizontally
33
repeat_count_y: Number of times to repeat texture vertically
34
flipped_horizontally: Mirror sprite horizontally
35
flipped_vertically: Mirror sprite vertically
36
flipped_diagonally: Mirror sprite diagonally
37
hit_box_algorithm: Algorithm for hit box calculation ("Simple", "Detailed", or "None")
38
hit_box_detail: Detail level for "Detailed" hit box algorithm
39
texture: Texture object to use instead of loading from file
40
angle: Initial rotation angle in degrees
41
"""
42
43
# Position properties
44
center_x: float
45
center_y: float
46
left: float
47
right: float
48
top: float
49
bottom: float
50
51
# Movement properties
52
change_x: float
53
change_y: float
54
velocity: tuple[float, float]
55
56
# Rotation properties
57
angle: float
58
change_angle: float
59
radians: float
60
61
# Scale properties
62
scale: float
63
width: float
64
height: float
65
66
# Physics properties
67
physics_engines: list
68
69
# Texture properties
70
texture: arcade.Texture
71
textures: list[arcade.Texture]
72
cur_texture_index: int
73
74
# Hit box and collision
75
hit_box: list[tuple[float, float]]
76
77
# Identification
78
guid: str
79
80
def update(self) -> None:
81
"""Update sprite position based on velocity."""
82
83
def update_animation(self, delta_time: float = 1/60) -> None:
84
"""Update sprite animation."""
85
86
def on_update(self, delta_time: float = 1/60) -> None:
87
"""Override this method to add custom update logic."""
88
89
def draw(self, *, filter=None, pixelated=None, blend_function=None) -> None:
90
"""Draw the sprite."""
91
92
def draw_hit_box(self, color: arcade.types.Color = arcade.color.BLACK, line_thickness: float = 1) -> None:
93
"""Draw the sprite's hit box for debugging."""
94
95
def set_hit_box(self, points: list[tuple[float, float]]) -> None:
96
"""Manually set the hit box points."""
97
98
def get_adjusted_hit_box(self) -> list[tuple[float, float]]:
99
"""Get hit box adjusted for current position and rotation."""
100
101
class BasicSprite:
102
"""
103
Minimal sprite implementation with reduced memory footprint for simple use cases.
104
"""
105
def __init__(self, filename: str = None, scale: float = 1, center_x: float = 0, center_y: float = 0):
106
"""Create a basic sprite with minimal properties."""
107
108
center_x: float
109
center_y: float
110
angle: float
111
scale: float
112
texture: arcade.Texture
113
```
114
115
### Specialized Sprite Types
116
117
Pre-configured sprite classes for common game object patterns.
118
119
```python { .api }
120
class SpriteSolidColor(arcade.Sprite):
121
"""
122
Sprite with a solid color rectangle instead of a texture.
123
"""
124
def __init__(self, width: int, height: int, color: arcade.types.Color, center_x: float = 0, center_y: float = 0):
125
"""
126
Create a solid color sprite.
127
128
Args:
129
width: Width of the rectangle
130
height: Height of the rectangle
131
color: Color as RGB or RGBA tuple (0-255)
132
center_x: Initial X position
133
center_y: Initial Y position
134
"""
135
136
class SpriteCircle(arcade.Sprite):
137
"""
138
Sprite with a circular shape.
139
"""
140
def __init__(self, radius: int, color: arcade.types.Color, soft: bool = False, center_x: float = 0, center_y: float = 0):
141
"""
142
Create a circular sprite.
143
144
Args:
145
radius: Radius of the circle
146
color: Color as RGB or RGBA tuple (0-255)
147
soft: Whether to use soft edges
148
center_x: Initial X position
149
center_y: Initial Y position
150
"""
151
152
class TextureAnimationSprite(arcade.Sprite):
153
"""
154
Sprite with texture-based animation support.
155
"""
156
def __init__(self, filename: str = None, scale: float = 1):
157
"""Create an animated sprite."""
158
159
def update_animation(self, delta_time: float = 1/60) -> None:
160
"""Update animation based on elapsed time."""
161
162
class AnimatedWalkingSprite(arcade.Sprite):
163
"""
164
Sprite with directional walking animations.
165
"""
166
def __init__(self, scale: float = 1):
167
"""Create a walking animated sprite."""
168
169
# Texture lists for different directions
170
walk_up_textures: list[arcade.Texture]
171
walk_down_textures: list[arcade.Texture]
172
walk_left_textures: list[arcade.Texture]
173
walk_right_textures: list[arcade.Texture]
174
stand_up_textures: list[arcade.Texture]
175
stand_down_textures: list[arcade.Texture]
176
stand_left_textures: list[arcade.Texture]
177
stand_right_textures: list[arcade.Texture]
178
179
def update_animation(self, delta_time: float = 1/60) -> None:
180
"""Update walking animation based on movement direction."""
181
```
182
183
### Sprite Lists
184
185
Efficient containers for managing and rendering groups of sprites.
186
187
```python { .api }
188
class SpriteList:
189
"""
190
Container for managing groups of sprites with optimized batch rendering.
191
"""
192
def __init__(self, use_spatial_hash: bool = None, spatial_hash_cell_size: int = 128,
193
is_static: bool = False, atlas: arcade.TextureAtlasBase = None):
194
"""
195
Create a new sprite list.
196
197
Args:
198
use_spatial_hash: Enable spatial hashing for collision optimization
199
spatial_hash_cell_size: Size of spatial hash cells
200
is_static: Whether sprites in this list move (enables optimizations)
201
atlas: Custom texture atlas to use
202
"""
203
204
def append(self, sprite: arcade.Sprite) -> None:
205
"""Add a sprite to the list."""
206
207
def remove(self, sprite: arcade.Sprite) -> None:
208
"""Remove a sprite from the list."""
209
210
def insert(self, index: int, sprite: arcade.Sprite) -> None:
211
"""Insert a sprite at a specific index."""
212
213
def extend(self, sprites: list[arcade.Sprite]) -> None:
214
"""Add multiple sprites to the list."""
215
216
def clear(self) -> None:
217
"""Remove all sprites from the list."""
218
219
def update(self) -> None:
220
"""Update all sprites in the list."""
221
222
def update_animation(self, delta_time: float = 1/60) -> None:
223
"""Update animations for all sprites in the list."""
224
225
def on_update(self, delta_time: float = 1/60) -> None:
226
"""Override this method for custom update logic."""
227
228
def draw(self, *, filter=None, pixelated=None, blend_function=None) -> None:
229
"""Draw all sprites in the list using batch rendering."""
230
231
def draw_hit_boxes(self, color: arcade.types.Color = arcade.color.BLACK, line_thickness: float = 1) -> None:
232
"""Draw hit boxes for all sprites (debugging)."""
233
234
def move(self, change_x: float, change_y: float) -> None:
235
"""Move all sprites in the list by the specified offset."""
236
237
# List-like operations
238
def __len__(self) -> int:
239
"""Get the number of sprites in the list."""
240
241
def __getitem__(self, index: int) -> arcade.Sprite:
242
"""Get a sprite by index."""
243
244
def __iter__(self):
245
"""Iterate over sprites in the list."""
246
247
def __contains__(self, sprite: arcade.Sprite) -> bool:
248
"""Check if a sprite is in the list."""
249
250
class SpriteSequence:
251
"""
252
Sequence interface for sprite lists with additional functionality.
253
"""
254
def __init__(self):
255
"""Create a new sprite sequence."""
256
257
def pop(self, index: int = -1) -> arcade.Sprite:
258
"""Remove and return sprite at index."""
259
260
def reverse(self) -> None:
261
"""Reverse the order of sprites."""
262
263
def shuffle(self) -> None:
264
"""Randomly shuffle the sprites."""
265
```
266
267
### Spatial Indexing
268
269
Spatial data structures for optimizing collision detection and spatial queries.
270
271
```python { .api }
272
class SpatialHash:
273
"""
274
Spatial hash grid for efficient collision detection and spatial queries.
275
"""
276
def __init__(self, cell_size: int = 128):
277
"""
278
Create a spatial hash.
279
280
Args:
281
cell_size: Size of each hash cell in pixels
282
"""
283
284
def insert_object_for_box(self, new_object: arcade.Sprite) -> None:
285
"""Insert a sprite into the spatial hash."""
286
287
def remove_object(self, sprite_to_remove: arcade.Sprite) -> None:
288
"""Remove a sprite from the spatial hash."""
289
290
def get_objects_for_box(self, check_object: arcade.Sprite) -> list[arcade.Sprite]:
291
"""Get all objects that might collide with the given sprite."""
292
293
def reset(self) -> None:
294
"""Clear all objects from the spatial hash."""
295
```
296
297
### Animation System
298
299
Classes for managing texture-based sprite animations.
300
301
```python { .api }
302
class TextureAnimation:
303
"""
304
Container for managing a sequence of animation frames.
305
"""
306
def __init__(self, keyframes: list[arcade.TextureKeyframe] = None):
307
"""
308
Create a texture animation.
309
310
Args:
311
keyframes: List of animation keyframes
312
"""
313
314
keyframes: list[arcade.TextureKeyframe]
315
316
def add_keyframe(self, keyframe: arcade.TextureKeyframe) -> None:
317
"""Add a keyframe to the animation."""
318
319
class TextureKeyframe:
320
"""
321
Single frame in a texture animation with timing information.
322
"""
323
def __init__(self, texture: arcade.Texture, duration: float = 1.0):
324
"""
325
Create an animation keyframe.
326
327
Args:
328
texture: Texture to display during this frame
329
duration: Duration to display this frame (in seconds or frame counts)
330
"""
331
332
texture: arcade.Texture
333
duration: float
334
335
def load_animated_gif(filename: str, scale: float = 1) -> arcade.TextureAnimationSprite:
336
"""
337
Load an animated GIF file as an animated sprite.
338
339
Args:
340
filename: Path to GIF file
341
scale: Scale factor for the sprite
342
343
Returns:
344
TextureAnimationSprite with frames from the GIF
345
"""
346
```
347
348
### Physics Integration
349
350
Mixins and types for integrating sprites with physics engines.
351
352
```python { .api }
353
class PymunkMixin:
354
"""
355
Mixin class for adding Pymunk physics integration to sprites.
356
"""
357
pymunk_shape: object # pymunk.Shape
358
pymunk_body: object # pymunk.Body
359
360
def pymunk_moved(self, physics_engine: arcade.PymunkPhysicsEngine, dx: float, dy: float, d_angle: float) -> None:
361
"""Called when the physics engine moves the sprite."""
362
363
# Type alias for sprites with Pymunk physics
364
PyMunk = arcade.Sprite # Sprite with PymunkMixin
365
```
366
367
### Collision Detection
368
369
Comprehensive collision detection functions for sprite interactions.
370
371
```python { .api }
372
def check_for_collision(sprite1: arcade.Sprite, sprite2: arcade.Sprite) -> bool:
373
"""
374
Check if two sprites are colliding.
375
376
Args:
377
sprite1: First sprite
378
sprite2: Second sprite
379
380
Returns:
381
True if sprites are colliding, False otherwise
382
"""
383
384
def check_for_collision_with_list(sprite: arcade.Sprite, sprite_list: arcade.SpriteList) -> list[arcade.Sprite]:
385
"""
386
Check if a sprite collides with any sprites in a list.
387
388
Args:
389
sprite: Sprite to check
390
sprite_list: List of sprites to check against
391
392
Returns:
393
List of sprites that are colliding with the input sprite
394
"""
395
396
def check_for_collision_with_lists(sprite: arcade.Sprite, sprite_lists: list[arcade.SpriteList]) -> list[arcade.Sprite]:
397
"""
398
Check if a sprite collides with sprites in multiple lists.
399
400
Args:
401
sprite: Sprite to check
402
sprite_lists: List of sprite lists to check against
403
404
Returns:
405
List of sprites that are colliding with the input sprite
406
"""
407
408
def get_closest_sprite(sprite: arcade.Sprite, sprite_list: arcade.SpriteList) -> tuple[arcade.Sprite, float]:
409
"""
410
Find the closest sprite in a list to the given sprite.
411
412
Args:
413
sprite: Reference sprite
414
sprite_list: List of sprites to search
415
416
Returns:
417
Tuple of (closest_sprite, distance) or (None, None) if list is empty
418
"""
419
420
def get_distance_between_sprites(sprite1: arcade.Sprite, sprite2: arcade.Sprite) -> float:
421
"""
422
Calculate the distance between two sprites.
423
424
Args:
425
sprite1: First sprite
426
sprite2: Second sprite
427
428
Returns:
429
Distance between sprite centers in pixels
430
"""
431
432
def get_sprites_at_point(point: tuple[float, float], sprite_list: arcade.SpriteList) -> list[arcade.Sprite]:
433
"""
434
Get all sprites that contain a specific point.
435
436
Args:
437
point: (x, y) coordinate tuple
438
sprite_list: List of sprites to check
439
440
Returns:
441
List of sprites containing the point
442
"""
443
444
def get_sprites_at_exact_point(point: tuple[float, float], sprite_list: arcade.SpriteList) -> list[arcade.Sprite]:
445
"""
446
Get sprites at an exact point (no hit box checking).
447
448
Args:
449
point: (x, y) coordinate tuple
450
sprite_list: List of sprites to check
451
452
Returns:
453
List of sprites at the exact point
454
"""
455
456
def get_sprites_in_rect(rect: arcade.types.Rect, sprite_list: arcade.SpriteList) -> list[arcade.Sprite]:
457
"""
458
Get all sprites within a rectangular area.
459
460
Args:
461
rect: Rectangle to check (x, y, width, height)
462
sprite_list: List of sprites to check
463
464
Returns:
465
List of sprites within the rectangle
466
"""
467
```
468
469
### Sprite Constants and Types
470
471
Direction constants and type definitions for sprite system.
472
473
```python { .api }
474
# Direction constants for sprite facing
475
FACE_LEFT: str = "left"
476
FACE_RIGHT: str = "right"
477
FACE_UP: str = "up"
478
FACE_DOWN: str = "down"
479
480
# Type definitions
481
SpriteType = arcade.Sprite # Base sprite type
482
SpriteType_co = arcade.Sprite # Covariant sprite type (for type hints)
483
```
484
485
## Usage Examples
486
487
### Basic Sprite Creation and Management
488
489
```python
490
import arcade
491
492
class GameView(arcade.View):
493
def __init__(self):
494
super().__init__()
495
496
# Create sprite lists
497
self.player_list = arcade.SpriteList()
498
self.enemy_list = arcade.SpriteList()
499
self.coin_list = arcade.SpriteList()
500
501
def setup(self):
502
# Create player sprite
503
self.player = arcade.Sprite(":resources:images/space_shooter/meteorGrey_med1.png", 0.5)
504
self.player.center_x = 400
505
self.player.center_y = 300
506
self.player_list.append(self.player)
507
508
# Create enemy sprites
509
for i in range(5):
510
enemy = arcade.Sprite(":resources:images/space_shooter/meteorGrey_med2.png", 0.3)
511
enemy.center_x = 100 + i * 150
512
enemy.center_y = 500
513
enemy.change_y = -2
514
self.enemy_list.append(enemy)
515
516
# Create collectible coins
517
for i in range(10):
518
coin = arcade.SpriteCircle(15, arcade.color.YELLOW)
519
coin.center_x = 50 + i * 70
520
coin.center_y = 100
521
self.coin_list.append(coin)
522
523
def on_update(self, delta_time):
524
# Update all sprites
525
self.player_list.update()
526
self.enemy_list.update()
527
528
# Check collisions
529
hit_list = arcade.check_for_collision_with_list(self.player, self.coin_list)
530
for coin in hit_list:
531
coin.remove_from_sprite_lists()
532
533
# Check enemy collisions
534
if arcade.check_for_collision_with_list(self.player, self.enemy_list):
535
print("Player hit by enemy!")
536
537
def on_draw(self):
538
self.clear()
539
self.player_list.draw()
540
self.enemy_list.draw()
541
self.coin_list.draw()
542
```
543
544
### Animated Sprite Example
545
546
```python
547
import arcade
548
549
class AnimatedPlayer(arcade.AnimatedWalkingSprite):
550
def __init__(self):
551
super().__init__(scale=0.5)
552
553
# Load walking animations
554
self.walk_right_textures = []
555
for i in range(8):
556
texture = arcade.load_texture(f":resources:images/animated_characters/female_person/femalePerson_walk{i}.png")
557
self.walk_right_textures.append(texture)
558
559
# Mirror for left walking
560
self.walk_left_textures = []
561
for texture in self.walk_right_textures:
562
self.walk_left_textures.append(texture.texture.flip_horizontally())
563
564
# Set initial texture
565
self.texture = self.walk_right_textures[0]
566
567
def update_animation(self, delta_time: float = 1/60):
568
# Update animation based on movement
569
if self.change_x > 0:
570
self.texture = self.walk_right_textures[int(self.cur_texture_index)]
571
elif self.change_x < 0:
572
self.texture = self.walk_left_textures[int(self.cur_texture_index)]
573
574
# Advance animation frame
575
if abs(self.change_x) > 0:
576
self.cur_texture_index += 0.1
577
if self.cur_texture_index >= len(self.walk_right_textures):
578
self.cur_texture_index = 0
579
580
class GameView(arcade.View):
581
def setup(self):
582
self.player_list = arcade.SpriteList()
583
self.player = AnimatedPlayer()
584
self.player.center_x = 400
585
self.player.center_y = 300
586
self.player_list.append(self.player)
587
588
def on_update(self, delta_time):
589
self.player_list.update()
590
self.player_list.update_animation(delta_time)
591
592
def on_key_press(self, key, modifiers):
593
if key == arcade.key.LEFT:
594
self.player.change_x = -5
595
elif key == arcade.key.RIGHT:
596
self.player.change_x = 5
597
598
def on_key_release(self, key, modifiers):
599
if key in (arcade.key.LEFT, arcade.key.RIGHT):
600
self.player.change_x = 0
601
```