batframework 1.0.8a4__py3-none-any.whl → 1.0.8a7__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.
- batFramework/__init__.py +15 -1
- batFramework/animatedSprite.py +65 -50
- batFramework/character.py +27 -0
- batFramework/dynamicEntity.py +1 -0
- batFramework/enums.py +2 -2
- batFramework/fontManager.py +2 -2
- batFramework/gui/clickableWidget.py +6 -7
- batFramework/gui/constraints/constraints.py +125 -40
- batFramework/gui/image.py +14 -14
- batFramework/gui/interactiveWidget.py +15 -0
- batFramework/gui/label.py +44 -27
- batFramework/gui/layout.py +23 -14
- batFramework/gui/meter.py +10 -7
- batFramework/gui/radioButton.py +1 -1
- batFramework/gui/shape.py +3 -25
- batFramework/gui/slider.py +40 -30
- batFramework/gui/textInput.py +160 -50
- batFramework/gui/toggle.py +20 -22
- batFramework/gui/widget.py +65 -32
- batFramework/manager.py +17 -5
- batFramework/object.py +17 -8
- batFramework/particle.py +18 -4
- batFramework/scene.py +1 -1
- batFramework/sceneManager.py +42 -13
- batFramework/stateMachine.py +9 -6
- batFramework/templates/__init__.py +2 -0
- batFramework/templates/character.py +44 -0
- batFramework/templates/states.py +166 -0
- batFramework/time.py +31 -9
- batFramework/transition.py +2 -2
- batFramework/triggerZone.py +1 -1
- batFramework/utils.py +35 -6
- {batframework-1.0.8a4.dist-info → batframework-1.0.8a7.dist-info}/METADATA +3 -15
- batframework-1.0.8a7.dist-info/RECORD +62 -0
- {batframework-1.0.8a4.dist-info → batframework-1.0.8a7.dist-info}/WHEEL +1 -1
- batframework-1.0.8a4.dist-info/RECORD +0 -58
- {batframework-1.0.8a4.dist-info → batframework-1.0.8a7.dist-info}/LICENCE +0 -0
- {batframework-1.0.8a4.dist-info → batframework-1.0.8a7.dist-info}/top_level.txt +0 -0
batFramework/__init__.py
CHANGED
@@ -24,12 +24,15 @@ from .dynamicEntity import DynamicEntity
|
|
24
24
|
from .sprite import Sprite
|
25
25
|
from .scrollingSprite import ScrollingSprite
|
26
26
|
from .particle import *
|
27
|
-
from .animatedSprite import AnimatedSprite,
|
27
|
+
from .animatedSprite import AnimatedSprite, Animation
|
28
|
+
from .character import Character
|
28
29
|
from .stateMachine import State, StateMachine
|
29
30
|
from .scene import Scene
|
30
31
|
from .gui import *
|
31
32
|
from .sceneManager import SceneManager
|
32
33
|
from .manager import Manager
|
34
|
+
from .templates import *
|
35
|
+
import importlib.metadata
|
33
36
|
|
34
37
|
|
35
38
|
def init_screen(resolution: tuple[int, int], flags: int = 0, vsync: int = 0):
|
@@ -44,6 +47,16 @@ def init_screen(resolution: tuple[int, int], flags: int = 0, vsync: int = 0):
|
|
44
47
|
)
|
45
48
|
|
46
49
|
|
50
|
+
|
51
|
+
def print_version():
|
52
|
+
package_name = "batFramework"
|
53
|
+
try:
|
54
|
+
version = importlib.metadata.version(package_name)
|
55
|
+
print(f"{package_name} version: {version}")
|
56
|
+
except importlib.metadata.PackageNotFoundError:
|
57
|
+
print(f"{package_name} is not installed")
|
58
|
+
|
59
|
+
|
47
60
|
def init(
|
48
61
|
resolution: tuple[int, int],
|
49
62
|
flags: int = 0,
|
@@ -54,6 +67,7 @@ def init(
|
|
54
67
|
window_title: str = "BatFramework Project",
|
55
68
|
fps_limit: int = 0,
|
56
69
|
):
|
70
|
+
print_version()
|
57
71
|
pygame.display.set_caption(window_title)
|
58
72
|
init_screen(resolution, flags, vsync)
|
59
73
|
|
batFramework/animatedSprite.py
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
import batFramework as bf
|
2
2
|
import pygame
|
3
|
-
from typing import List, Dict, Tuple, Union, Optional
|
4
|
-
from enum import Enum
|
3
|
+
from typing import List, Dict, Tuple, Union, Optional, Self
|
5
4
|
|
6
5
|
|
7
6
|
def search_index(target: int, lst: List[int]) -> int:
|
@@ -13,30 +12,28 @@ def search_index(target: int, lst: List[int]) -> int:
|
|
13
12
|
return -1
|
14
13
|
|
15
14
|
|
16
|
-
class
|
15
|
+
class Animation:
|
17
16
|
def __init__(
|
18
17
|
self,
|
19
|
-
name: str
|
20
|
-
surface: pygame.Surface,
|
21
|
-
size: Tuple[int,int],
|
22
|
-
duration_list: Union[List[int], int],
|
18
|
+
name: str
|
23
19
|
) -> None:
|
24
|
-
self.frames: List[pygame.Surface] = list(
|
25
|
-
bf.utils.split_surface(
|
26
|
-
surface, size
|
27
|
-
).values()
|
28
|
-
)
|
29
|
-
self.frames_flipX: List[pygame.Surface] = list(
|
30
|
-
bf.utils.split_surface(surface, size,).values()
|
31
|
-
)
|
32
|
-
|
33
20
|
self.name = name
|
34
|
-
self.
|
21
|
+
self.frames: list[pygame.Surface] = []
|
22
|
+
self.frames_flipX : list[pygame.Surface] = []
|
23
|
+
self.duration_list = []
|
24
|
+
self.duration_list_length = 1
|
25
|
+
|
26
|
+
def from_surface(self,surface:pygame.Surface,size : Tuple[int,int])->Self:
|
27
|
+
self.frames : List[pygame.Surface] = list(bf.utils.split_surface(surface, size).values())
|
28
|
+
self.frames_flipX : List[pygame.Surface] = list(bf.utils.split_surface(surface, size,func=lambda s : pygame.transform.flip(s,True,False)).values())
|
29
|
+
return self
|
35
30
|
|
36
31
|
def __repr__(self):
|
37
|
-
return f"
|
32
|
+
return f"Animation({self.name})"
|
38
33
|
|
39
34
|
def counter_to_frame(self, counter: Union[float, int]) -> int:
|
35
|
+
if not self.frames :
|
36
|
+
raise ValueError("Animation has no frames")
|
40
37
|
return search_index(
|
41
38
|
int(counter % self.duration_list_length), self.duration_list
|
42
39
|
)
|
@@ -45,24 +42,30 @@ class AnimState:
|
|
45
42
|
i = self.counter_to_frame(counter)
|
46
43
|
return self.frames_flipX[i] if flip else self.frames[i]
|
47
44
|
|
48
|
-
def set_duration_list(self, duration_list: Union[List[int], int]):
|
45
|
+
def set_duration_list(self, duration_list: Union[List[int], int]) -> Self:
|
49
46
|
if isinstance(duration_list, int):
|
50
47
|
duration_list = [duration_list] * len(self.frames)
|
51
48
|
if len(duration_list) != len(self.frames):
|
52
49
|
raise ValueError("duration_list should have values for all frames")
|
53
50
|
self.duration_list = duration_list
|
54
51
|
self.duration_list_length = sum(self.duration_list)
|
55
|
-
|
52
|
+
return self
|
56
53
|
|
57
54
|
class AnimatedSprite(bf.Entity):
|
58
55
|
def __init__(self, size: Optional[Tuple[int, int]] = None) -> None:
|
59
56
|
super().__init__(size, no_surface=True)
|
60
57
|
self.float_counter: float = 0
|
61
|
-
self.
|
62
|
-
self.current_state: Optional[
|
58
|
+
self.animations: Dict[str, Animation] = {}
|
59
|
+
self.current_state: Optional[Animation] = None
|
63
60
|
self.flipX: bool = False
|
64
61
|
self._locked: bool = False
|
65
62
|
self._paused: bool = False
|
63
|
+
self.animation_end_callback = None
|
64
|
+
self.transition_end_animation = None
|
65
|
+
|
66
|
+
def set_animation_end_callback(self,callback)->Self:
|
67
|
+
self.animation_end_callback = callback
|
68
|
+
return self
|
66
69
|
|
67
70
|
@property
|
68
71
|
def paused(self) -> bool:
|
@@ -92,60 +95,72 @@ class AnimatedSprite(bf.Entity):
|
|
92
95
|
def set_flipX(self, value: bool) -> None:
|
93
96
|
self.flipX = value
|
94
97
|
|
95
|
-
def
|
96
|
-
if name not in self.
|
98
|
+
def remove_animation(self, name: str) -> bool:
|
99
|
+
if name not in self.animations:
|
97
100
|
return False
|
98
|
-
self.
|
101
|
+
self.animations.pop(name)
|
99
102
|
if self.current_state and self.current_state.name == name:
|
100
103
|
self.current_state = (
|
101
|
-
list(self.
|
104
|
+
list(self.animations.values())[0] if self.animations else None
|
102
105
|
)
|
103
106
|
return True
|
104
107
|
|
105
|
-
def
|
108
|
+
def add_animation(
|
106
109
|
self,
|
107
|
-
|
108
|
-
surface: pygame.Surface,
|
109
|
-
size: Tuple[int, int],
|
110
|
-
duration_list: Union[List[int], int],
|
110
|
+
animation:Animation
|
111
111
|
) -> bool:
|
112
|
-
if name in self.
|
112
|
+
if animation.name in self.animations:
|
113
113
|
return False
|
114
|
-
self.
|
115
|
-
name, surface, size, duration_list
|
116
|
-
)
|
117
|
-
if len(self.animStates) == 1:
|
118
|
-
self.set_animState(name)
|
114
|
+
self.animations[animation.name] = animation
|
119
115
|
return True
|
120
116
|
|
121
|
-
def
|
117
|
+
def set_animation(
|
122
118
|
self, state: str, reset_counter: bool = True, lock: bool = False
|
123
119
|
) -> bool:
|
124
|
-
if state not in self.
|
120
|
+
if state not in self.animations or self._locked:
|
125
121
|
return False
|
122
|
+
|
123
|
+
animation = self.animations[state]
|
124
|
+
self.current_state = animation
|
126
125
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
self.rect = self.current_state.frames[0].get_rect(center=self.rect.center)
|
126
|
+
if self.current_state.frames:
|
127
|
+
self.rect = self.current_state.frames[0].get_frect(center=self.rect.center)
|
131
128
|
|
132
|
-
if reset_counter or self.float_counter >
|
129
|
+
if reset_counter or (self.float_counter > animation.duration_list_length):
|
133
130
|
self.float_counter = 0
|
131
|
+
|
134
132
|
if lock:
|
135
133
|
self.lock()
|
134
|
+
|
135
|
+
if self.transition_end_animation is not None:
|
136
|
+
self.transition_end_animation = None
|
136
137
|
return True
|
137
|
-
|
138
|
-
def
|
138
|
+
|
139
|
+
def transition_to_animation(self,transition:str,animation:str)->Self:
|
140
|
+
self.set_animation(transition)
|
141
|
+
self.transition_end_animation = animation
|
142
|
+
return self
|
143
|
+
|
144
|
+
def get_current_animation(self) -> Optional[Animation]:
|
139
145
|
return self.current_state
|
140
146
|
|
141
147
|
def update(self, dt: float) -> None:
|
142
|
-
s = self.
|
143
|
-
if self.
|
148
|
+
s = self.get_current_animation()
|
149
|
+
if self.animations and s is not None:
|
144
150
|
if not self.paused:
|
145
151
|
self.float_counter += 60 * dt
|
146
152
|
if self.float_counter > s.duration_list_length:
|
153
|
+
if self.transition_end_animation is not None:
|
154
|
+
# print(f"{self.transition_end_animation=}, {self.get_current_animation()=}")
|
155
|
+
self.set_animation(self.transition_end_animation)
|
156
|
+
if self.animation_end_callback is not None:
|
157
|
+
self.animation_end_callback()
|
147
158
|
self.float_counter = 0
|
148
|
-
|
159
|
+
super().update(dt)
|
160
|
+
|
161
|
+
|
162
|
+
def get_current_frame(self)->pygame.Surface:
|
163
|
+
return self.current_state.get_frame(self.float_counter, self.flipX)
|
149
164
|
|
150
165
|
def draw(self, camera: bf.Camera) -> None:
|
151
166
|
if (
|
@@ -155,7 +170,7 @@ class AnimatedSprite(bf.Entity):
|
|
155
170
|
):
|
156
171
|
return
|
157
172
|
camera.surface.blit(
|
158
|
-
self.
|
173
|
+
self.get_current_frame(),
|
159
174
|
camera.world_to_screen(self.rect),
|
160
175
|
)
|
161
176
|
return
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import batFramework as bf
|
2
|
+
from .stateMachine import State
|
3
|
+
from .animatedSprite import AnimatedSprite
|
4
|
+
from .dynamicEntity import DynamicEntity
|
5
|
+
|
6
|
+
class Character(AnimatedSprite,DynamicEntity):
|
7
|
+
def __init__(self) -> None:
|
8
|
+
super().__init__()
|
9
|
+
self.state_machine = bf.StateMachine(self)
|
10
|
+
self.do_setup_animations()
|
11
|
+
self.do_setup_states()
|
12
|
+
|
13
|
+
def set_state(self,state_name:str):
|
14
|
+
self.state_machine.set_state(state_name)
|
15
|
+
|
16
|
+
def get_current_state(self)->State:
|
17
|
+
return self.state_machine.get_current_state()
|
18
|
+
|
19
|
+
def update(self, dt: float) -> None:
|
20
|
+
self.state_machine.update(dt)
|
21
|
+
super().update(dt)
|
22
|
+
|
23
|
+
def do_setup_states(self):
|
24
|
+
pass
|
25
|
+
|
26
|
+
def do_setup_animations(self):
|
27
|
+
pass
|
batFramework/dynamicEntity.py
CHANGED
@@ -12,6 +12,7 @@ class DynamicEntity(bf.Entity):
|
|
12
12
|
) -> None:
|
13
13
|
super().__init__(size, surface_flags, convert_alpha,*args,**kwargs)
|
14
14
|
self.velocity = pygame.math.Vector2(0, 0)
|
15
|
+
self.ignore_collisions : bool = False
|
15
16
|
|
16
17
|
def on_collideX(self, collider: "DynamicEntity"):
|
17
18
|
"""
|
batFramework/enums.py
CHANGED
@@ -51,7 +51,7 @@ class easing(Enum):
|
|
51
51
|
EASE_IN = (0.95, 0, 1, 0.55)
|
52
52
|
EASE_OUT = (0.5, 1, 0.5, 1)
|
53
53
|
EASE_IN_OUT = (0.55, 0, 0.45, 1)
|
54
|
-
EASE_IN_OUT_ELASTIC = (0.
|
54
|
+
EASE_IN_OUT_ELASTIC = (0.76,-0.36,0.41,1.34)
|
55
55
|
|
56
56
|
def __init__(self, *control_points):
|
57
57
|
self.control_points = control_points
|
@@ -110,4 +110,4 @@ class actionType(Enum):
|
|
110
110
|
class textMode(Enum):
|
111
111
|
ALPHABETICAL = 0
|
112
112
|
NUMERICAL = 1
|
113
|
-
|
113
|
+
ALPHANUMERICAL = 3
|
batFramework/fontManager.py
CHANGED
@@ -42,7 +42,7 @@ class FontManager(metaclass=Singleton):
|
|
42
42
|
filename = name # if name is not given, name is the filename
|
43
43
|
self.FONTS[filename] = {}
|
44
44
|
# fill the dict
|
45
|
-
for size in range(self.MIN_FONT_SIZE, self.MAX_FONT_SIZE, 2):
|
45
|
+
for size in range(self.MIN_FONT_SIZE, self.MAX_FONT_SIZE+1, 2):
|
46
46
|
self.FONTS[filename][size] = pygame.font.Font(path, size=size)
|
47
47
|
|
48
48
|
def load_sysfont(self, font_name: str | None, key: str | None = ""):
|
@@ -52,7 +52,7 @@ class FontManager(metaclass=Singleton):
|
|
52
52
|
raise FileNotFoundError(f"Requested font '{font_name}' was not found")
|
53
53
|
self.FONTS[font_name] = {}
|
54
54
|
|
55
|
-
for size in range(self.MIN_FONT_SIZE, self.MAX_FONT_SIZE, 2):
|
55
|
+
for size in range(self.MIN_FONT_SIZE, self.MAX_FONT_SIZE+1, 2):
|
56
56
|
self.FONTS[key][size] = pygame.font.SysFont(font_name, size=size)
|
57
57
|
|
58
58
|
def get_font(
|
@@ -27,7 +27,7 @@ class ClickableWidget(Shape, InteractiveWidget):
|
|
27
27
|
self.set_debug_color("cyan")
|
28
28
|
self.set_relief(self.unpressed_relief)
|
29
29
|
|
30
|
-
def set_unpressed_relief(self, relief: int
|
30
|
+
def set_unpressed_relief(self, relief: int) -> Self:
|
31
31
|
if relief == self.unpressed_relief:
|
32
32
|
return self
|
33
33
|
self.unpressed_relief = relief
|
@@ -36,18 +36,17 @@ class ClickableWidget(Shape, InteractiveWidget):
|
|
36
36
|
self.set_relief(relief)
|
37
37
|
return self
|
38
38
|
|
39
|
-
def
|
40
|
-
self.silent_focus = value
|
41
|
-
return self
|
42
|
-
|
43
|
-
def set_pressed_relief(self, relief: int = 0) -> Self:
|
39
|
+
def set_pressed_relief(self, relief: int) -> Self:
|
44
40
|
if relief == self.pressed_relief:
|
45
41
|
return self
|
46
42
|
self.pressed_relief = relief
|
47
43
|
self.dirty_shape = True
|
48
44
|
if self.is_pressed:
|
49
45
|
self.set_relief(relief)
|
46
|
+
return self
|
50
47
|
|
48
|
+
def set_silent_focus(self, value: bool) -> Self:
|
49
|
+
self.silent_focus = value
|
51
50
|
return self
|
52
51
|
|
53
52
|
def set_click_down_sound(self, sound_name: str) -> Self:
|
@@ -143,7 +142,6 @@ class ClickableWidget(Shape, InteractiveWidget):
|
|
143
142
|
self.is_pressed = True
|
144
143
|
if self.click_down_sound:
|
145
144
|
bf.AudioManager().play_sound(self.click_down_sound)
|
146
|
-
|
147
145
|
pygame.mouse.set_cursor(self.click_cursor)
|
148
146
|
self.set_relief(self.pressed_relief)
|
149
147
|
|
@@ -219,3 +217,4 @@ class ClickableWidget(Shape, InteractiveWidget):
|
|
219
217
|
self._paint_disabled()
|
220
218
|
elif self.is_hovered:
|
221
219
|
self._paint_hovered()
|
220
|
+
|