batframework 1.0.8a8__py3-none-any.whl → 1.0.8a10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. batFramework/__init__.py +68 -51
  2. batFramework/action.py +126 -99
  3. batFramework/actionContainer.py +53 -9
  4. batFramework/animatedSprite.py +141 -82
  5. batFramework/audioManager.py +69 -26
  6. batFramework/camera.py +259 -69
  7. batFramework/character.py +27 -0
  8. batFramework/constants.py +16 -54
  9. batFramework/cutscene.py +39 -29
  10. batFramework/cutsceneBlocks.py +36 -43
  11. batFramework/dynamicEntity.py +18 -9
  12. batFramework/easingController.py +58 -0
  13. batFramework/entity.py +48 -97
  14. batFramework/enums.py +113 -0
  15. batFramework/fontManager.py +65 -0
  16. batFramework/gui/__init__.py +10 -2
  17. batFramework/gui/button.py +9 -78
  18. batFramework/gui/clickableWidget.py +220 -0
  19. batFramework/gui/constraints/__init__.py +1 -0
  20. batFramework/gui/constraints/constraints.py +815 -0
  21. batFramework/gui/container.py +174 -32
  22. batFramework/gui/debugger.py +131 -43
  23. batFramework/gui/dialogueBox.py +99 -0
  24. batFramework/gui/draggableWidget.py +40 -0
  25. batFramework/gui/image.py +56 -20
  26. batFramework/gui/indicator.py +38 -21
  27. batFramework/gui/interactiveWidget.py +192 -13
  28. batFramework/gui/label.py +309 -74
  29. batFramework/gui/layout.py +231 -63
  30. batFramework/gui/meter.py +74 -0
  31. batFramework/gui/radioButton.py +84 -0
  32. batFramework/gui/root.py +134 -38
  33. batFramework/gui/shape.py +237 -57
  34. batFramework/gui/slider.py +240 -0
  35. batFramework/gui/style.py +10 -0
  36. batFramework/gui/styleManager.py +48 -0
  37. batFramework/gui/textInput.py +247 -0
  38. batFramework/gui/toggle.py +101 -51
  39. batFramework/gui/widget.py +358 -250
  40. batFramework/manager.py +52 -19
  41. batFramework/object.py +123 -0
  42. batFramework/particle.py +115 -0
  43. batFramework/renderGroup.py +67 -0
  44. batFramework/resourceManager.py +100 -0
  45. batFramework/scene.py +281 -123
  46. batFramework/sceneManager.py +178 -116
  47. batFramework/scrollingSprite.py +114 -0
  48. batFramework/sprite.py +51 -0
  49. batFramework/stateMachine.py +11 -8
  50. batFramework/templates/__init__.py +2 -0
  51. batFramework/templates/character.py +44 -0
  52. batFramework/templates/states.py +166 -0
  53. batFramework/tileset.py +46 -0
  54. batFramework/time.py +145 -58
  55. batFramework/transition.py +195 -124
  56. batFramework/triggerZone.py +1 -1
  57. batFramework/utils.py +112 -147
  58. batframework-1.0.8a10.dist-info/LICENCE +21 -0
  59. batframework-1.0.8a10.dist-info/METADATA +43 -0
  60. batframework-1.0.8a10.dist-info/RECORD +62 -0
  61. batFramework/debugger.py +0 -48
  62. batFramework/easing.py +0 -71
  63. batFramework/gui/constraints.py +0 -204
  64. batFramework/gui/frame.py +0 -19
  65. batFramework/particles.py +0 -77
  66. batFramework/transitionManager.py +0 -0
  67. batframework-1.0.8a8.dist-info/METADATA +0 -53
  68. batframework-1.0.8a8.dist-info/RECORD +0 -42
  69. {batframework-1.0.8a8.dist-info → batframework-1.0.8a10.dist-info}/WHEEL +0 -0
  70. {batframework-1.0.8a8.dist-info → batframework-1.0.8a10.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,166 @@
1
+ import batFramework as bf
2
+ from typing import TYPE_CHECKING
3
+
4
+ if TYPE_CHECKING:
5
+ from .character import Platform2DCharacter
6
+
7
+
8
+ class CharacterState(bf.State):
9
+ def set_parent(self, parent):
10
+ """Initialize the parent character."""
11
+ res = super().set_parent(parent)
12
+ if res:
13
+ self.parent: Platform2DCharacter = parent
14
+ return res
15
+
16
+ def on_enter(self):
17
+ """Handle state entry."""
18
+ self.parent.set_animation(self.name)
19
+
20
+ def handle_input(self):
21
+ """Process input and update movement direction."""
22
+ if self.parent.actions.is_active("right"):
23
+ self._apply_horizontal_input(self.parent.acceleration, self.parent.speed)
24
+ if self.parent.actions.is_active("left"):
25
+ self._apply_horizontal_input(-self.parent.acceleration, -self.parent.speed)
26
+
27
+ if self.parent.velocity.x > 0:
28
+ self.parent.set_flipX(False)
29
+ elif self.parent.velocity.x < 0:
30
+ self.parent.set_flipX(True)
31
+
32
+
33
+ def _apply_horizontal_input(self, acceleration, limit):
34
+ """Apply input acceleration and enforce speed limit."""
35
+
36
+ self.parent.velocity.x += acceleration
37
+ if abs(self.parent.velocity.x) > abs(limit):
38
+ self.parent.velocity.x = limit
39
+
40
+ def apply_friction(self):
41
+ """Apply friction to horizontal velocity."""
42
+ if (self.parent.actions.is_active("right") or self.parent.actions.is_active("left")):
43
+ return
44
+
45
+ if abs(self.parent.velocity.x) < 0.01: # Threshold for negligible velocity
46
+ self.parent.velocity.x = 0
47
+ else:
48
+ self.parent.velocity.x *= self.parent.friction
49
+
50
+ def apply_gravity(self, dt):
51
+ """Apply gravity to vertical velocity."""
52
+ self.parent.velocity.y += self.parent.gravity * dt
53
+ self.parent.velocity.y = min(self.parent.velocity.y, self.parent.terminal_velocity)
54
+
55
+ def move_character(self, dt):
56
+ """Move the character based on velocity."""
57
+ self.parent.rect.x += self.parent.velocity.x * dt
58
+ self.parent.rect.y += self.parent.velocity.y * dt
59
+
60
+ def update(self, dt):
61
+ """Update the character state."""
62
+ self.handle_input()
63
+ self.apply_physics(dt)
64
+ self.handle_collision()
65
+
66
+ def apply_physics(self, dt):
67
+ """Apply all physics effects."""
68
+ self.apply_friction()
69
+ self.move_character(dt)
70
+ if self.parent.on_ground:
71
+ self.parent.velocity.y = 0 # Stop downward movement on ground
72
+
73
+ def handle_collision(self):
74
+ """Placeholder for collision detection and resolution."""
75
+ pass # Future collision code goes here
76
+
77
+
78
+ class Platform2DIdle(CharacterState):
79
+ def __init__(self) -> None:
80
+ super().__init__("idle")
81
+
82
+ def on_enter(self):
83
+ self.parent.jump_counter = 0
84
+ super().on_enter()
85
+
86
+ def update(self, dt):
87
+ super().update(dt)
88
+
89
+ if not self.parent.on_ground:
90
+ self.parent.set_state("fall")
91
+ elif self.parent.velocity.x != 0:
92
+ self.parent.set_state("run")
93
+ elif self.parent.actions.is_active("jump"):
94
+ self.parent.set_state("jump")
95
+
96
+
97
+ class Platform2DRun(CharacterState):
98
+ def __init__(self) -> None:
99
+ super().__init__("run")
100
+
101
+
102
+ def on_enter(self):
103
+ self.parent.jump_counter = 0
104
+ super().on_enter()
105
+
106
+ def update(self, dt):
107
+ super().update(dt)
108
+
109
+ if self.parent.velocity.x :
110
+ if (self.parent.actions.is_active("right") or self.parent.actions.is_active("left")):
111
+ if self.parent.get_current_animation().name != "run" : self.parent.set_animation("run")
112
+ else:
113
+ if self.parent.get_current_animation().name != "idle" : self.parent.set_animation("idle")
114
+
115
+ if self.parent.actions.is_active("jump"):
116
+ self.parent.set_state("jump")
117
+ elif self.parent.velocity.x == 0:
118
+ if not (self.parent.actions.is_active("right") or self.parent.actions.is_active("left")):
119
+ self.parent.set_state("idle")
120
+ elif not self.parent.on_ground:
121
+ self.parent.set_state("fall")
122
+
123
+
124
+
125
+
126
+ class Platform2DJump(CharacterState):
127
+ def __init__(self) -> None:
128
+ super().__init__("jump")
129
+
130
+ def on_enter(self):
131
+ super().on_enter()
132
+ self.parent.on_ground = False
133
+ self.parent.velocity.y = -self.parent.jump_force
134
+ self.parent.jump_counter += 1
135
+
136
+ def update(self, dt):
137
+ super().update(dt)
138
+ self.apply_gravity(dt)
139
+
140
+
141
+ if self.parent.jump_counter < self.parent.max_jumps:
142
+ if self.parent.actions.is_active("jump") and (self.parent.velocity.y//10)*10 == 0:
143
+ self.parent.set_state("jump")
144
+ return
145
+
146
+
147
+ if self.parent.velocity.y > 0:
148
+ self.parent.set_state("fall")
149
+
150
+
151
+ class Platform2DFall(CharacterState):
152
+ def __init__(self) -> None:
153
+ super().__init__("fall")
154
+
155
+ def update(self, dt):
156
+ super().update(dt)
157
+ self.apply_gravity(dt)
158
+
159
+ if self.parent.on_ground:
160
+ if abs(self.parent.velocity.x) > 0.01:
161
+ self.parent.set_state("run")
162
+ else:
163
+ self.parent.set_state("idle")
164
+
165
+ if self.parent.actions.is_active("jump") and self.parent.jump_counter < self.parent.max_jumps:
166
+ self.parent.set_state("jump")
@@ -0,0 +1,46 @@
1
+ import pygame
2
+ from .resourceManager import ResourceManager
3
+ import batFramework as bf
4
+
5
+
6
+ class Tileset:
7
+ def __init__(self, source: pygame.Surface, tilesize: tuple[int, int]) -> None:
8
+ self.surface = source
9
+ self.tile_size = tilesize
10
+ self.tile_width = source.get_width() // tilesize[0]
11
+ self.tile_height = source.get_height() // tilesize[1]
12
+ # Create flipped versions of the tileset surface
13
+ self.flipped_surfaces = {
14
+ (False, False): self.surface,
15
+ (False, True): pygame.transform.flip(self.surface, False, True),
16
+ (True, False): pygame.transform.flip(self.surface, True, False),
17
+ (True, True): pygame.transform.flip(self.surface, True, True),
18
+ }
19
+
20
+ # Split each of the surfaces into tiles
21
+ self.tile_dict = {}
22
+ for flip_state, surf in self.flipped_surfaces.items():
23
+ tiles = bf.utils.split_surface(surf, self.tile_size)
24
+ for coord, tile in tiles.items():
25
+ if coord not in self.tile_dict:
26
+ self.tile_dict[coord] = {}
27
+ self.tile_dict[coord][flip_state] = tile
28
+
29
+ def __str__(self) -> str:
30
+ num_tiles = 0
31
+ if self.tile_dict:
32
+ num_tiles = len(self.tile_dict.values())
33
+ return f"{num_tiles} tiles | Tile size : {self.tile_size}"
34
+
35
+ def get_tile(
36
+ self, x: int, y: int, flipX=False, flipY=False
37
+ ) -> pygame.Surface | None:
38
+ if flipX:
39
+ x = self.tile_width - 1 - x
40
+ if flipY:
41
+ y = self.tile_height - 1 - y
42
+ tile_data = self.tile_dict.get((x, y), None)
43
+ if tile_data is None:
44
+ return None
45
+
46
+ return tile_data.get((flipX, flipY), None)
batFramework/time.py CHANGED
@@ -1,75 +1,162 @@
1
- import pygame
2
1
  import batFramework as bf
2
+ from typing import Self
3
+
4
+
5
+ from typing import Callable, Union, Self
6
+
3
7
 
4
8
  class Timer:
5
- _highest_count = 0
6
- def __init__(self, name=None, duration=1000, loop=False, end_callback=None,reusable:bool=False):
7
- # Initialize timer properties
8
- self.start_time = None
9
- self.stopped = True
10
- self.name = name if name is not None else self._highest_count
11
- Timer._highest_count += 1
12
- self.duration = duration
13
- self.loop = loop
14
- self.elapsed_progress = 0.0
9
+ _count: int = 0
10
+ _available_ids: set[int] = set()
11
+
12
+ def __init__(self, duration: Union[float, int], end_callback: Callable, loop: bool = False, register: str = "global") -> None:
13
+ if Timer._available_ids:
14
+ self.uid = Timer._available_ids.pop()
15
+ else:
16
+ self.uid = Timer._count
17
+ Timer._count += 1
18
+
19
+ self.register = register
20
+ self.duration: int | float = duration
15
21
  self.end_callback = end_callback
16
- self.reusable:bool = reusable
17
- def start(self):
18
- # Start the timer and set the start time
19
- if self.start_time is None:
20
- Time().add_timer(self)
21
-
22
- self.start_time = pygame.time.get_ticks()
23
- self.stopped = False
24
- self.elapsed_progress = 0.0
25
-
26
- def update(self):
27
- if self.stopped : return False
28
- current_time = pygame.time.get_ticks()
29
- if self.elapsed_progress < 1:
30
- # Calculate elapsed progress
31
- self.elapsed_progress = (current_time - self.start_time) / self.duration
32
- if self.elapsed_progress >= 1:
33
- # Timer has completed
34
- self.end()
35
- return True
36
- elif self.loop:
37
- # If looping, restart the timer
38
- self.start()
39
- return False
40
22
 
41
- def stop(self):
42
- # Stop the timer
43
- self.stopped = True
23
+ self.elapsed_time: float = -1
24
+ self.is_over: bool = False
25
+ self.is_looping: bool = loop
26
+ self.is_paused: bool = False
27
+ self.do_delete: bool = False
28
+
29
+ def __bool__(self)->bool:
30
+ return self.elapsed_time==-1 or self.is_over
31
+
32
+ def __str__(self) -> str:
33
+ return f"Timer ({self.uid}) {self.elapsed_time}/{self.duration} | {'loop ' if self.is_looping else ''} {'(D) ' if self.do_delete else ''}"
34
+
35
+ def stop(self) -> Self:
36
+ self.elapsed_time = -1
37
+ self.is_over = False
38
+ self.is_paused = False
39
+ return self
40
+
41
+ def start(self, force: bool = False) -> Self:
42
+ if self.elapsed_time != -1 and not force:
43
+ return self
44
+ if not bf.TimeManager().add_timer(self,self.register):
45
+ return self
46
+ self.elapsed_time = 0
47
+ self.is_paused = False
48
+ self.is_over = False
49
+ return self
50
+
51
+ def pause(self) -> Self:
52
+ self.is_paused = True
53
+ return self
54
+
55
+ def resume(self) -> Self:
56
+ self.is_paused = False
57
+ return self
58
+
59
+ def delete(self) -> Self:
60
+ self.do_delete = True
61
+ return self
62
+
63
+ def has_started(self) -> bool:
64
+ return self.elapsed_time != -1
65
+
66
+ def get_progression(self) -> float:
67
+ if self.elapsed_time < 0:
68
+ return 0
69
+ if self.elapsed_time >= self.duration:
70
+ return 1
71
+ return self.elapsed_time / self.duration
72
+
73
+ def update(self, dt) -> None:
74
+ if self.elapsed_time < 0 or self.is_paused or self.is_over:
75
+ return
76
+ self.elapsed_time += dt
77
+ # print("update :",self.elapsed_time,self.duration)
78
+ if self.get_progression() == 1:
79
+ self.end()
44
80
 
45
81
  def end(self):
46
- self.elapsed_progress = 1
47
- self.stopped = False
48
82
  if self.end_callback:
49
83
  self.end_callback()
84
+ self.elapsed_time = -1
85
+ self.is_over = True
86
+ if self.is_looping:
87
+ self.start()
88
+ return
89
+
90
+ def should_delete(self) -> bool:
91
+ return self.is_over or self.do_delete
92
+
93
+ def _release_id(self):
94
+ Timer._available_ids.add(self.uid)
95
+
96
+
97
+ class SceneTimer(Timer):
98
+ def __init__(self, duration: float | int, end_callback, loop: bool = False, scene_name:str = "global") -> None:
99
+ super().__init__(duration, end_callback, loop, scene_name)
50
100
 
51
- def ended(self):
52
- if self.start_time is None:
53
- return False
54
- return (not self.loop) and (self.elapsed_progress >= 1) and (not self.stopped) and not self.reusable
101
+ class TimeManager(metaclass=bf.Singleton):
102
+ class TimerRegister:
103
+ def __init__(self, active=True):
104
+ self.active = active
105
+ self.timers: dict[int | str, Timer] = {}
55
106
 
107
+ def __iter__(self):
108
+ return iter(self.timers.values())
109
+
110
+ def add_timer(self, timer: Timer):
111
+ self.timers[timer.uid] = timer
112
+
113
+ def update(self, dt):
114
+ expired_timers = []
115
+ for timer in list(self.timers.values()):
116
+ if not timer.is_paused:
117
+ timer.update(dt)
118
+ if timer.should_delete():
119
+ expired_timers.append(timer.uid)
120
+ for uid in expired_timers:
121
+ self.timers[uid]._release_id()
122
+ del self.timers[uid]
56
123
 
57
- class Time(metaclass=bf.Singleton):
58
124
  def __init__(self):
59
- # Initialize the Time class with a dictionary of timers
60
- self.timers = {}
125
+ self.registers = {"global": TimeManager.TimerRegister()}
126
+
127
+ def add_register(self, name, active=True):
128
+ if name not in self.registers:
129
+ self.registers[name] = TimeManager.TimerRegister(active)
130
+
131
+ def add_timer(self, timer, register="global") -> bool:
132
+ if register in self.registers:
133
+ self.registers[register].add_timer(timer)
134
+ return True
135
+ print(f"Register '{register}' does not exist.")
136
+ return False
137
+
138
+ def get_active_registers(self) -> list[TimerRegister]:
139
+ return [t for t in self.registers.values() if t.active]
61
140
 
62
- def add_timer(self, timer):
63
- # Add a timer to the dictionary
64
- self.timers[timer.name] = timer
141
+ def update(self, dt):
142
+ for register_name, register in self.registers.items():
143
+ if register.active:
144
+ register.update(dt)
65
145
 
66
- def update(self):
67
- # Update all timers and remove completed ones
68
- for timer in list(self.timers.values()):
69
- timer.update()
146
+ def activate_register(self, name, active=True):
147
+ if name in self.registers:
148
+ self.registers[name].active = active
149
+ else:
150
+ print(f"Register '{name}' does not exist.")
70
151
 
71
- to_remove = [name for name, timer in self.timers.items() if timer.ended()]
152
+ def deactivate_register(self, name):
153
+ self.activate_register(name, active=False)
72
154
 
73
- for name in to_remove:
74
- # print(self.timers.pop(name).name,"removed !")
75
- self.timers.pop(name)
155
+ def __str__(self)->str:
156
+ res = ""
157
+ for name,reg in self.registers.items():
158
+ if not reg.timers:continue
159
+ res +=name+"\n"
160
+ for t in reg.timers.values():
161
+ res +="\t"+str(t)+"\n"
162
+ return res