batframework 1.0.10__py3-none-any.whl → 2.0.0__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 +84 -52
- batFramework/action.py +280 -252
- batFramework/actionContainer.py +105 -38
- batFramework/animatedSprite.py +81 -117
- batFramework/animation.py +91 -0
- batFramework/audioManager.py +156 -85
- batFramework/baseScene.py +249 -0
- batFramework/camera.py +245 -123
- batFramework/constants.py +57 -75
- batFramework/cutscene.py +239 -119
- batFramework/cutsceneManager.py +34 -0
- batFramework/drawable.py +107 -0
- batFramework/dynamicEntity.py +30 -23
- batFramework/easingController.py +58 -0
- batFramework/entity.py +130 -123
- batFramework/enums.py +171 -0
- batFramework/fontManager.py +65 -0
- batFramework/gui/__init__.py +28 -14
- batFramework/gui/animatedLabel.py +90 -0
- batFramework/gui/button.py +18 -84
- batFramework/gui/clickableWidget.py +244 -0
- batFramework/gui/collapseContainer.py +98 -0
- batFramework/gui/constraints/__init__.py +1 -0
- batFramework/gui/constraints/constraints.py +1066 -0
- batFramework/gui/container.py +220 -49
- batFramework/gui/debugger.py +140 -47
- batFramework/gui/draggableWidget.py +63 -0
- batFramework/gui/image.py +61 -23
- batFramework/gui/indicator.py +116 -40
- batFramework/gui/interactiveWidget.py +243 -22
- batFramework/gui/label.py +147 -110
- batFramework/gui/layout.py +442 -81
- batFramework/gui/meter.py +155 -0
- batFramework/gui/radioButton.py +43 -0
- batFramework/gui/root.py +228 -60
- batFramework/gui/scrollingContainer.py +282 -0
- batFramework/gui/selector.py +232 -0
- batFramework/gui/shape.py +286 -86
- batFramework/gui/slider.py +353 -0
- batFramework/gui/style.py +10 -0
- batFramework/gui/styleManager.py +49 -0
- batFramework/gui/syncedVar.py +43 -0
- batFramework/gui/textInput.py +331 -0
- batFramework/gui/textWidget.py +308 -0
- batFramework/gui/toggle.py +140 -62
- batFramework/gui/tooltip.py +35 -0
- batFramework/gui/widget.py +546 -307
- batFramework/manager.py +131 -50
- batFramework/particle.py +118 -0
- batFramework/propertyEaser.py +79 -0
- batFramework/renderGroup.py +34 -0
- batFramework/resourceManager.py +130 -0
- batFramework/scene.py +31 -226
- batFramework/sceneLayer.py +134 -0
- batFramework/sceneManager.py +200 -165
- batFramework/scrollingSprite.py +115 -0
- batFramework/sprite.py +46 -0
- batFramework/stateMachine.py +49 -51
- batFramework/templates/__init__.py +2 -0
- batFramework/templates/character.py +15 -0
- batFramework/templates/controller.py +158 -0
- batFramework/templates/stateMachine.py +39 -0
- batFramework/tileset.py +46 -0
- batFramework/timeManager.py +213 -0
- batFramework/transition.py +162 -157
- batFramework/triggerZone.py +22 -22
- batFramework/utils.py +306 -184
- {batframework-1.0.10.dist-info → batframework-2.0.0.dist-info}/LICENSE +1 -1
- {batframework-1.0.10.dist-info → batframework-2.0.0.dist-info}/METADATA +3 -4
- batframework-2.0.0.dist-info/RECORD +72 -0
- batFramework/cutsceneBlocks.py +0 -176
- batFramework/debugger.py +0 -48
- batFramework/easing.py +0 -71
- batFramework/gui/constraints.py +0 -204
- batFramework/gui/frame.py +0 -19
- batFramework/particles.py +0 -77
- batFramework/time.py +0 -75
- batFramework/transitionManager.py +0 -0
- batframework-1.0.10.dist-info/RECORD +0 -43
- {batframework-1.0.10.dist-info → batframework-2.0.0.dist-info}/WHEEL +0 -0
- {batframework-1.0.10.dist-info → batframework-2.0.0.dist-info}/top_level.txt +0 -0
batFramework/manager.py
CHANGED
@@ -1,50 +1,131 @@
|
|
1
|
-
import batFramework as bf
|
2
|
-
import
|
3
|
-
import
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
self.
|
11
|
-
self.
|
12
|
-
|
13
|
-
self.
|
14
|
-
self.
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
1
|
+
import batFramework as bf
|
2
|
+
from batFramework import const
|
3
|
+
import pygame
|
4
|
+
import asyncio
|
5
|
+
|
6
|
+
|
7
|
+
class Manager(bf.SceneManager):
|
8
|
+
def __init__(self, *initial_scenes) -> None:
|
9
|
+
super().__init__()
|
10
|
+
self.debug_mode: bf.enums.debugMode = bf.debugMode.HIDDEN
|
11
|
+
self.screen: pygame.Surface | None = bf.const.SCREEN
|
12
|
+
self.timeManager = bf.TimeManager()
|
13
|
+
self.cutsceneManager = bf.CutsceneManager()
|
14
|
+
self.cutsceneManager.set_manager(self)
|
15
|
+
self.clock: pygame.Clock = pygame.Clock()
|
16
|
+
self.is_async_running : bool = False
|
17
|
+
self.running = False
|
18
|
+
pygame.mouse.set_cursor(bf.const.DEFAULT_CURSOR)
|
19
|
+
bf.ResourceManager().set_sharedVar("clock", self.clock)
|
20
|
+
bf.ResourceManager().set_sharedVar("debug_mode", self.debug_mode)
|
21
|
+
|
22
|
+
self.do_pre_init()
|
23
|
+
if initial_scenes:
|
24
|
+
self.init_scenes(*initial_scenes)
|
25
|
+
self.do_init()
|
26
|
+
|
27
|
+
@staticmethod
|
28
|
+
def set_icon(path: str) -> None:
|
29
|
+
surf = pygame.image.load(bf.ResourceManager().get_path(path)).convert_alpha()
|
30
|
+
pygame.display.set_icon(surf)
|
31
|
+
|
32
|
+
def print_status(self):
|
33
|
+
"""
|
34
|
+
Print detailed information about the current state of the scenes, shared variables,
|
35
|
+
and additional timers managed by the subclass.
|
36
|
+
"""
|
37
|
+
# Call the parent class's print_status method to include its information
|
38
|
+
super().print_status()
|
39
|
+
# Add the timers information in a cohesive manner
|
40
|
+
print("\n" + "=" * 50)
|
41
|
+
print(" TIMERS".center(50))
|
42
|
+
print("=" * 50)
|
43
|
+
# Print the timers information
|
44
|
+
print(self.timeManager)
|
45
|
+
# End with a visual separator
|
46
|
+
print("=" * 50 + "\n")
|
47
|
+
|
48
|
+
|
49
|
+
def get_fps(self) -> float:
|
50
|
+
return self.clock.get_fps()
|
51
|
+
|
52
|
+
def do_init(self) -> None:
|
53
|
+
pass
|
54
|
+
|
55
|
+
def do_pre_init(self) -> None:
|
56
|
+
pass
|
57
|
+
|
58
|
+
def stop(self) -> None:
|
59
|
+
self.running = False
|
60
|
+
|
61
|
+
def process_event(self, event: pygame.Event):
|
62
|
+
event.consumed = False
|
63
|
+
keys = pygame.key.get_pressed()
|
64
|
+
if (
|
65
|
+
bf.const.ALLOW_DEBUG and
|
66
|
+
keys[pygame.K_LCTRL]
|
67
|
+
and keys[pygame.K_LSHIFT]
|
68
|
+
and event.type == pygame.KEYDOWN
|
69
|
+
):
|
70
|
+
if event.key == pygame.K_d:
|
71
|
+
self.cycle_debug_mode()
|
72
|
+
return
|
73
|
+
if event.key == pygame.K_p:
|
74
|
+
self.print_status()
|
75
|
+
return
|
76
|
+
self.cutsceneManager.process_event(event)
|
77
|
+
if event.type == pygame.VIDEORESIZE and not (bf.const.FLAGS & pygame.SCALED):
|
78
|
+
bf.const.set_resolution((event.w, event.h))
|
79
|
+
|
80
|
+
if event.consumed: return
|
81
|
+
|
82
|
+
super().process_event(event)
|
83
|
+
if not event.consumed:
|
84
|
+
if event.type == pygame.QUIT:
|
85
|
+
self.running = False
|
86
|
+
|
87
|
+
def update(self, dt: float) -> None:
|
88
|
+
self.timeManager.update(dt)
|
89
|
+
self.cutsceneManager.update(dt)
|
90
|
+
super().update(dt)
|
91
|
+
|
92
|
+
|
93
|
+
async def run_async(self):
|
94
|
+
if len(self.scenes) == 0:
|
95
|
+
raise Exception("Manager can't start without scenes")
|
96
|
+
if self.running:
|
97
|
+
raise Exception("Error : Already running")
|
98
|
+
self.is_async_running = True
|
99
|
+
self.running = True
|
100
|
+
dt: float = 0
|
101
|
+
while self.running:
|
102
|
+
for event in pygame.event.get():
|
103
|
+
self.process_event(event)
|
104
|
+
# update
|
105
|
+
self.update(dt)
|
106
|
+
# render
|
107
|
+
self.draw(self.screen)
|
108
|
+
pygame.display.flip()
|
109
|
+
dt = self.clock.tick(bf.const.FPS) / 1000
|
110
|
+
dt = min(dt, 0.02) # dirty fix for dt being too high when window not focused for a long time
|
111
|
+
await asyncio.sleep(0)
|
112
|
+
pygame.quit()
|
113
|
+
|
114
|
+
def run(self) -> None:
|
115
|
+
if len(self.scenes) == 0:
|
116
|
+
raise Exception("Manager can't start without scenes")
|
117
|
+
if self.running:
|
118
|
+
raise Exception("Error : Already running")
|
119
|
+
self.running = True
|
120
|
+
dt: float = 0
|
121
|
+
while self.running:
|
122
|
+
for event in pygame.event.get():
|
123
|
+
self.process_event(event)
|
124
|
+
# update
|
125
|
+
self.update(dt)
|
126
|
+
# render
|
127
|
+
self.draw(self.screen)
|
128
|
+
pygame.display.flip()
|
129
|
+
dt = self.clock.tick(bf.const.FPS) / 1000
|
130
|
+
dt = min(dt, 0.02) # fix for dt being too high when window not focused for a long time
|
131
|
+
pygame.quit()
|
batFramework/particle.py
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
import batFramework as bf
|
2
|
+
import pygame
|
3
|
+
from pygame.math import Vector2
|
4
|
+
|
5
|
+
|
6
|
+
class Particle:
|
7
|
+
def __init__(self, *args, **kwargs):
|
8
|
+
self.dead = False
|
9
|
+
self.surface = None
|
10
|
+
self.generator = None
|
11
|
+
|
12
|
+
def do_when_added(self):
|
13
|
+
pass
|
14
|
+
|
15
|
+
def update(self, dt):
|
16
|
+
pass
|
17
|
+
|
18
|
+
def kill(self):
|
19
|
+
self.dead = True
|
20
|
+
|
21
|
+
def update_surface(self):
|
22
|
+
pass
|
23
|
+
|
24
|
+
|
25
|
+
class TimedParticle(Particle):
|
26
|
+
def __init__(self, duration):
|
27
|
+
super().__init__()
|
28
|
+
self.duration = duration
|
29
|
+
|
30
|
+
def do_when_added(self):
|
31
|
+
if self.generator and self.generator.parent_scene:
|
32
|
+
self.timer = bf.SceneTimer(
|
33
|
+
self.duration, end_callback=self.kill,
|
34
|
+
scene_name=self.generator.parent_scene.name).start()
|
35
|
+
else:
|
36
|
+
self.timer = bf.Timer(self.duration, end_callback=self.kill).start()
|
37
|
+
|
38
|
+
|
39
|
+
class BasicParticle(TimedParticle):
|
40
|
+
def __init__(
|
41
|
+
self,
|
42
|
+
start_pos: tuple[float, float],
|
43
|
+
start_vel: tuple[float, float],
|
44
|
+
duration=1,
|
45
|
+
color=None,
|
46
|
+
size: tuple[int, int] = (4, 4),
|
47
|
+
*args,
|
48
|
+
**kwargs,
|
49
|
+
):
|
50
|
+
super().__init__(duration)
|
51
|
+
self.rect = pygame.FRect(0,0, *size)
|
52
|
+
self.rect.center = start_pos
|
53
|
+
self.surface = pygame.Surface(size)
|
54
|
+
self.velocity = Vector2(start_vel)
|
55
|
+
if color:
|
56
|
+
self.surface.fill(color)
|
57
|
+
self.start()
|
58
|
+
|
59
|
+
def start(self):
|
60
|
+
pass
|
61
|
+
|
62
|
+
def update(self, dt):
|
63
|
+
super().update(dt)
|
64
|
+
self.rect.center += self.velocity * dt
|
65
|
+
self.update_surface()
|
66
|
+
|
67
|
+
def update_surface(self):
|
68
|
+
self.surface.set_alpha(255 - int(self.timer.get_progression() * 255))
|
69
|
+
|
70
|
+
|
71
|
+
class DirectionalParticle(BasicParticle):
|
72
|
+
def start(self):
|
73
|
+
self.original_surface = self.surface.copy()
|
74
|
+
|
75
|
+
def update_surface(self):
|
76
|
+
angle = self.velocity.angle_to(Vector2(1, 0))
|
77
|
+
self.surface = pygame.transform.rotate(self.original_surface, angle)
|
78
|
+
super().update_surface()
|
79
|
+
|
80
|
+
|
81
|
+
class ParticleGenerator(bf.Drawable):
|
82
|
+
def __init__(self) -> None:
|
83
|
+
super().__init__((0, 0))
|
84
|
+
self.particles: list[Particle] = []
|
85
|
+
self.count = 0
|
86
|
+
|
87
|
+
def get_debug_outlines(self):
|
88
|
+
return
|
89
|
+
for particle in self.particles:
|
90
|
+
yield (
|
91
|
+
particle.rect.move(particle.rect.w // 2, particle.rect.h // 2),
|
92
|
+
"blue",
|
93
|
+
)
|
94
|
+
yield (self.rect, "cyan")
|
95
|
+
|
96
|
+
def add_particle(self, particle:Particle):
|
97
|
+
particle.generator = self
|
98
|
+
particle.do_when_added()
|
99
|
+
self.particles.append(particle)
|
100
|
+
self.count += 1
|
101
|
+
|
102
|
+
def clear(self):
|
103
|
+
self.particles = []
|
104
|
+
self.count = 0
|
105
|
+
def update(self, dt: float):
|
106
|
+
particles_to_remove = []
|
107
|
+
for particle in self.particles:
|
108
|
+
particle.update(dt)
|
109
|
+
if particle.dead:
|
110
|
+
particles_to_remove.append(particle)
|
111
|
+
for p in particles_to_remove:
|
112
|
+
self.particles.remove(p)
|
113
|
+
self.count -= 1
|
114
|
+
|
115
|
+
def draw(self, camera) -> None:
|
116
|
+
camera.surface.fblits(
|
117
|
+
[(p.surface, camera.world_to_screen(p.rect)) for p in self.particles]
|
118
|
+
)
|
@@ -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
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import batFramework as bf
|
2
|
+
import pygame
|
3
|
+
from typing import Callable, Iterator
|
4
|
+
|
5
|
+
|
6
|
+
class RenderGroup(bf.Drawable):
|
7
|
+
def __init__(
|
8
|
+
self, entity_iterator: Callable[[], Iterator[bf.Drawable]], blit_flags: int = 0
|
9
|
+
) -> None:
|
10
|
+
super().__init__()
|
11
|
+
self.entity_iterator = entity_iterator
|
12
|
+
self.blit_flags = blit_flags
|
13
|
+
self.set_debug_color("white")
|
14
|
+
|
15
|
+
def draw(self, camera: bf.Camera) -> None:
|
16
|
+
if not self.visible:
|
17
|
+
return
|
18
|
+
|
19
|
+
fblits_data = []
|
20
|
+
for e in self.entity_iterator():
|
21
|
+
if not getattr(e, "drawn_by_group", False):
|
22
|
+
# Set flag to skip their individual draw call
|
23
|
+
e.drawn_by_group = True
|
24
|
+
|
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
|
+
)
|
29
|
+
|
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()
|
@@ -0,0 +1,130 @@
|
|
1
|
+
import batFramework as bf
|
2
|
+
import os
|
3
|
+
import pygame
|
4
|
+
import sys
|
5
|
+
import json
|
6
|
+
from typing import Any, Callable
|
7
|
+
from .utils import Singleton
|
8
|
+
import asyncio
|
9
|
+
|
10
|
+
|
11
|
+
if getattr(sys, "frozen", False):
|
12
|
+
# If the application is run as a bundle, the PyInstaller bootloader
|
13
|
+
# extends the sys module by a flag frozen=True and sets the app
|
14
|
+
# path into variable _MEIPASS'.
|
15
|
+
application_path = sys._MEIPASS
|
16
|
+
else:
|
17
|
+
application_path = os.getcwd()
|
18
|
+
|
19
|
+
|
20
|
+
class ResourceManager(metaclass=Singleton):
|
21
|
+
def __init__(self):
|
22
|
+
self.shared_variables: dict[str, Any] = {}
|
23
|
+
self.convert_image_cache = {}
|
24
|
+
self.convert_alpha_image_cache = {}
|
25
|
+
self.sound_cache = {}
|
26
|
+
self.RESOURCE_PATH = "."
|
27
|
+
self.loading_thread = None
|
28
|
+
|
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
|
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("__"))]
|
46
|
+
for file in files:
|
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
|
+
|
52
|
+
if file.lower().endswith((".png", ".jpg", ".jpeg", ".gif")):
|
53
|
+
self.load_image(file_path)
|
54
|
+
elif file.lower().endswith((".mp3", ".wav", ".ogg")):
|
55
|
+
bf.AudioManager().load_sound(file.split(".")[0], file_path)
|
56
|
+
elif file.lower().endswith((".ttf", ".otf")):
|
57
|
+
bf.FontManager().load_font(file_path, file.split(".")[0])
|
58
|
+
|
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
|
+
|
66
|
+
|
67
|
+
def set_resource_path(self, path: str):
|
68
|
+
self.RESOURCE_PATH = os.path.join(application_path, path)
|
69
|
+
print(f"Resource path : '{self.RESOURCE_PATH}'")
|
70
|
+
|
71
|
+
def get_path(self, path: str) -> str:
|
72
|
+
# Normalize path separators
|
73
|
+
normalized_path = path.replace("/", os.sep).replace("\\", os.sep)
|
74
|
+
return os.path.join(self.RESOURCE_PATH, normalized_path)
|
75
|
+
|
76
|
+
def load_image(self, path) -> None:
|
77
|
+
key = self.get_path(path)
|
78
|
+
if key in self.convert_image_cache:
|
79
|
+
return
|
80
|
+
self.convert_image_cache[key] = pygame.image.load(path).convert()
|
81
|
+
self.convert_alpha_image_cache[key] = pygame.image.load(path).convert_alpha()
|
82
|
+
|
83
|
+
|
84
|
+
def get_image(self, path, convert_alpha: bool = False) -> pygame.Surface | None:
|
85
|
+
key = self.get_path(path)
|
86
|
+
return (
|
87
|
+
self.convert_alpha_image_cache.get(key, None)
|
88
|
+
if convert_alpha
|
89
|
+
else self.convert_image_cache.get(key, None)
|
90
|
+
)
|
91
|
+
|
92
|
+
def load_json_from_file(self, path: str) -> dict | None:
|
93
|
+
try:
|
94
|
+
with open(self.get_path(path), "r") as file:
|
95
|
+
data = json.load(file)
|
96
|
+
return data
|
97
|
+
except FileNotFoundError:
|
98
|
+
print(f"File '{path}' not found")
|
99
|
+
return None
|
100
|
+
|
101
|
+
def save_json_to_file(self, path: str, data) -> bool:
|
102
|
+
try:
|
103
|
+
with open(self.get_path(path), "w") as file:
|
104
|
+
json.dump(data, file, indent=2)
|
105
|
+
return True
|
106
|
+
except FileNotFoundError:
|
107
|
+
return False
|
108
|
+
|
109
|
+
|
110
|
+
def set_sharedVar(self, name, value) -> bool:
|
111
|
+
"""
|
112
|
+
Set a shared variable of any type. This will be accessible (read/write) from any scene
|
113
|
+
"""
|
114
|
+
self.shared_variables[name] = value
|
115
|
+
return True
|
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
|
+
|
126
|
+
def get_sharedVar(self, name, error_value=None):
|
127
|
+
"""
|
128
|
+
Get a shared variable
|
129
|
+
"""
|
130
|
+
return self.shared_variables.get(name, error_value)
|