batframework 1.0.9a7__py3-none-any.whl → 1.0.9a9__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 +8 -5
- batFramework/baseScene.py +240 -0
- batFramework/camera.py +4 -0
- batFramework/constants.py +6 -2
- 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 +6 -3
- batFramework/gui/animatedLabel.py +10 -2
- batFramework/gui/button.py +4 -31
- batFramework/gui/clickableWidget.py +63 -50
- batFramework/gui/constraints/constraints.py +212 -136
- batFramework/gui/container.py +77 -58
- batFramework/gui/debugger.py +12 -17
- batFramework/gui/draggableWidget.py +21 -17
- batFramework/gui/image.py +3 -10
- batFramework/gui/indicator.py +56 -1
- batFramework/gui/interactiveWidget.py +127 -108
- batFramework/gui/label.py +73 -64
- batFramework/gui/layout.py +286 -445
- batFramework/gui/meter.py +42 -20
- batFramework/gui/radioButton.py +20 -69
- batFramework/gui/root.py +99 -29
- batFramework/gui/selector.py +250 -0
- batFramework/gui/shape.py +13 -5
- batFramework/gui/slider.py +262 -107
- batFramework/gui/syncedVar.py +49 -0
- batFramework/gui/textInput.py +46 -22
- batFramework/gui/toggle.py +70 -52
- batFramework/gui/tooltip.py +30 -0
- batFramework/gui/widget.py +222 -135
- 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 +125 -66
- {batframework-1.0.9a7.dist-info → batframework-1.0.9a9.dist-info}/METADATA +24 -3
- batframework-1.0.9a9.dist-info/RECORD +67 -0
- {batframework-1.0.9a7.dist-info → batframework-1.0.9a9.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.9a7.dist-info/RECORD +0 -63
- /batframework-1.0.9a7.dist-info/LICENCE → /batframework-1.0.9a9.dist-info/LICENSE +0 -0
- {batframework-1.0.9a7.dist-info → batframework-1.0.9a9.dist-info}/top_level.txt +0 -0
@@ -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
|
batFramework/scene.py
CHANGED
@@ -1,351 +1,31 @@
|
|
1
|
-
from
|
2
|
-
import re
|
3
|
-
from collections import OrderedDict
|
4
|
-
import itertools
|
5
|
-
|
6
|
-
from typing import TYPE_CHECKING, Any
|
7
|
-
if TYPE_CHECKING:
|
8
|
-
from .manager import Manager
|
9
|
-
from .sceneManager import SceneManager
|
10
|
-
import pygame
|
1
|
+
from .baseScene import BaseScene
|
11
2
|
import batFramework as bf
|
12
3
|
|
13
4
|
|
14
|
-
class Scene:
|
15
|
-
def __init__(
|
16
|
-
self,
|
17
|
-
name: str,
|
18
|
-
hud_convert_alpha: bool = True,
|
19
|
-
world_convert_alpha: bool = False,
|
20
|
-
) -> None:
|
5
|
+
class Scene(BaseScene):
|
6
|
+
def __init__(self,name: str) -> None:
|
21
7
|
"""
|
22
|
-
|
23
|
-
|
8
|
+
Default Scene object.
|
9
|
+
Has 2 layers (world and hud) by default
|
10
|
+
Contains an exposed root gui object on the hud layer
|
24
11
|
Args:
|
25
12
|
name: Name of the scene.
|
26
|
-
enable_alpha (bool, optional): Enable alpha channel for the scene surfaces. Defaults to True.
|
27
13
|
"""
|
28
|
-
|
29
|
-
self.
|
30
|
-
bf.
|
31
|
-
self.
|
32
|
-
self.
|
33
|
-
self.
|
34
|
-
self.
|
35
|
-
self.hud_entities: OrderedDict[bf.Entity, None] = OrderedDict()
|
36
|
-
self.actions: bf.ActionContainer = bf.ActionContainer()
|
37
|
-
self.early_actions: bf.ActionContainer = bf.ActionContainer()
|
38
|
-
self.camera: bf.Camera = bf.Camera(convert_alpha=world_convert_alpha)
|
39
|
-
self.hud_camera: bf.Camera = bf.Camera(convert_alpha=hud_convert_alpha)
|
40
|
-
self.should_sort :bool = True
|
41
|
-
self.root: bf.Root = bf.Root(self.hud_camera)
|
42
|
-
self.root.rect.center = self.hud_camera.get_center()
|
43
|
-
self.add_hud_entity(self.root)
|
14
|
+
super().__init__(name)
|
15
|
+
self.add_layer(bf.SceneLayer("world",True))
|
16
|
+
hud_layer = bf.SceneLayer("hud",True)
|
17
|
+
self.add_layer(hud_layer)
|
18
|
+
self.root: bf.gui.Root = bf.gui.Root(hud_layer.camera)
|
19
|
+
self.root.rect.center = hud_layer.camera.get_center()
|
20
|
+
self.add("hud",self.root)
|
44
21
|
self.entities_to_remove = []
|
45
22
|
self.entities_to_add = []
|
46
23
|
|
47
|
-
|
48
|
-
def __str__(self)->str:
|
49
|
-
return f"Scene({self.name})"
|
50
|
-
|
51
|
-
def get_world_entity_count(self) -> int:
|
52
|
-
return len(self.world_entities)
|
53
|
-
|
54
|
-
def get_hud_entity_count(self) -> int:
|
55
|
-
n = 0
|
56
|
-
|
57
|
-
def adder(e):
|
58
|
-
nonlocal n
|
59
|
-
n += len(e.children)
|
60
|
-
|
61
|
-
self.root.visit(adder)
|
62
|
-
|
63
|
-
return len(self.hud_entities) + n
|
64
|
-
|
65
|
-
def set_scene_index(self, index: int):
|
66
|
-
"""Set the scene index."""
|
67
|
-
self.scene_index = index
|
68
|
-
|
69
|
-
def get_scene_index(self) -> int:
|
70
|
-
"""Get the scene index."""
|
71
|
-
return self.scene_index
|
72
|
-
|
73
|
-
def do_when_added(self):
|
74
|
-
pass
|
75
|
-
|
76
|
-
def set_clear_color(self, color: pygame.Color | tuple):
|
77
|
-
"""Set the clear color for the camera."""
|
78
|
-
self.camera.set_clear_color(color)
|
79
|
-
|
80
|
-
def set_manager(self, manager_link: Manager):
|
81
|
-
"""Set the manager link for the scene."""
|
82
|
-
self.manager = manager_link
|
83
|
-
self.manager.update_scene_states()
|
84
|
-
|
85
|
-
def set_visible(self, value: bool):
|
86
|
-
"""Set the visibility of the scene."""
|
87
|
-
self.visible = value
|
88
|
-
if self.manager:
|
89
|
-
self.manager.update_scene_states()
|
90
|
-
|
91
|
-
def set_active(self, value):
|
92
|
-
"""Set the activity of the scene."""
|
93
|
-
self.active = value
|
94
|
-
if self.manager:
|
95
|
-
self.manager.update_scene_states()
|
96
|
-
|
97
|
-
def is_active(self) -> bool:
|
98
|
-
"""Check if the scene is active."""
|
99
|
-
return self.active
|
100
|
-
|
101
|
-
def is_visible(self) -> bool:
|
102
|
-
"""Check if the scene is visible."""
|
103
|
-
return self.visible
|
104
|
-
|
105
|
-
def get_name(self) -> str:
|
106
|
-
"""Get the name of the scene."""
|
107
|
-
return self.name
|
108
|
-
|
109
|
-
def add_world_entity(self, *entities: bf.Entity):
|
110
|
-
"""Add world entities to the scene."""
|
111
|
-
change = False
|
112
|
-
for e in entities:
|
113
|
-
if e not in self.world_entities and e not in self.entities_to_add:
|
114
|
-
change = True
|
115
|
-
# self.world_entities[e] = None
|
116
|
-
self.entities_to_add.append(e)
|
117
|
-
e.set_parent_scene(self)
|
118
|
-
# self.sort_entities()
|
119
|
-
return change
|
120
|
-
|
121
|
-
# Updated remove_world_entity method to add entities to the removal list
|
122
|
-
def remove_world_entity(self, *entities: bf.Entity):
|
123
|
-
"""Mark world entities for removal from the scene."""
|
124
|
-
change = False
|
125
|
-
for e in entities:
|
126
|
-
if e in self.world_entities:
|
127
|
-
change = True
|
128
|
-
self.entities_to_remove.append(e)
|
129
|
-
e.set_parent_scene(None)
|
130
|
-
return change
|
131
|
-
|
132
|
-
def add_hud_entity(self, *entities: bf.Entity):
|
133
|
-
"""Add HUD entities to the scene."""
|
134
|
-
for e in entities:
|
135
|
-
if e not in self.hud_entities:
|
136
|
-
self.hud_entities[e] = None
|
137
|
-
e.set_parent_scene(self)
|
138
|
-
self.sort_entities()
|
139
|
-
return True
|
140
|
-
|
141
|
-
def remove_hud_entity(self, *entities: bf.Entity):
|
142
|
-
"""Remove HUD entities from the scene."""
|
143
|
-
for e in entities:
|
144
|
-
if e in self.hud_entities:
|
145
|
-
e.set_parent_scene(None)
|
146
|
-
self.hud_entities.pop(e)
|
147
|
-
|
148
|
-
def add_actions(self, *action):
|
149
|
-
"""Add actions to the scene."""
|
150
|
-
self.actions.add_actions(*action)
|
151
|
-
|
152
|
-
def add_early_actions(self, *action):
|
153
|
-
"""Add actions to the scene."""
|
154
|
-
self.early_actions.add_actions(*action)
|
155
|
-
|
156
|
-
def get_by_tags(self, *tags):
|
157
|
-
"""Get entities by their tags."""
|
158
|
-
res = [
|
159
|
-
entity
|
160
|
-
for entity in itertools.chain(
|
161
|
-
self.world_entities.keys(), self.hud_entities.keys()
|
162
|
-
)
|
163
|
-
if any(entity.has_tags(t) for t in tags)
|
164
|
-
]
|
165
|
-
res.extend(list(self.root.get_by_tags(*tags)))
|
166
|
-
return res
|
167
|
-
|
168
|
-
def get_by_uid(self, uid) -> bf.Entity | None:
|
169
|
-
"""Get an entity by its unique identifier."""
|
170
|
-
res = self._find_entity_by_uid(
|
171
|
-
uid, itertools.chain(self.world_entities.keys(), self.hud_entities.keys())
|
172
|
-
)
|
173
|
-
if res is None:
|
174
|
-
res = self._recursive_search_by_uid(uid, self.root)
|
175
|
-
return res
|
176
|
-
|
177
|
-
def _find_entity_by_uid(self, uid, entities) -> bf.Entity | None:
|
178
|
-
"""Search for entity by uid in a list of entities."""
|
179
|
-
for entity in entities:
|
180
|
-
if entity.uid == uid:
|
181
|
-
return entity
|
182
|
-
return None
|
183
|
-
|
184
|
-
def _recursive_search_by_uid(self, uid, widget) -> bf.Entity | None:
|
185
|
-
"""Recursively search for entity by uid in the widget's children."""
|
186
|
-
if widget.uid == uid:
|
187
|
-
return widget
|
188
|
-
|
189
|
-
for child in widget.children:
|
190
|
-
res = self._recursive_search_by_uid(uid, child)
|
191
|
-
if res is not None:
|
192
|
-
return res
|
193
|
-
|
194
|
-
return None
|
195
|
-
|
196
|
-
def process_event(self, event: pygame.Event):
|
197
|
-
"""
|
198
|
-
Propagates event while it is not consumed.
|
199
|
-
In order :
|
200
|
-
-do_early_handle_event()
|
201
|
-
-scene early_actions
|
202
|
-
-propagate to scene entities (hud then world)
|
203
|
-
-do_handle_event()
|
204
|
-
-scene actions
|
205
|
-
at each step, if the event is consumed the propagation stops
|
206
|
-
"""
|
207
|
-
if event.consumed:
|
208
|
-
return
|
209
|
-
self.do_early_handle_event(event)
|
210
|
-
if event.consumed:
|
211
|
-
return
|
212
|
-
self.early_actions.process_event(event)
|
213
|
-
if event.consumed:
|
214
|
-
return
|
215
|
-
for entity in itertools.chain(
|
216
|
-
self.hud_entities.keys(), self.world_entities.keys()
|
217
|
-
):
|
218
|
-
entity.process_event(event)
|
219
|
-
if event.consumed:
|
220
|
-
return
|
221
|
-
self.do_handle_event(event)
|
222
|
-
if event.consumed:
|
223
|
-
return
|
224
|
-
self.actions.process_event(event)
|
225
|
-
|
226
|
-
# called before process event
|
227
|
-
def do_early_handle_event(self, event: pygame.Event):
|
228
|
-
"""Called early in event propagation"""
|
229
|
-
pass
|
230
|
-
|
231
|
-
def do_handle_event(self, event: pygame.Event):
|
232
|
-
"""called inside process_event but before resetting the scene's action container and propagating event to child entities of the scene"""
|
233
|
-
pass
|
234
|
-
|
235
|
-
def update(self, dt):
|
236
|
-
"""Update the scene. Do NOT override"""
|
237
|
-
if self.should_sort:
|
238
|
-
self._sort_entities_internal()
|
239
|
-
|
240
|
-
for entity in itertools.chain(
|
241
|
-
self.hud_entities.keys(), self.world_entities.keys()
|
242
|
-
):
|
243
|
-
entity.update(dt)
|
244
|
-
|
245
|
-
self.do_update(dt)
|
246
|
-
self.camera.update(dt)
|
247
|
-
self.hud_camera.update(dt)
|
248
|
-
self.actions.reset()
|
249
|
-
self.early_actions.reset()
|
250
|
-
|
251
|
-
if self.entities_to_add:
|
252
|
-
for e in self.entities_to_add:
|
253
|
-
self.world_entities[e] = None
|
254
|
-
self.entities_to_add.clear()
|
255
|
-
|
256
|
-
# Remove marked entities after updating
|
257
|
-
if self.entities_to_remove:
|
258
|
-
for e in self.entities_to_remove:
|
259
|
-
self.world_entities.pop(e, None)
|
260
|
-
self.entities_to_remove.clear()
|
261
|
-
|
262
|
-
def do_update(self, dt):
|
263
|
-
"""Specific update within the scene."""
|
264
|
-
pass
|
265
|
-
|
266
|
-
def debug_entity(self, entity: bf.Entity, camera: bf.Camera):
|
267
|
-
def draw_rect(data):
|
268
|
-
if data is None:
|
269
|
-
return
|
270
|
-
if isinstance(data, pygame.FRect) or isinstance(data, pygame.Rect):
|
271
|
-
rect = data
|
272
|
-
color = entity.debug_color
|
273
|
-
else:
|
274
|
-
rect = data[0]
|
275
|
-
color = data[1]
|
276
|
-
pygame.draw.rect(camera.surface, color, camera.world_to_screen(rect), 1)
|
277
|
-
|
278
|
-
[draw_rect(data) for data in entity.get_debug_outlines()]
|
279
|
-
|
280
|
-
def sort_entities(self) -> None:
|
281
|
-
self.should_sort = True
|
282
|
-
|
283
|
-
def _sort_entities_internal(self):
|
284
|
-
"""Sort entities within the scene based on their rendering order."""
|
285
|
-
self.world_entities = OrderedDict(
|
286
|
-
sorted(self.world_entities.items(), key=lambda e: e[0].render_order)
|
287
|
-
)
|
288
|
-
self.hud_entities = OrderedDict(
|
289
|
-
sorted(self.hud_entities.items(), key=lambda e: e[0].render_order)
|
290
|
-
)
|
291
|
-
self.should_sort = False
|
292
|
-
|
293
|
-
def draw(self, surface: pygame.Surface):
|
294
|
-
self.camera.clear()
|
295
|
-
self.hud_camera.clear()
|
296
|
-
|
297
|
-
# Draw all world entities
|
298
|
-
self._draw_camera(self.camera, self.world_entities.keys())
|
299
|
-
# Draw all HUD entities
|
300
|
-
self._draw_camera(self.hud_camera, self.hud_entities.keys())
|
301
|
-
|
302
|
-
self.do_early_draw(surface)
|
303
|
-
self.camera.draw(surface)
|
304
|
-
self.do_post_world_draw(surface)
|
305
|
-
self.hud_camera.draw(surface)
|
306
|
-
self.do_final_draw(surface)
|
307
|
-
|
308
|
-
def _draw_camera(self, camera: bf.Camera, entity_list):
|
309
|
-
_ = [entity.draw(camera) for entity in entity_list]
|
310
|
-
debugMode = bf.ResourceManager().get_sharedVar("debug_mode")
|
311
|
-
# Draw outlines for world entities if required
|
312
|
-
if debugMode == bf.debugMode.OUTLINES:
|
313
|
-
[self.debug_entity(e, camera) for e in entity_list]
|
314
|
-
|
315
|
-
def do_early_draw(self, surface: pygame.Surface):
|
316
|
-
pass
|
317
|
-
|
318
|
-
def do_post_world_draw(self, surface: pygame.Surface):
|
319
|
-
pass
|
320
|
-
|
321
|
-
def do_final_draw(self, surface: pygame.Surface):
|
322
|
-
pass
|
323
|
-
|
324
24
|
def on_enter(self):
|
325
|
-
self.set_active(True)
|
326
|
-
self.set_visible(True)
|
327
25
|
self.root.clear_hovered()
|
328
26
|
self.root.build()
|
329
|
-
|
330
|
-
self.do_on_enter()
|
27
|
+
super().on_enter()
|
331
28
|
|
332
29
|
def on_exit(self):
|
333
30
|
self.root.clear_hovered()
|
334
|
-
|
335
|
-
self.set_visible(False)
|
336
|
-
self.actions.hard_reset()
|
337
|
-
self.early_actions.hard_reset()
|
338
|
-
bf.TimeManager().deactivate_register(self.name)
|
339
|
-
self.do_on_exit()
|
340
|
-
|
341
|
-
def do_on_enter(self) -> None:
|
342
|
-
pass
|
343
|
-
|
344
|
-
def do_on_exit(self) -> None:
|
345
|
-
pass
|
346
|
-
|
347
|
-
def do_on_enter_early(self) -> None:
|
348
|
-
pass
|
349
|
-
|
350
|
-
def do_on_exit_early(self) -> None:
|
351
|
-
pass
|
31
|
+
super().on_exit()
|