Coverage for topdownengine/scenes.py: 44%

48 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-13 14:20 +0000

1import pygame as pg 

2from .math import scale_rect 

3 

4class BaseScene: 

5 """A scene that determines the behavior of the game loop. 

6  

7 Attributes: 

8 game (Game): The game object to use. 

9 ui_containers (list[UIContainer]): The list of UIContainers for this scene. 

10 """ 

11 def __init__(self, game): 

12 """Initialize the scene. 

13  

14 Args: 

15 game (Game): The game object to use. 

16 """ 

17 self.game = game 

18 self.ui_containers = [] 

19 

20 def handle_event(self, event: pg.Event): 

21 """Handle a single event. 

22  

23 Args: 

24 event (pygame.Event): The event to handle. 

25 """ 

26 for container in self.ui_containers: 

27 container.handle_event(event) 

28 

29 def update(self, dt: float): 

30 """Update the scene. 

31  

32 Args: 

33 dt (float): The deltatime. 

34 """ 

35 for container in self.ui_containers: 

36 container.update(dt) 

37 

38 def render(self, surface: pg.Surface): 

39 """Render the scene. 

40  

41 Args: 

42 surface (pygame.Surface): The Surface to render to. 

43 """ 

44 for container in self.ui_containers: 

45 container.render(surface) 

46 

47class GameplayScene(BaseScene): 

48 """A scene that updates and renders all `GameObject` instances. 

49  

50 Attributes: 

51 global_alpha (int): The global alpha for lighting. 

52 """ 

53 

54 def __init__(self, game): 

55 """Initialize the GameplayScene. 

56  

57 Args: 

58 game (Game): The game object to use. 

59 """ 

60 super().__init__(game) 

61 self.global_alpha = 0 

62 self._light_filters = {} 

63 

64 def get_light(self, radius: int): 

65 """Get the cached light surface of a given radius. One will be created and stored if it doesn't already exist. 

66  

67 Args: 

68 radius (int): The radius of the light. 

69 """ 

70 if not radius in self._light_filters: 

71 self._light_filters[radius] = self.create_light(radius) 

72 return self._light_filters[(radius)] 

73 

74 def create_light(self, radius: int): 

75 """Create a light surface for a given radius. 

76  

77 Args: 

78 radius (int): The radius of the new light. 

79 """ 

80 surface = pg.Surface((max(radius * 2, 1), max(radius * 2, 1)), pg.SRCALPHA) 

81 for i in range(int(radius), 0, -1): 

82 alpha = 255 * (1 - i / radius) 

83 pg.draw.circle(surface, (0, 0, 0, alpha), (radius, radius), i) 

84 return surface 

85 

86 def update(self, dt): 

87 """Update the GameplayScene. 

88  

89 Args: 

90 dt (float): The deltatime. 

91 """ 

92 super().update(dt) 

93 self.game.game_object_group.update(dt, self.game) 

94 

95 def render(self, surface: pg.Surface): 

96 """Render the GameplayScene. 

97  

98 Args: 

99 surface (pygame.Surface): The Surface to render to. 

100 """ 

101 overlay = pg.Surface(surface.size, pg.SRCALPHA) 

102 overlay.fill((0, 0, 0, self.global_alpha)) 

103 

104 for game_object in sorted(self.game.game_object_group.game_objects, key=lambda g: g.draw_index): 

105 cr = game_object.rect.move(-self.game.camera.position * game_object.SCALE) 

106 surface.blit(game_object.image, cr) 

107 if self.global_alpha > 0 and game_object.light_radius > 0: 

108 scaled_lr = game_object.light_radius * game_object.SCALE 

109 overlay.blit( 

110 self.get_light(scaled_lr), 

111 ( 

112 cr.centerx - scaled_lr, 

113 cr.bottom - scaled_lr - game_object.z * game_object.SCALE - game_object.current_frame.height / 2 + game_object.elevation * game_object.SCALE 

114 ), 

115 special_flags=pg.BLEND_RGBA_SUB 

116 ) 

117 

118 # Draw debug in a separate loop so that it is drawn over images. 

119 if self.game.debug: 

120 for game_object in self.game.game_object_group.game_objects: 

121 # Draw Colliders 

122 for collider in game_object.world_colliders: 

123 pg.draw.rect( 

124 surface, 

125 (0, 0, 255), 

126 scale_rect(collider.move(-self.game.camera.position), game_object.SCALE), 

127 1 

128 ) 

129 

130 surface.blit(overlay, (0, 0)) 

131 

132 super().render(surface) # Draw UI