batframework 0.1.13__py3-none-any.whl → 1.0.1__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 (47) hide show
  1. batFramework/__init__.py +41 -46
  2. batFramework/action.py +42 -20
  3. batFramework/actionContainer.py +43 -4
  4. batFramework/animatedSprite.py +26 -20
  5. batFramework/camera.py +177 -47
  6. batFramework/constants.py +26 -51
  7. batFramework/cutscene.py +15 -15
  8. batFramework/cutsceneBlocks.py +11 -9
  9. batFramework/dynamicEntity.py +7 -6
  10. batFramework/easing.py +28 -23
  11. batFramework/entity.py +87 -49
  12. batFramework/enums.py +14 -0
  13. batFramework/fontManager.py +57 -0
  14. batFramework/gui/__init__.py +2 -2
  15. batFramework/gui/button.py +82 -31
  16. batFramework/gui/constraints.py +137 -104
  17. batFramework/gui/container.py +27 -28
  18. batFramework/gui/debugger.py +92 -42
  19. batFramework/gui/frame.py +15 -15
  20. batFramework/gui/image.py +37 -17
  21. batFramework/gui/indicator.py +18 -14
  22. batFramework/gui/interactiveWidget.py +11 -10
  23. batFramework/gui/label.py +60 -56
  24. batFramework/gui/layout.py +50 -47
  25. batFramework/gui/root.py +43 -30
  26. batFramework/gui/shape.py +34 -41
  27. batFramework/gui/slider.py +5 -0
  28. batFramework/gui/toggle.py +31 -27
  29. batFramework/gui/widget.py +148 -128
  30. batFramework/manager.py +18 -13
  31. batFramework/particles.py +16 -13
  32. batFramework/resourceManager.py +55 -0
  33. batFramework/scene.py +141 -83
  34. batFramework/sceneManager.py +21 -16
  35. batFramework/sprite.py +31 -0
  36. batFramework/stateMachine.py +1 -0
  37. batFramework/tileset.py +7 -9
  38. batFramework/time.py +61 -50
  39. batFramework/transition.py +20 -12
  40. batFramework/utils.py +2 -65
  41. batframework-1.0.1.dist-info/LICENCE +21 -0
  42. {batframework-0.1.13.dist-info → batframework-1.0.1.dist-info}/METADATA +3 -2
  43. batframework-1.0.1.dist-info/RECORD +48 -0
  44. {batframework-0.1.13.dist-info → batframework-1.0.1.dist-info}/WHEEL +1 -1
  45. batFramework/debugger.py +0 -48
  46. batframework-0.1.13.dist-info/RECORD +0 -43
  47. {batframework-0.1.13.dist-info → batframework-1.0.1.dist-info}/top_level.txt +0 -0
batFramework/entity.py CHANGED
@@ -1,51 +1,59 @@
1
+ from typing import Any, Self
1
2
  import pygame
2
3
  import batFramework as bf
3
- from typing import Any
4
4
 
5
5
  class Entity:
6
- instance_num = 0
6
+ """
7
+ Basic entity class
8
+ """
9
+ __instance_count = 0
10
+
7
11
  def __init__(
8
12
  self,
9
- size : None|tuple[int,int]=None,
10
- no_surface : bool =False,
11
- surface_flags : int =0,
12
- convert_alpha : bool=False
13
+ size: None | tuple[int, int] = None,
14
+ no_surface: bool = False,
15
+ surface_flags: int = 0,
16
+ convert_alpha: bool = False,
13
17
  ) -> None:
14
18
  self.convert_alpha = convert_alpha
15
19
  if size is None:
16
- size= (100,100)
17
-
20
+ size = (10, 10)
18
21
  if no_surface:
19
22
  self.surface = None
20
23
  else:
21
- self.surface = (pygame.Surface(size, surface_flags))
22
-
24
+ self.surface = pygame.Surface(size, surface_flags)
25
+
23
26
  if convert_alpha and self.surface is not None:
