batframework 1.0.9a6__py3-none-any.whl → 1.0.9a8__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 +20 -11
- batFramework/action.py +1 -1
- batFramework/animatedSprite.py +47 -116
- batFramework/animation.py +30 -5
- batFramework/audioManager.py +16 -13
- batFramework/baseScene.py +240 -0
- batFramework/camera.py +4 -0
- batFramework/constants.py +6 -1
- batFramework/cutscene.py +221 -21
- batFramework/cutsceneManager.py +5 -2
- batFramework/drawable.py +7 -5
- batFramework/easingController.py +10 -11
- batFramework/entity.py +21 -2
- batFramework/enums.py +48 -33
- batFramework/gui/__init__.py +3 -1
- batFramework/gui/animatedLabel.py +10 -2
- batFramework/gui/button.py +4 -31
- batFramework/gui/clickableWidget.py +42 -30
- batFramework/gui/constraints/constraints.py +212 -136
- batFramework/gui/container.py +72 -48
- batFramework/gui/debugger.py +12 -17
- batFramework/gui/draggableWidget.py +8 -11
- batFramework/gui/image.py +3 -10
- batFramework/gui/indicator.py +73 -1
- batFramework/gui/interactiveWidget.py +117 -100
- batFramework/gui/label.py +73 -63
- batFramework/gui/layout.py +221 -452
- batFramework/gui/meter.py +21 -7
- batFramework/gui/radioButton.py +0 -1
- batFramework/gui/root.py +99 -29
- batFramework/gui/selector.py +257 -0
- batFramework/gui/shape.py +13 -5
- batFramework/gui/slider.py +260 -93
- batFramework/gui/textInput.py +45 -21
- batFramework/gui/toggle.py +70 -52
- batFramework/gui/tooltip.py +30 -0
- batFramework/gui/widget.py +203 -125
- batFramework/manager.py +7 -8
- batFramework/particle.py +4 -1
- batFramework/propertyEaser.py +79 -0
- batFramework/renderGroup.py +17 -50
- batFramework/resourceManager.py +43 -13
- batFramework/scene.py +15 -335
- batFramework/sceneLayer.py +138 -0
- batFramework/sceneManager.py +31 -36
- batFramework/scrollingSprite.py +8 -3
- batFramework/sprite.py +1 -1
- batFramework/templates/__init__.py +1 -2
- batFramework/templates/controller.py +97 -0
- batFramework/timeManager.py +76 -22
- batFramework/transition.py +37 -103
- batFramework/utils.py +121 -3
- {batframework-1.0.9a6.dist-info → batframework-1.0.9a8.dist-info}/METADATA +24 -3
- batframework-1.0.9a8.dist-info/RECORD +66 -0
- {batframework-1.0.9a6.dist-info → batframework-1.0.9a8.dist-info}/WHEEL +1 -1
- batFramework/character.py +0 -27
- batFramework/templates/character.py +0 -43
- batFramework/templates/states.py +0 -166
- batframework-1.0.9a6.dist-info/RECORD +0 -63
- /batframework-1.0.9a6.dist-info/LICENCE → /batframework-1.0.9a8.dist-info/LICENSE +0 -0
- {batframework-1.0.9a6.dist-info → batframework-1.0.9a8.dist-info}/top_level.txt +0 -0
batFramework/manager.py
CHANGED
@@ -3,7 +3,7 @@ import pygame
|
|
3
3
|
import asyncio
|
4
4
|
|
5
5
|
class Manager(bf.SceneManager):
|
6
|
-
def __init__(self, *
|
6
|
+
def __init__(self, *initial_scenes) -> None:
|
7
7
|
super().__init__()
|
8
8
|
self.debug_mode: bf.enums.debugMode = bf.debugMode.HIDDEN
|
9
9
|
self.screen: pygame.Surface | None = bf.const.SCREEN
|
@@ -18,8 +18,8 @@ class Manager(bf.SceneManager):
|
|
18
18
|
bf.ResourceManager().set_sharedVar("debug_mode", self.debug_mode)
|
19
19
|
|
20
20
|
self.do_pre_init()
|
21
|
-
if
|
22
|
-
self.init_scenes(*
|
21
|
+
if initial_scenes:
|
22
|
+
self.init_scenes(*initial_scenes)
|
23
23
|
self.do_init()
|
24
24
|
|
25
25
|
@staticmethod
|
@@ -75,15 +75,15 @@ class Manager(bf.SceneManager):
|
|
75
75
|
self.print_status()
|
76
76
|
return
|
77
77
|
self.cutsceneManager.process_event(event)
|
78
|
+
if event.type == pygame.VIDEORESIZE and not (bf.const.FLAGS & pygame.SCALED):
|
79
|
+
bf.const.set_resolution((event.w, event.h))
|
80
|
+
|
78
81
|
if event.consumed: return
|
82
|
+
|
79
83
|
super().process_event(event)
|
80
84
|
if not event.consumed:
|
81
85
|
if event.type == pygame.QUIT:
|
82
86
|
self.running = False
|
83
|
-
elif event.type == pygame.VIDEORESIZE and not (
|
84
|
-
bf.const.FLAGS & pygame.SCALED
|
85
|
-
):
|
86
|
-
bf.const.set_resolution((event.w, event.h))
|
87
87
|
|
88
88
|
def update(self, dt: float) -> None:
|
89
89
|
self.timeManager.update(dt)
|
@@ -96,7 +96,6 @@ class Manager(bf.SceneManager):
|
|
96
96
|
raise Exception("Manager can't start without scenes")
|
97
97
|
if self.running:
|
98
98
|
raise Exception("Error : Already running")
|
99
|
-
return
|
100
99
|
self.is_async_running = True
|
101
100
|
self.running = True
|
102
101
|
dt: float = 0
|
batFramework/particle.py
CHANGED
@@ -82,6 +82,7 @@ class ParticleGenerator(bf.Drawable):
|
|
82
82
|
def __init__(self) -> None:
|
83
83
|
super().__init__((0, 0))
|
84
84
|
self.particles: list[Particle] = []
|
85
|
+
self.count = 0
|
85
86
|
|
86
87
|
def get_debug_outlines(self):
|
87
88
|
return
|
@@ -96,10 +97,11 @@ class ParticleGenerator(bf.Drawable):
|
|
96
97
|
particle.generator = self
|
97
98
|
particle.do_when_added()
|
98
99
|
self.particles.append(particle)
|
100
|
+
self.count += 1
|
99
101
|
|
100
102
|
def clear(self):
|
101
103
|
self.particles = []
|
102
|
-
|
104
|
+
self.count = 0
|
103
105
|
def update(self, dt: float):
|
104
106
|
particles_to_remove = []
|
105
107
|
for particle in self.particles:
|
@@ -108,6 +110,7 @@ class ParticleGenerator(bf.Drawable):
|
|
108
110
|
particles_to_remove.append(particle)
|
109
111
|
for p in particles_to_remove:
|
110
112
|
self.particles.remove(p)
|
113
|
+
self.count -= 1
|
111
114
|
|
112
115
|
def draw(self, camera) -> None:
|
113
116
|
camera.surface.fblits(
|
@@ -0,0 +1,79 @@
|
|
1
|
+
from .easingController import EasingController
|
2
|
+
import pygame
|
3
|
+
from typing import Callable, Any, Self
|
4
|
+
import batFramework as bf
|
5
|
+
|
6
|
+
class PropertyEaser(EasingController):
|
7
|
+
class EasedProperty:
|
8
|
+
def __init__(self, getter: Callable[[], Any], setter: Callable[[Any], None], end_value: Any, start_value: Any = None):
|
9
|
+
self.getter = getter
|
10
|
+
self.setter = setter
|
11
|
+
self.start_value = start_value if start_value is not None else getter()
|
12
|
+
self.end_value = end_value
|
13
|
+
|
14
|
+
def interpolate(self, t: float):
|
15
|
+
a, b = self.start_value, self.end_value
|
16
|
+
if isinstance(a, (int, float)):
|
17
|
+
return a + (b - a) * t
|
18
|
+
elif isinstance(a, pygame.Vector2):
|
19
|
+
return a.lerp(b, t)
|
20
|
+
elif isinstance(a, pygame.Color):
|
21
|
+
return pygame.Color(
|
22
|
+
round(a.r + (b.r - a.r) * t),
|
23
|
+
round(a.g + (b.g - a.g) * t),
|
24
|
+
round(a.b + (b.b - a.b) * t),
|
25
|
+
round(a.a + (b.a - a.a) * t),
|
26
|
+
)
|
27
|
+
else:
|
28
|
+
raise TypeError(f"Unsupported type for interpolation: {type(a)}")
|
29
|
+
|
30
|
+
def apply(self, t: float):
|
31
|
+
self.setter(self.interpolate(t))
|
32
|
+
|
33
|
+
def __init__(
|
34
|
+
self,
|
35
|
+
duration: float = 1,
|
36
|
+
easing: bf.easing = bf.easing.LINEAR,
|
37
|
+
loop: int = 0,
|
38
|
+
register: str = "global",
|
39
|
+
end_callback: Callable[[], Any] = None,
|
40
|
+
):
|
41
|
+
self.properties: list[PropertyEaser.EasedProperty] = []
|
42
|
+
|
43
|
+
def update_all(progress):
|
44
|
+
for prop in self.properties:
|
45
|
+
prop.apply(progress)
|
46
|
+
|
47
|
+
super().__init__(duration, easing, update_all, end_callback, loop, register)
|
48
|
+
|
49
|
+
def __str__(self):
|
50
|
+
return f"(PROP){super().__str__()}"
|
51
|
+
|
52
|
+
def add_attr(
|
53
|
+
self,
|
54
|
+
obj: Any,
|
55
|
+
attr: str,
|
56
|
+
end_value: Any,
|
57
|
+
start_value: Any = None,
|
58
|
+
)->Self:
|
59
|
+
self.properties.append(
|
60
|
+
PropertyEaser.EasedProperty(
|
61
|
+
getter=lambda o=obj, a=attr: getattr(o, a),
|
62
|
+
setter=lambda v, o=obj, a=attr: setattr(o, a, v),
|
63
|
+
end_value=end_value,
|
64
|
+
start_value=start_value,
|
65
|
+
)
|
66
|
+
)
|
67
|
+
return self
|
68
|
+
|
69
|
+
def add_custom(
|
70
|
+
self,
|
71
|
+
getter: Callable[[], Any],
|
72
|
+
setter: Callable[[Any], None],
|
73
|
+
end_value: Any,
|
74
|
+
start_value: Any = None,
|
75
|
+
)->Self:
|
76
|
+
self.properties.append(
|
77
|
+
PropertyEaser.EasedProperty(getter, setter, end_value, start_value)
|
78
|
+
)
|
79
|
+
return self
|
batFramework/renderGroup.py
CHANGED
@@ -1,11 +1,6 @@
|
|
1
1
|
import batFramework as bf
|
2
2
|
import pygame
|
3
|
-
from typing import
|
4
|
-
|
5
|
-
"""
|
6
|
-
+ same render order
|
7
|
-
+ fblits
|
8
|
-
"""
|
3
|
+
from typing import Callable, Iterator
|
9
4
|
|
10
5
|
|
11
6
|
class RenderGroup(bf.Drawable):
|
@@ -14,54 +9,26 @@ class RenderGroup(bf.Drawable):
|
|
14
9
|
) -> None:
|
15
10
|
super().__init__()
|
16
11
|
self.entity_iterator = entity_iterator
|
17
|
-
|
12
|
+
self.blit_flags = blit_flags
|
18
13
|
self.set_debug_color("white")
|
19
14
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
yield from e.get_debug_outlines()
|
24
|
-
|
25
|
-
def set_parent_scene(self, scene) -> Self:
|
26
|
-
self.parent_scene = scene
|
27
|
-
for e in self.entity_iterator():
|
28
|
-
e.set_parent_scene(scene)
|
29
|
-
return self
|
30
|
-
|
31
|
-
def process_event(self, event: pygame.Event) -> bool:
|
32
|
-
"""
|
33
|
-
Returns bool : True if the method is blocking (no propagation to next children of the scene)
|
34
|
-
"""
|
35
|
-
self.do_process_actions(event)
|
36
|
-
res = self.do_handle_event(event)
|
37
|
-
if res:
|
38
|
-
return res
|
39
|
-
for e in self.entity_iterator():
|
40
|
-
if e.process_event(event):
|
41
|
-
return True
|
42
|
-
return False
|
15
|
+
def draw(self, camera: bf.Camera) -> None:
|
16
|
+
if not self.visible:
|
17
|
+
return
|
43
18
|
|
44
|
-
|
45
|
-
"""
|
46
|
-
Update method to be overriden by subclasses of entity
|
47
|
-
"""
|
19
|
+
fblits_data = []
|
48
20
|
for e in self.entity_iterator():
|
49
|
-
e
|
50
|
-
|
51
|
-
|
21
|
+
if not getattr(e, "drawn_by_group", False):
|
22
|
+
# Set flag to skip their individual draw call
|
23
|
+
e.drawn_by_group = True
|
52
24
|
|
53
|
-
|
54
|
-
|
25
|
+
if e.visible and camera.rect.colliderect(e.rect):
|
26
|
+
fblits_data.append(
|
27
|
+
(e.surface, (e.rect.x - camera.rect.x, e.rect.y - camera.rect.y))
|
28
|
+
)
|
55
29
|
|
56
|
-
def draw(self, camera: bf.Camera) -> None:
|
57
|
-
"""
|
58
|
-
Draw the entity onto the camera with coordinate transposing
|
59
|
-
"""
|
60
|
-
if not self.visible:
|
61
|
-
return
|
62
|
-
fblits_data = (
|
63
|
-
(e.surface, (e.rect.x - camera.rect.x, e.rect.y - camera.rect.y))
|
64
|
-
for e in self.entity_iterator()
|
65
|
-
if camera.rect.colliderect(e.rect)
|
66
|
-
)
|
67
30
|
camera.surface.fblits(fblits_data, self.blit_flags)
|
31
|
+
|
32
|
+
def get_debug_outlines(self):
|
33
|
+
for e in self.entity_iterator():
|
34
|
+
yield from e.get_debug_outlines()
|
batFramework/resourceManager.py
CHANGED
@@ -3,8 +3,10 @@ import os
|
|
3
3
|
import pygame
|
4
4
|
import sys
|
5
5
|
import json
|
6
|
-
from typing import Any
|
6
|
+
from typing import Any, Callable
|
7
7
|
from .utils import Singleton
|
8
|
+
import asyncio
|
9
|
+
|
8
10
|
|
9
11
|
if getattr(sys, "frozen", False):
|
10
12
|
# If the application is run as a bundle, the PyInstaller bootloader
|
@@ -17,32 +19,50 @@ else:
|
|
17
19
|
|
18
20
|
class ResourceManager(metaclass=Singleton):
|
19
21
|
def __init__(self):
|
20
|
-
self.shared_variables: dict[str,Any] = {}
|
22
|
+
self.shared_variables: dict[str, Any] = {}
|
21
23
|
self.convert_image_cache = {}
|
22
24
|
self.convert_alpha_image_cache = {}
|
23
25
|
self.sound_cache = {}
|
24
26
|
self.RESOURCE_PATH = "."
|
27
|
+
self.loading_thread = None
|
25
28
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
29
|
+
def load_resources(self, path: str, progress_callback: Callable[[float], Any] = None):
|
30
|
+
"""
|
31
|
+
loads resources from a directory.
|
32
|
+
Progress is reported through the callback.
|
33
|
+
Supposed to be asynchronous but don't use it as such yet
|
34
|
+
"""
|
35
|
+
self.progress_callback = progress_callback
|
36
|
+
|
37
|
+
total_files = sum(
|
38
|
+
len(files) for _, _, files in os.walk(path) if not any(f.startswith(".") for f in files)
|
39
|
+
)
|
40
|
+
|
41
|
+
loaded_files = 0
|
30
42
|
|
43
|
+
for root, dirs, files in os.walk(path):
|
44
|
+
files = [f for f in files if not f.startswith(".")]
|
45
|
+
dirs[:] = [d for d in dirs if not (d.startswith(".") or d.startswith("__"))]
|
31
46
|
for file in files:
|
32
47
|
file_path = os.path.join(root, file)
|
48
|
+
|
49
|
+
# Simulate resource loading
|
50
|
+
# await asyncio.sleep(0) # Yield control to the event loop
|
51
|
+
|
33
52
|
if file.lower().endswith((".png", ".jpg", ".jpeg", ".gif")):
|
34
53
|
self.load_image(file_path)
|
35
|
-
|
36
|
-
|
37
|
-
elif file.lower().endswith((".mp3", ".wav")):
|
54
|
+
elif file.lower().endswith((".mp3", ".wav", ".ogg")):
|
38
55
|
bf.AudioManager().load_sound(file.split(".")[0], file_path)
|
39
|
-
# print(f"Loaded sound : '{file_path}'")
|
40
|
-
|
41
56
|
elif file.lower().endswith((".ttf", ".otf")):
|
42
57
|
bf.FontManager().load_font(file_path, file.split(".")[0])
|
43
|
-
# print(f"Loaded font : '{file_path}'")
|
44
58
|
|
45
|
-
|
59
|
+
loaded_files += 1
|
60
|
+
# Report progress
|
61
|
+
# if self.progress_callback:
|
62
|
+
# self.progress_callback(loaded_files / total_files)
|
63
|
+
|
64
|
+
print(f"Loaded resources in directory: '{path}'")
|
65
|
+
|
46
66
|
|
47
67
|
def set_resource_path(self, path: str):
|
48
68
|
self.RESOURCE_PATH = os.path.join(application_path, path)
|
@@ -60,6 +80,7 @@ class ResourceManager(metaclass=Singleton):
|
|
60
80
|
self.convert_image_cache[key] = pygame.image.load(path).convert()
|
61
81
|
self.convert_alpha_image_cache[key] = pygame.image.load(path).convert_alpha()
|
62
82
|
|
83
|
+
|
63
84
|
def get_image(self, path, convert_alpha: bool = False) -> pygame.Surface | None:
|
64
85
|
key = self.get_path(path)
|
65
86
|
return (
|
@@ -93,6 +114,15 @@ class ResourceManager(metaclass=Singleton):
|
|
93
114
|
self.shared_variables[name] = value
|
94
115
|
return True
|
95
116
|
|
117
|
+
def set_sharedVars(self, variables: dict) -> bool:
|
118
|
+
"""
|
119
|
+
Set multiple shared variables at once. This will be accessible (read/write) from any scene.
|
120
|
+
"""
|
121
|
+
if not isinstance(variables, dict):
|
122
|
+
raise ValueError("Input must be a dictionary")
|
123
|
+
self.shared_variables.update(variables)
|
124
|
+
return True
|
125
|
+
|
96
126
|
def get_sharedVar(self, name, error_value=None):
|
97
127
|
"""
|
98
128
|
Get a shared variable
|