batframework 1.0.8a1__py3-none-any.whl → 1.0.8a2__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 (63) hide show
  1. batFramework/__init__.py +50 -53
  2. batFramework/action.py +105 -116
  3. batFramework/actionContainer.py +11 -53
  4. batFramework/animatedSprite.py +65 -115
  5. batFramework/audioManager.py +26 -70
  6. batFramework/camera.py +68 -253
  7. batFramework/constants.py +54 -16
  8. batFramework/cutscene.py +25 -34
  9. batFramework/cutsceneBlocks.py +42 -37
  10. batFramework/debugger.py +48 -0
  11. batFramework/dynamicEntity.py +7 -9
  12. batFramework/easing.py +71 -0
  13. batFramework/entity.py +98 -42
  14. batFramework/gui/__init__.py +2 -8
  15. batFramework/gui/button.py +79 -7
  16. batFramework/gui/constraints.py +204 -0
  17. batFramework/gui/container.py +31 -155
  18. batFramework/gui/debugger.py +43 -124
  19. batFramework/gui/frame.py +19 -0
  20. batFramework/gui/image.py +17 -41
  21. batFramework/gui/indicator.py +21 -41
  22. batFramework/gui/interactiveWidget.py +13 -116
  23. batFramework/gui/label.py +73 -278
  24. batFramework/gui/layout.py +61 -148
  25. batFramework/gui/root.py +37 -102
  26. batFramework/gui/shape.py +57 -258
  27. batFramework/gui/toggle.py +46 -97
  28. batFramework/gui/widget.py +254 -268
  29. batFramework/manager.py +19 -40
  30. batFramework/particles.py +77 -0
  31. batFramework/scene.py +107 -214
  32. batFramework/sceneManager.py +107 -150
  33. batFramework/stateMachine.py +0 -1
  34. batFramework/time.py +57 -117
  35. batFramework/transition.py +126 -184
  36. batFramework/transitionManager.py +0 -0
  37. batFramework/utils.py +161 -34
  38. batframework-1.0.8a2.dist-info/METADATA +58 -0
  39. batframework-1.0.8a2.dist-info/RECORD +42 -0
  40. {batframework-1.0.8a1.dist-info → batframework-1.0.8a2.dist-info}/WHEEL +1 -1
  41. batFramework/easingController.py +0 -58
  42. batFramework/enums.py +0 -104
  43. batFramework/fontManager.py +0 -65
  44. batFramework/gui/clickableWidget.py +0 -206
  45. batFramework/gui/constraints/__init__.py +0 -1
  46. batFramework/gui/constraints/constraints.py +0 -378
  47. batFramework/gui/dialogueBox.py +0 -96
  48. batFramework/gui/draggableWidget.py +0 -38
  49. batFramework/gui/meter.py +0 -76
  50. batFramework/gui/radioButton.py +0 -62
  51. batFramework/gui/slider.py +0 -220
  52. batFramework/gui/textInput.py +0 -134
  53. batFramework/object.py +0 -115
  54. batFramework/particle.py +0 -101
  55. batFramework/renderGroup.py +0 -62
  56. batFramework/resourceManager.py +0 -84
  57. batFramework/scrollingSprite.py +0 -113
  58. batFramework/sprite.py +0 -45
  59. batFramework/tileset.py +0 -46
  60. batframework-1.0.8a1.dist-info/LICENCE +0 -21
  61. batframework-1.0.8a1.dist-info/METADATA +0 -55
  62. batframework-1.0.8a1.dist-info/RECORD +0 -56
  63. {batframework-1.0.8a1.dist-info → batframework-1.0.8a2.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,5 @@
1
1
  import batFramework as bf
2
- from .cutscene import Cutscene, CutsceneManager
3
- from .transition import *
2
+ from .cutscene import Cutscene,CutsceneManager
4
3
 
5
4
 
6
5
  # Define the base CutsceneBlock class
@@ -18,18 +17,18 @@ class CutsceneBlock:
18
17
  self.ended = False
19
18
  self.started = False
20
19
 
21
- def get_scene_at(self, index):
22
- return bf.CutsceneManager().manager.scenes[index]
23
-
24
- def set_scene(self, name, index=0):
25
- return CutsceneManager().manager.set_scene(name, index)
20
+ def get_scene_at(self,index):
21
+ return bf.CutsceneManager().manager._scenes[index]
26
22
 
23
+ def set_scene(self,name,index=0):
24
+ return CutsceneManager().manager.set_scene(name,index)
25
+
27
26
  def get_current_scene(self):
28
27
  return CutsceneManager().manager.get_current_scene()
29
-
30
- def get_scene(self, name):
28
+
29
+ def get_scene(self,name):
31
30
  return CutsceneManager().manager.get_scene(name)
32
-
31
+
33
32
  # Set the parent cutscene for this block
34
33
  def set_parent_cutscene(self, parent):
35
34
  """
@@ -91,13 +90,17 @@ class ParallelBlock(CutsceneBlock):
91
90
  Represents a parallel execution block for multiple Cutscene blocks.
92
91
  """
93
92
 
93
+ # Constructor for ParallelBlock, taking a variable number of blocks as arguments
94
94
  def __init__(self, *blocks) -> None:
95
95
  super().__init__()
96
96
  # List of blocks to run in parallel
97
- self.blocks: list[CutsceneBlock] = list(blocks)
97
+ self.blocks: list[CutsceneBlock] = blocks
98
98
 
99
99
  # Start the parallel block (override the base class method)
100
100
  def start(self):
101
+ """
102
+ Start the parallel execution block.
103
+ """
101
104
  super().start()
102
105
  # Start each block in parallel
103
106
  for block in self.blocks:
@@ -105,14 +108,32 @@ class ParallelBlock(CutsceneBlock):
105
108
 
106
109
  # Process an event for each block in parallel
107
110
  def process_event(self, event):
111
+ """
112
+ Process an event for each block in the parallel execution block.
113
+
114
+ Args:
115
+ event: The event to be processed.
116
+ """
108
117
  _ = [b.process_event(event) for b in self.blocks]
109
118
 
110
119
  # Update each block in parallel
111
120
  def update(self, dt):
121
+ """
122
+ Update each block in the parallel execution block.
123
+
124
+ Args:
125
+ dt: Time elapsed since the last update.
126
+ """
112
127
  _ = [b.update(dt) for b in self.blocks]
113
128
 
114
129
  # Check if all blocks have ended
115
130
  def has_ended(self):
131
+ """
132
+ Check if all blocks in the parallel execution block have ended.
133
+
134
+ Returns:
135
+ bool: True if all blocks have ended, False otherwise.
136
+ """
116
137
  return all(b.has_ended() for b in self.blocks)
117
138
 
118
139
 
@@ -123,16 +144,15 @@ class SceneTransitionBlock(CutsceneBlock):
123
144
  """
124
145
 
125
146
  # Constructor for SceneTransitionBlock
126
- def __init__(
127
- self, scene, transition: Transition = Fade(0.1), index: int = 0
128
- ) -> None:
147
+ def __init__(self, scene, transition, duration, **kwargs) -> None:
129
148
  super().__init__()
130
149
  # Target scene, transition type, duration, and additional keyword arguments
131
150
  self.target_scene = scene
132
151
  self.transition = transition
133
- self.index = index
152
+ self.duration = duration
153
+ self.kwargs = kwargs
134
154
  # Timer to handle the end of the transition
135
- self.timer = bf.Timer(transition.duration, self.end)
155
+ self.timer = bf.Timer(name = "scene_transition_block",duration=duration, end_callback=self.end)
136
156
 
137
157
  # Start the scene transition block
138
158
  def start(self):
@@ -140,32 +160,17 @@ class SceneTransitionBlock(CutsceneBlock):
140
160
  Start the scene transition block.
141
161
  """
142
162
  super().start()
163
+ print(f"transition to {scene}")
164
+
143
165
  # Initiate the scene transition
144
- if self.get_current_scene().name == self.target_scene:
166
+ if self.get_current_scene()._name == self.target_scene:
145
167
  self.end()
146
168
  return
147
169
  CutsceneManager().manager.transition_to_scene(
148
- self.target_scene, self.transition, self.index
170
+ self.target_scene, self.transition, duration=self.duration, **self.kwargs
149
171
  )
150
172
  # Start the timer to handle the end of the transition
151
173
  self.timer.start()
152
174
 
153
-
154
- class DelayBlock(CutsceneBlock):
155
- def __init__(self, duration) -> None:
156
- super().__init__()
157
- self.timer = bf.Timer(duration=duration, end_callback=self.end)
158
-
159
- def start(self):
160
- super().start()
161
- self.timer.start()
162
-
163
-
164
- class FunctionBlock(CutsceneBlock):
165
- def __init__(self, func) -> None:
166
- self.function = func
167
-
168
- def start(self):
169
- super().start()
170
- self.function()
171
- self.end()
175
+ def end(self):
176
+ return super().end()
@@ -0,0 +1,48 @@
1
+ import batFramework as bf
2
+ import pygame
3
+
4
+
5
+ class Debugger(bf.Label):
6
+ def __init__(self, manager) -> None:
7
+ super().__init__()
8
+ self.manager: bf.Manager = manager
9
+ self.refresh_rate = 0
10
+ self._refresh_counter = 0
11
+ self.dynamic_data = {}
12
+ self.static_data = {}
13
+ self.render_order = 99
14
+ self.set_outline_color((20, 20, 20))
15
+ # self.set_background_color((0,0,0,0))
16
+ self.set_text_color("white")
17
+ # self.set_padding((30,30))
18
+ self.set_refresh_rate(20)
19
+ self.add_dynamic_data("FPS", lambda: str(round(self.manager.get_fps())))
20
+ self.add_dynamic_data("BLITS", lambda: str(self.parent_scene.blit_calls))
21
+ self.set_visible(False)
22
+
23
+ def set_refresh_rate(self, val: int):
24
+ self.refresh_rate = val
25
+
26
+ def update(self, dt: float):
27
+ visible = self.manager._debugging == 1
28
+ self.set_visible(visible)
29
+ if not visible:
30
+ return
31
+ self._refresh_counter -= dt * 60
32
+ if self._refresh_counter < 0:
33
+ self._refresh_counter = self.refresh_rate
34
+ self._refresh_debug_info()
35
+
36
+ def add_dynamic_data(self, key, func):
37
+ self.dynamic_data[key] = func
38
+
39
+ def set_static_data(self, key, value):
40
+ self.static_data[key] = value
41
+
42
+ def _refresh_debug_info(self):
43
+ lines = []
44
+ lines.extend([f"{key}:{value}" for key, value in self.static_data.items()])
45
+ lines.extend([f"{key}:{func()}" for key, func in self.dynamic_data.items()])
46
+ debug_text = "\n".join(lines)
47
+ self.set_text(debug_text)
48
+ self.update_surface() # Update the surface after modifying the text
@@ -2,15 +2,15 @@ import pygame
2
2
  import batFramework as bf
3
3
  from typing import Self
4
4
 
5
-
6
5
  class DynamicEntity(bf.Entity):
7
6
  def __init__(
8
7
  self,
9
- size: None | tuple[int, int] = None,
10
- surface_flags: int = 0,
11
- convert_alpha: bool = False,
8
+ size : None|tuple[int,int]=None,
9
+ no_surface : bool =False,
10
+ surface_flags : int =0,
11
+ convert_alpha : bool=False
12
12
  ) -> None:
13
- super().__init__(size, surface_flags, convert_alpha)
13
+ super().__init__(size,no_surface,surface_flags,convert_alpha)
14
14
  self.velocity = pygame.math.Vector2(0, 0)
15
15
 
16
16
  def on_collideX(self, collider: Self):
@@ -19,7 +19,5 @@ class DynamicEntity(bf.Entity):
19
19
  def on_collideY(self, collider: Self):
20
20
  return False
21
21
 
22
- def move_by_velocity(self, dt) -> None:
23
- self.set_position(
24
- self.rect.x + self.velocity.x * dt, self.rect.y + self.velocity.y * dt
25
- )
22
+ def move_by_velocity(self)->None:
23
+ self.set_position(self.rect.x + self.velocity.x, self.rect.y + self.velocity.y)
batFramework/easing.py ADDED
@@ -0,0 +1,71 @@
1
+ from enum import Enum
2
+ import pygame
3
+ import batFramework as bf
4
+
5
+ class Easing(Enum):
6
+ EASE_IN = (0.12, 0, 0.39, 0)
7
+ EASE_OUT = (0.61, 1, 0.88, 1)
8
+ EASE_IN_OUT = (0.37, 0, 0.63, 1)
9
+ EASE_IN_OUT_ELASTIC = (.7,-0.5,.3,1.5)
10
+ LINEAR = (1, 1, 0, 0)
11
+ # Add more easing functions as needed
12
+
13
+ def __init__(self, *control_points):
14
+ self.control_points = control_points
15
+
16
+ class EasingAnimation(bf.Timer):
17
+ _cache = {}
18
+ def __init__(
19
+ self,
20
+ name:str=None,
21
+ easing_function:Easing=Easing.LINEAR,
22
+ duration:int=100,
23
+ update_callback=None,
24
+ end_callback=None,
25
+ loop:bool=False,
26
+ reusable:bool=False
27
+ ):
28
+ self.easing_function = easing_function
29
+ self.update_callback = update_callback
30
+ self.value = 0.0
31
+ super().__init__(name,duration,loop,end_callback,reusable)
32
+
33
+ def get_value(self):
34
+ return self.value
35
+
36
+ def start(self):
37
+ self.value = 0
38
+ super().start() # self.elapsed_progress set to 0 here
39
+
40
+ def update(self)->bool:
41
+ if super().update():
42
+ return True# If timer ended now, end() is called. So don't process value.
43
+ self._process_value()
44
+ # if self.name == 0: print("UPDATING (callback) in easing")
45
+ if self.update_callback: self.update_callback(self.value)
46
+ return False
47
+
48
+ def end(self):
49
+ # Call update 1 last time with the last value
50
+
51
+ self.elapsed_progress = 1
52
+ self._process_value()
53
+ if self.update_callback: self.update_callback(self.value)
54
+ self.value = 0
55
+ super().end() # sets elapsed_progress to 0
56
+
57
+ def _process_value(self):
58
+ p0, p1, p2, p3 = self.easing_function.control_points
59
+ cache_key = (self.elapsed_progress, p0, p1, p2, p3)
60
+ if cache_key in EasingAnimation._cache:
61
+ y = EasingAnimation._cache[cache_key]
62
+ else:
63
+ t = self.elapsed_progress
64
+ t_inv = 1.0 - t
65
+ t2 = t * t
66
+ t3 = t * t2
67
+ t_inv2 = t_inv * t_inv
68
+
69
+ y = 3 * t_inv2 * t * p1 + 3 * t_inv * t2 * p3 + t3
70
+ EasingAnimation._cache[cache_key] = y
71
+ self.value = y
batFramework/entity.py CHANGED
@@ -1,67 +1,123 @@
1
- from typing import Any, Self
2
1
  import pygame
3
2
  import batFramework as bf
4
- from .object import Object
3
+ from typing import Any
5
4
 
6
- class Entity(Object):
7
- """
8
- Basic entity class
9
- """
5
+ class Entity:
6
+ instance_num = 0
10
7
  def __init__(
11
8
  self,
12
- size: None | tuple[int, int] = None,
13
- surface_flags: int = 0,
14
- convert_alpha: bool = False,
15
- *args,
16
- **kwargs,
9
+ size : None|tuple[int,int]=None,
10
+ no_surface : bool =False,
11
+ surface_flags : int =0,
12
+ convert_alpha : bool=False
17
13
  ) -> None:
18
- super().__init__()
19
- self.visible: bool = True
20
- self.rect.size = (10, 10) if size is None else size
21
- self.convert_alpha: bool = convert_alpha
22
- self.surface_flags: int = surface_flags
23
- self.blit_flags: int = 0
24
- self.surface: pygame.Surface = pygame.Surface(self.rect.size, surface_flags)
25
- if convert_alpha:
14
+ self.convert_alpha = convert_alpha
15
+ if size is None:
16
+ size= (100,100)
17
+
18
+ if no_surface:
19
+ self.surface = None
20
+ else:
21
+ self.surface = (pygame.Surface(size, surface_flags))
22
+
23
+ if convert_alpha and self.surface is not None:
26
24
  self.surface = self.surface.convert_alpha()
27
- self.surface.fill((0, 0, 0, 0))
25
+ self.surface.fill((0,0,0,0))
28
26
 
29
- def set_alpha(self, alpha: int) -> Self:
30
- self.surface.set_alpha(min(max(0, alpha), 255))
31
- return self
27
+ self.uid: Any = Entity.instance_num
28
+ self.tags: list[str] = []
29
+ self.parent_scene: bf.Scene | None = None
30
+ self.rect = pygame.FRect(0, 0, *size)
31
+
32
+ self.visible = True
33
+ self._debug_color : tuple = bf.color.DARK_RED
34
+ self.render_order = 0
35
+ self.z_depth = 1
36
+ Entity.instance_num += 1
37
+
38
+ def get_bounding_box(self):
39
+ yield (self.rect,self._debug_color)
32
40
 
33
- def get_alpha(self)->int:
34
- return self.surface.get_alpha()
41
+ def set_debug_color(self, color):
42
+ self._debug_color = color
43
+
44
+ def set_visible(self, value: bool):
45
+ self.visible = value
35
46
 
36
- def set_surface_flags(self, surface_flags: int) -> Self:
37
- self.surface_flags = surface_flags
47
+ def set_parent_scene(self, scene):
48
+ self.parent_scene = scene
49
+
50
+ def do_when_added(self):
51
+ pass
52
+
53
+ def do_when_removed(self):
54
+ pass
55
+
56
+ def set_position(self, x, y):
57
+ self.rect.topleft = (x, y)
38
58
  return self
39
59
 
40
- def set_convert_alpha(self, value: bool) -> Self:
41
- self.convert_alpha = value
60
+ def set_x(self,x):
61
+ self.rect.x = x
42
62
  return self
43
63
 
44
- def set_blit_flags(self, blit_flags: int) -> Self:
45
- self.blit_flags = blit_flags
64
+ def set_y(self,y):
65
+ self.rect.y = y
46
66
  return self
47
67
 
48
- def set_render_order(self, render_order: int) -> Self:
49
- self.render_order = render_order
50
- if self.parent_scene:
51
- self.parent_scene.sort_entities()
68
+ def set_center(self, x, y):
69
+ self.rect.center = (x, y)
52
70
  return self
53
71
 
54
- def set_visible(self, value: bool) -> Self:
55
- self.visible = value
72
+ def set_uid(self, uid):
73
+ self.uid = uid
56
74
  return self
57
75
 
58
- def draw(self, camera: bf.Camera) -> None:
76
+ def add_tag(self, *tags):
77
+ for tag in tags:
78
+ if tag not in self.tags:
79
+ self.tags.append(tag)
80
+ self.tags.sort()
81
+ return self
82
+
83
+ def remove_tag(self, *tags):
84
+ self.tags = [tag for tag in self.tags if tag not in tags]
85
+ self.tags.sort()
86
+
87
+ def has_tag(self, tag) -> bool:
88
+ return tag in self.tags
89
+
90
+ def process_event(self, event: pygame.Event)->bool:
59
91
  """
60
- Draw the entity onto the camera surface
92
+ Returns bool : True if the method is blocking (no propagation to next children of the scene)
61
93
  """
62
- if not self.visible or not camera.rect.colliderect(self.rect): return
94
+ self.do_process_actions(event)
95
+ res = self.do_handle_event(event)
96
+ self.do_reset_actions()
97
+ return res
98
+
99
+ def do_process_actions(self,event : pygame.Event)->None:
100
+ pass
101
+
102
+ def do_reset_actions(self)->None:
103
+ pass
104
+
105
+ def do_handle_event(self, event: pygame.Event) -> bool:
106
+ return False
107
+
108
+ def update(self, dt: float):
109
+ self.do_update(dt)
110
+
111
+ def do_update(self,dt:float):
112
+ pass
113
+
114
+ def draw(self, camera: bf.Camera) -> int:
115
+ if not self.visible:
116
+ return False
117
+ if not self.surface or not camera.intersects(self.rect):
118
+ return False
63
119
  camera.surface.blit(
64
120
  self.surface,
65
- camera.world_to_screen(self.rect),
66
- special_flags=self.blit_flags,
121
+ tuple(round(i * self.z_depth) for i in camera.transpose(self.rect).topleft),
67
122
  )
123
+ return True
@@ -2,19 +2,13 @@ from .constraints import *
2
2
  from .widget import Widget
3
3
  from .image import Image
4
4
  from .interactiveWidget import InteractiveWidget
5
- from .draggableWidget import DraggableWidget
6
- from .clickableWidget import ClickableWidget
7
5
  from .root import Root
8
6
  from .shape import Shape
9
- from .meter import Meter
7
+ from .frame import Frame
10
8
  from .label import Label
11
- from .dialogueBox import DialogueBox
12
- from .textInput import TextInput
13
9
  from .button import Button
14
- from .debugger import *
10
+ from .debugger import Debugger
15
11
  from .layout import *
16
12
  from .container import Container
17
13
  from .indicator import *
18
14
  from .toggle import Toggle
19
- from .radioButton import RadioButton,RadioVariable
20
- from .slider import Slider
@@ -1,12 +1,84 @@
1
1
  from .label import Label
2
2
  import batFramework as bf
3
- from typing import Self, Callable
4
- from .clickableWidget import ClickableWidget
3
+ from types import FunctionType
4
+ from typing import Self
5
+ from .interactiveWidget import InteractiveWidget
5
6
  import pygame
6
- from math import ceil
7
7
 
8
-
9
- class Button(Label, ClickableWidget):
10
- def __init__(self, text: str, callback: None | Callable = None) -> None:
8
+ class Button(Label,InteractiveWidget):
9
+ _cache = {}
10
+
11
+ def __init__(self, text: str, callback : FunctionType =None) -> None:
12
+ # Label.__init__(self,text)
13
+ self.callback = callback
14
+ self.click_action = bf.Action("click").add_mouse_control(1)
15
+ self.hover_action = bf.Action("hover").add_mouse_control(pygame.MOUSEMOTION)
16
+ self.is_hovered : bool = False
17
+ self.is_clicking : bool = False
11
18
  super().__init__(text=text)
12
- self.set_callback(callback)
19
+ self.set_debug_color("cyan")
20
+
21
+
22
+ def set_callback(self,callback : FunctionType = None)->Self:
23
+ self.callback = callback
24
+ return self
25
+
26
+ def on_get_focus(self):
27
+ super().on_get_focus()
28
+ self.build()
29
+
30
+ def on_lose_focus(self):
31
+ super().on_lose_focus()
32
+ self.build()
33
+
34
+ def to_string_id(self)->str:
35
+ return f"Button({self._text})"
36
+
37
+ def click(self)->None:
38
+ if self.callback and not self.is_clicking:
39
+ self.is_clicking = True
40
+ self.callback()
41
+ self.is_clicking = False
42
+
43
+
44
+ def do_process_actions(self,event):
45
+ self.click_action.process_event(event)
46
+ self.hover_action.process_event(event)
47
+
48
+ def do_reset_actions(self):
49
+ self.click_action.reset()
50
+ self.hover_action.reset()
51
+
52
+ def do_handle_event(self,event)->None:
53
+ res = False
54
+ if self.click_action.is_active():
55
+ root = self.get_root()
56
+ if root.hovered == self:
57
+ if not self.is_focused : self.get_focus()
58
+ self.click()
59
+ elif self.hover_action.is_active():
60
+ root = self.get_root()
61
+ if root:
62
+ if self.is_hovered and root.hovered != self:
63
+ self.is_hovered = False
64
+ self.build()
65
+ if not self.is_hovered and root.hovered == self:
66
+ self.is_hovered = True
67
+ self.build()
68
+ return res
69
+
70
+
71
+
72
+ def build(self)->None:
73
+ super().build()
74
+ if self.is_hovered:
75
+ hover_surf = Button._cache.get(self.surface.get_size(),None)
76
+ if hover_surf is None:
77
+ hover_surf = pygame.Surface(self.surface.get_size()).convert_alpha()
78
+ hover_surf.fill((30,30,30,0))
79
+ Button._cache[self.surface.get_size()] = hover_surf
80
+ self.surface.blit(hover_surf,(0,0),special_flags = pygame.BLEND_ADD)
81
+
82
+
83
+ def apply_contraints(self)->None:
84
+ super().apply_contraints()