24
27
  self.surface = self.surface.convert_alpha()
25
- self.surface.fill((0,0,0,0))
28
+ self.surface.fill((0, 0, 0, 0))
26
29
 
27
- self.uid: Any = Entity.instance_num
30
+ self.rect = pygame.FRect(0, 0, *size)
28
31
  self.tags: list[str] = []
29
32
  self.parent_scene: bf.Scene | None = None
30
- self.rect = pygame.FRect(0, 0, *size)
31
-
32
- self.visible :bool = True
33
- self._debug_color : tuple = bf.color.DARK_RED
34
- self.render_order :int = 0
35
- self.z_depth :float = 1
36
- Entity.instance_num += 1
33
+ self.visible: bool = True
34
+ self.debug_color: tuple = bf.color.DARK_RED
35
+ self.render_order: int = 0
36
+ self.uid: Any = Entity.__instance_count
37
+ Entity.__instance_count += 1
38
+
39
+ def set_render_order(self, render_order: int) -> Self:
40
+ self.render_order = render_order
41
+ return self
37
42
 
38
43
  def get_bounding_box(self):
39
- yield (self.rect,self._debug_color)
44
+ yield (self.rect, self.debug_color)
40
45
 
41
- def set_debug_color(self, color):
42
- self._debug_color = color
46
+ def set_debug_color(self, color) -> Self:
47
+ self.debug_color = color
48
+ return self
43
49
 
44
- def set_visible(self, value: bool):
50
+ def set_visible(self, value: bool) -> Self:
45
51
  self.visible = value
52
+ return self
46
53
 
47
- def set_parent_scene(self, scene):
54
+ def set_parent_scene(self, scene) -> Self:
48
55
  self.parent_scene = scene
56
+ return self
49
57
 
50
58
  def do_when_added(self):
51
59
  pass
@@ -53,70 +61,100 @@ class Entity:
53
61
  def do_when_removed(self):
54
62
  pass
55
63
 
56
- def set_position(self, x, y):
64
+ def set_position(self, x, y) -> Self:
57
65
  self.rect.topleft = (x, y)
58
66
  return self
59
67
 
60
- def set_x(self,x):
68
+ def get_position(self) -> tuple:
69
+ return self.rect.topleft
70
+
71
+ def get_center(self) -> tuple:
72
+ return self.rect.center
73
+
74
+ def set_x(self, x) -> Self:
61
75
  self.rect.x = x
62
76
  return self
63
77
 
64
- def set_y(self,y):
78
+ def set_y(self, y) -> Self:
65
79
  self.rect.y = y
66
80
  return self
67
81
 
68
- def set_center(self, x, y):
82
+ def set_center(self, x, y) -> Self:
69
83
  self.rect.center = (x, y)
70
84
  return self
71
85
 
72
- def set_uid(self, uid):
86
+ def set_uid(self, uid) -> Self:
73
87
  self.uid = uid
74
88
  return self
75
89
 
76
- def add_tag(self, *tags):
90
+ def add_tags(self, *tags) -> Self:
77
91
  for tag in tags:
78
92
  if tag not in self.tags:
79
93
  self.tags.append(tag)
80
94
  self.tags.sort()
81
95
  return self
82
96
 
83
- def remove_tag(self, *tags):
97
+ def remove_tags(self, *tags):
84
98
  self.tags = [tag for tag in self.tags if tag not in tags]
85
99
 
86
- def has_tag(self, tag) -> bool:
87
- return tag in self.tags
100
+ def has_tags(self, *tags) -> bool:
101
+ return all(tag in self.tags for tag in tags)
102
+
103
+ def get_tags(self) -> list[str]:
104
+ return self.tags
88
105
 
89
- def process_event(self, event: pygame.Event)->bool:
106
+ def process_event(self, event: pygame.Event) -> bool:
90
107
  """
91
108
  Returns bool : True if the method is blocking (no propagation to next children of the scene)
92
109
  """
93
110
  self.do_process_actions(event)
94
- res = self.do_handle_event(event)
111
+ res = self.do_handle_actions()
112
+ res = res or self.do_handle_event(event)
95
113
  self.do_reset_actions()
96
114
  return res
97
115
 
98
- def do_process_actions(self,event : pygame.Event)->None:
99
- pass
100
116
 
101
- def do_reset_actions(self)->None:
102
- pass
103
-
117
+
118
+ def do_process_actions(self, event: pygame.Event) -> None:
119
+ """
120
+ Process entity actions you may have set
121
+ """
122
+
123
+ def do_reset_actions(self) -> None:
124
+ """
125
+ Reset entity actions you may have set
126
+ """
127
+
128
+ def do_handle_actions(self) ->None:
129
+ """
130
+ Handle entity actions
131
+ """
132
+
104
133
  def do_handle_event(self, event: pygame.Event) -> bool:
134
+ """
135
+ Handle specific
136
+ """
137
+
105
138
  return False
106
139
 
107
140
  def update(self, dt: float):
141
+ """
142
+ Update method to be overriden by subclasses of widget
143
+ """
108
144
  self.do_update(dt)
109
145
 
110
- def do_update(self,dt:float):
111
- pass
146
+ def do_update(self, dt: float):
147
+ """
148
+ Update method to be overriden for specific behavior by the end user
149
+ """
112
150
 
113
151
  def draw(self, camera: bf.Camera) -> int:
114
- if not self.visible:
115
- return 0
116
- if not self.surface or not camera.intersects(self.rect):
152
+ """
153
+ Draw the entity onto the camera with coordinate transposing
154
+ """
155
+ should_not_draw = not self.visible or not self.surface or not camera.intersects(self.rect)
156
+ if should_not_draw:
117
157
  return 0
118
- camera.surface.blit(
119
- self.surface,
120
- tuple(round(i * self.z_depth) for i in camera.transpose(self.rect).topleft),
121
- )
158
+ camera.surface.blit(self.surface, camera.transpose(self.rect))
159
+
122
160
  return 1
batFramework/enums.py ADDED
@@ -0,0 +1,14 @@
1
+ from enum import Enum
2
+
3
+ class Direction(Enum):
4
+ HORIZONTAL = "horizontal"
5
+ VERTICAL = "vertical"
6
+
7
+
8
+ class Alignment(Enum):
9
+ LEFT = "left"
10
+ RIGHT = "right"
11
+ CENTER = "center"
12
+ TOP = "top"
13
+ BOTTOM = "bottom"
14
+
@@ -0,0 +1,57 @@
1
+ from .utils import Singleton
2
+ # put font stuff here later
3
+ import pygame
4
+ import os
5
+ import batFramework as bf
6
+ class FontManager(metaclass=Singleton):
7
+ def __init__(self):
8
+ pygame.font.init()
9
+ self.DEFAULT_TEXT_SIZE = 16
10
+ self.MIN_FONT_SIZE = 8
11
+ self.MAX_FONT_SIZE = 64
12
+ self.DEFAULT_ANTIALIAS = False
13
+ self.FONTS = {}
14
+
15
+ def set_default_text_size(self,size: int):
16
+ self.DEFAULT_TEXT_SIZE = size
17
+
18
+ def init_font(self,raw_path: str|None):
19
+ try:
20
+ if raw_path is not None:
21
+ self.load_font(raw_path if raw_path else None, None)
22
+ self.load_font(raw_path)
23
+ except FileNotFoundError:
24
+ self.load_sysfont(raw_path)
25
+ self.load_sysfont(raw_path, None)
26
+
27
+ def load_font(self,path: str|None, name: str|None = ""):
28
+ if path is not None:
29
+ path = bf.ResourceManager().get_path(path) # convert path if given
30
+ filename = None
31
+ if path is not None:
32
+ filename = os.path.basename(path).split(".")[0]
33
+
34
+ # get filename if path is given, else None
35
+ if name != "":
36
+ filename = name # if name is not given, name is the filename
37
+ self.FONTS[filename] = {}
38
+ # fill the dict
39
+ for size in range(self.MIN_FONT_SIZE, self.MAX_FONT_SIZE, 2):
40
+ self.FONTS[filename][size] = pygame.font.Font(path, size=size)
41
+
42
+ def load_sysfont(self,font_name: str|None, key: str |None= ""):
43
+ if key == "":
44
+ key = font_name
45
+ if font_name is None or pygame.font.match_font(font_name) is None:
46
+ raise FileNotFoundError(f"Requested font '{font_name}' was not found")
47
+ self.FONTS[font_name] = {}
48
+
49
+ for size in range(self.MIN_FONT_SIZE, self.MAX_FONT_SIZE, 2):
50
+ self.FONTS[key][size] = pygame.font.SysFont(font_name, size=size)
51
+
52
+ def get_font(self,name: str | None = None, text_size: int = 12) -> pygame.Font|None:
53
+ if not name in self.FONTS:
54
+ return None
55
+ if not text_size in self.FONTS[name]:
56
+ return None
57
+ return self.FONTS[name][text_size]
@@ -5,9 +5,9 @@ from .interactiveWidget import InteractiveWidget
5
5
  from .root import Root
6
6
  from .shape import Shape
7
7
  from .frame import Frame
8
- from .label import Label,Align
8
+ from .label import Label, Align
9
9
  from .button import Button
10
- from .debugger import Debugger
10
+ from .debugger import *
11
11
  from .layout import *
12
12
  from .container import Container
13
13
  from .indicator import *
@@ -1,25 +1,50 @@
1
1
  from .label import Label
2
2
  import batFramework as bf
3
- from types import FunctionType
4
- from typing import Self
3
+ from typing import Self,Callable
5
4
  from .interactiveWidget import InteractiveWidget
6
5
  import pygame
7
6
 
8
- class Button(Label,InteractiveWidget):
7
+
8
+ class Button(Label, InteractiveWidget):
9
9
  _cache = {}
10
-
11
- def __init__(self, text: str, callback : FunctionType =None) -> None:
12
- # Label.__init__(self,text)
13
- self.callback = callback
10
+
11
+ def __init__(self, text: str, callback: None| Callable = None) -> None:
12
+ # Label.__init__(self,text)
13
+ self.callback = callback
14
14
  self.click_action = bf.Action("click").add_mouse_control(1)
15
15
  self.hover_action = bf.Action("hover").add_mouse_control(pygame.MOUSEMOTION)
16
- self.is_hovered : bool = False
17
- self.is_clicking : bool = False
16
+ self.is_hovered: bool = False
17
+ self.is_clicking: bool = False
18
+ self.effect_max :float= 20
19
+ self.effect_speed :float= 1.2
20
+ self.effect :float = 0
21
+ self.enabled :bool = True
18
22
  super().__init__(text=text)
19
23
  self.set_debug_color("cyan")
20
24
 
25
+ def get_surface_filter(self)->pygame.Surface|None:
26
+ if not self.surface : return None
27
+ size = self.surface.get_size()
28
+ surface_filter = Button._cache.get(size, None)
29
+ if surface_filter is None:
30
+ surface_filter = pygame.Surface(size).convert_alpha()
31
+ surface_filter.fill((30, 30, 30, 0))
32
+ Button._cache[size] = surface_filter
33
+ return surface_filter
34
+ def enable(self)->Self:
35
+ self.enabled = True
36
+ self.build()
37
+ return self
21
38
 
22
- def set_callback(self,callback : FunctionType = None)->Self:
39
+ def disable(self)->Self:
40
+ self.enabled = False
41
+ self.build()
42
+ return self
43
+
44
+ def is_enabled(self)->bool:
45
+ return self.enabled
46
+
47
+ def set_callback(self, callback: Callable) -> Self:
23
48
  self.callback = callback
24
49
  return self
25
50
 
@@ -31,17 +56,19 @@ class Button(Label,InteractiveWidget):
31
56
  super().on_lose_focus()
32
57
  self.build()
33
58
 
34
- def to_string_id(self)->str:
35
- return f"Button({self._text})"
59
+ def to_string_id(self) -> str:
60
+ return f"Button({self._text}){'' if self.enabled else '[disabled]'}"
36
61
 
37
- def click(self)->None:
38
- if self.callback and not self.is_clicking:
62
+ def click(self) -> None:
63
+ if self.callback is not None and not self.is_clicking:
39
64
  self.is_clicking = True
40
65
  self.callback()
41
66
  self.is_clicking = False
42
-
43
-
44
- def do_process_actions(self,event):
67
+
68
+ def start_effect(self):
69
+ if self.effect <= 0 : self.effect = self.effect_max
70
+
71
+ def do_process_actions(self, event):
45
72
  self.click_action.process_event(event)
46
73
  self.hover_action.process_event(event)
47
74
 
@@ -49,13 +76,16 @@ class Button(Label,InteractiveWidget):
49
76
  self.click_action.reset()
50
77
  self.hover_action.reset()
51
78
 
52
- def do_handle_event(self,event)->None:
79
+ def do_handle_event(self, event) -> bool:
53
80
  res = False
54
81
  if self.click_action.is_active():
55
82
  root = self.get_root()
56
- if root.hovered == self:
57
- if not self.is_focused : self.get_focus()
58
- self.click()
83
+ if root is None : return res
84
+ if root.get_hovered() == self and self.enabled:
85
+ if not self.is_focused:
86
+ self.get_focus()
87
+ # self.click()
88
+ self.start_effect()
59
89
  res = True
60
90
  elif self.hover_action.is_active():
61
91
  root = self.get_root()
@@ -70,18 +100,39 @@ class Button(Label,InteractiveWidget):
70
100
  res = True
71
101
  return res
72
102
 
103
+ def update(self,dt):
104
+ super().update(dt)
105
+ if self.effect > 0:
106
+ self.effect -= dt*60*self.effect_speed
107
+ self.build()
108
+ if self.effect <= 0:
109
+ self.is_hovered = False
110
+ self.effect = 0
111
+ self.click()
112
+ self.build()
73
113
 
74
-
75
- def build(self)->None:
114
+ def _build_effect(self)->None:
115
+ pygame.draw.rect(
116
+ self.surface,
117
+ bf.color.CLOUD_WHITE,
118
+ (0,0,*self.surface.get_size()),
119
+ int(self.effect),
120
+ *self._border_radius
121
+ )
122
+
123
+ def build(self) -> None:
76
124
  super().build()
125
+ size = self.surface.get_size()
126
+ if not self.enabled:
127
+ self.surface.blit(self.get_surface_filter(), (0, 0), special_flags=pygame.BLEND_SUB)
128
+ return
129
+ if self.effect:
130
+ if self.effect >= 1 :
131
+ self._build_effect()
132
+ return
77
133
  if self.is_hovered:
78
- hover_surf = Button._cache.get(self.surface.get_size(),None)
79
- if hover_surf is None:
80
- hover_surf = pygame.Surface(self.surface.get_size()).convert_alpha()
81
- hover_surf.fill((30,30,30,0))
82
- Button._cache[self.surface.get_size()] = hover_surf
83
- self.surface.blit(hover_surf,(0,0),special_flags = pygame.BLEND_ADD)
134
+ self.surface.blit(self.get_surface_filter(), (0, 0), special_flags=pygame.BLEND_ADD)
84
135
 
136
+ def apply_contraints(self) -> None:
137
+ super().apply_constraints()
85
138
 
86
- def apply_contraints(self)->None:
87
- super().apply_contraints()