batframework 0.1.13__tar.gz → 1.0.1__tar.gz
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-1.0.1/LICENCE +21 -0
- {batframework-0.1.13 → batframework-1.0.1}/PKG-INFO +3 -2
- {batframework-0.1.13 → batframework-1.0.1}/pyproject.toml +2 -2
- batframework-1.0.1/src/batFramework/__init__.py +62 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/action.py +42 -20
- batframework-1.0.1/src/batFramework/actionContainer.py +77 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/animatedSprite.py +26 -20
- batframework-1.0.1/src/batFramework/camera.py +253 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/constants.py +26 -51
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/cutscene.py +15 -15
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/cutsceneBlocks.py +11 -9
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/dynamicEntity.py +7 -6
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/easing.py +28 -23
- batframework-1.0.1/src/batFramework/entity.py +160 -0
- batframework-1.0.1/src/batFramework/enums.py +14 -0
- batframework-1.0.1/src/batFramework/fontManager.py +57 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/gui/__init__.py +2 -2
- batframework-1.0.1/src/batFramework/gui/button.py +138 -0
- batframework-1.0.1/src/batFramework/gui/constraints.py +262 -0
- batframework-1.0.1/src/batFramework/gui/container.py +60 -0
- batframework-1.0.1/src/batFramework/gui/debugger.py +97 -0
- batframework-1.0.1/src/batFramework/gui/frame.py +25 -0
- batframework-1.0.1/src/batFramework/gui/image.py +43 -0
- batframework-1.0.1/src/batFramework/gui/indicator.py +46 -0
- batframework-1.0.1/src/batFramework/gui/interactiveWidget.py +23 -0
- batframework-1.0.1/src/batFramework/gui/label.py +152 -0
- batframework-1.0.1/src/batFramework/gui/layout.py +96 -0
- batframework-1.0.1/src/batFramework/gui/root.py +78 -0
- batframework-1.0.1/src/batFramework/gui/shape.py +79 -0
- batframework-1.0.1/src/batFramework/gui/slider.py +5 -0
- batframework-1.0.1/src/batFramework/gui/toggle.py +66 -0
- batframework-1.0.1/src/batFramework/gui/widget.py +341 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/manager.py +18 -13
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/particles.py +16 -13
- batframework-1.0.1/src/batFramework/resourceManager.py +55 -0
- batframework-1.0.1/src/batFramework/scene.py +309 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/sceneManager.py +21 -16
- batframework-1.0.1/src/batFramework/sprite.py +31 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/stateMachine.py +1 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/tileset.py +7 -9
- batframework-1.0.1/src/batFramework/time.py +86 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/transition.py +20 -12
- batframework-1.0.1/src/batFramework/utils.py +61 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batframework.egg-info/PKG-INFO +3 -2
- {batframework-0.1.13 → batframework-1.0.1}/src/batframework.egg-info/SOURCES.txt +6 -1
- batframework-0.1.13/src/batFramework/__init__.py +0 -67
- batframework-0.1.13/src/batFramework/actionContainer.py +0 -38
- batframework-0.1.13/src/batFramework/camera.py +0 -123
- batframework-0.1.13/src/batFramework/debugger.py +0 -48
- batframework-0.1.13/src/batFramework/entity.py +0 -122
- batframework-0.1.13/src/batFramework/gui/button.py +0 -87
- batframework-0.1.13/src/batFramework/gui/constraints.py +0 -229
- batframework-0.1.13/src/batFramework/gui/container.py +0 -61
- batframework-0.1.13/src/batFramework/gui/debugger.py +0 -47
- batframework-0.1.13/src/batFramework/gui/frame.py +0 -25
- batframework-0.1.13/src/batFramework/gui/image.py +0 -23
- batframework-0.1.13/src/batFramework/gui/indicator.py +0 -42
- batframework-0.1.13/src/batFramework/gui/interactiveWidget.py +0 -22
- batframework-0.1.13/src/batFramework/gui/label.py +0 -148
- batframework-0.1.13/src/batFramework/gui/layout.py +0 -93
- batframework-0.1.13/src/batFramework/gui/root.py +0 -65
- batframework-0.1.13/src/batFramework/gui/shape.py +0 -86
- batframework-0.1.13/src/batFramework/gui/toggle.py +0 -62
- batframework-0.1.13/src/batFramework/gui/widget.py +0 -321
- batframework-0.1.13/src/batFramework/scene.py +0 -251
- batframework-0.1.13/src/batFramework/time.py +0 -75
- batframework-0.1.13/src/batFramework/utils.py +0 -124
- {batframework-0.1.13 → batframework-1.0.1}/README.md +0 -0
- {batframework-0.1.13 → batframework-1.0.1}/setup.cfg +0 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/audioManager.py +0 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/transitionManager.py +0 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batFramework/triggerZone.py +0 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batframework.egg-info/dependency_links.txt +0 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batframework.egg-info/requires.txt +0 -0
- {batframework-0.1.13 → batframework-1.0.1}/src/batframework.egg-info/top_level.txt +0 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) [2023] [TURAN BATURAY]
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
@@ -1,14 +1,15 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: batframework
|
3
|
-
Version: 0.1
|
3
|
+
Version: 1.0.1
|
4
4
|
Summary: Pygame framework for making games easier.
|
5
5
|
Author-email: Turan Baturay <baturayturan@gmail.com>
|
6
6
|
Project-URL: Homepage, https://github.com/TuranBaturay/batFramework
|
7
7
|
Classifier: Programming Language :: Python :: 3
|
8
8
|
Classifier: License :: OSI Approved :: MIT License
|
9
9
|
Classifier: Operating System :: OS Independent
|
10
|
-
Requires-Python: >=3.
|
10
|
+
Requires-Python: >=3.11
|
11
11
|
Description-Content-Type: text/markdown
|
12
|
+
License-File: LICENCE
|
12
13
|
Requires-Dist: pygame-ce
|
13
14
|
|
14
15
|
# batFramework & gamejam Project
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "batframework"
|
7
|
-
version = "0.1
|
7
|
+
version = "1.0.1"
|
8
8
|
authors = [
|
9
9
|
{ name="Turan Baturay", email="baturayturan@gmail.com" }
|
10
10
|
]
|
@@ -15,7 +15,7 @@ classifiers = [
|
|
15
15
|
"License :: OSI Approved :: MIT License",
|
16
16
|
"Operating System :: OS Independent",
|
17
17
|
]
|
18
|
-
requires-python = ">=3.
|
18
|
+
requires-python = ">=3.11"
|
19
19
|
dependencies=[
|
20
20
|
"pygame-ce"
|
21
21
|
]
|
@@ -0,0 +1,62 @@
|
|
1
|
+
import pygame
|
2
|
+
import batFramework as bf
|
3
|
+
import sys
|
4
|
+
from .constants import Constants as const
|
5
|
+
from .constants import Colors as color
|
6
|
+
from .utils import Singleton
|
7
|
+
from .enums import *
|
8
|
+
from .resourceManager import ResourceManager
|
9
|
+
from .fontManager import FontManager
|
10
|
+
# if const.BF_INITIALIZED:
|
11
|
+
from .utils import Utils as utils
|
12
|
+
from .tileset import Tileset
|
13
|
+
from .time import TimeManager, Timer
|
14
|
+
from .cutscene import Cutscene, CutsceneManager
|
15
|
+
from .cutsceneBlocks import *
|
16
|
+
from .easing import Easing, EasingAnimation
|
17
|
+
from .audioManager import AudioManager
|
18
|
+
# import batFramework.transition as transition
|
19
|
+
from .action import Action
|
20
|
+
from .actionContainer import *
|
21
|
+
from .camera import Camera
|
22
|
+
from .entity import Entity
|
23
|
+
from .dynamicEntity import DynamicEntity
|
24
|
+
from .sprite import Sprite
|
25
|
+
from .animatedSprite import AnimatedSprite, AnimState
|
26
|
+
from .stateMachine import State, StateMachine
|
27
|
+
# from .debugger import Debugger
|
28
|
+
from .scene import Scene
|
29
|
+
from .gui import *
|
30
|
+
from .sceneManager import SceneManager
|
31
|
+
from .manager import Manager
|
32
|
+
|
33
|
+
|
34
|
+
def init_screen(resolution: tuple[int, int], flags: int = 0, vsync: int = 0):
|
35
|
+
const.RESOLUTION = resolution
|
36
|
+
const.FLAGS = flags
|
37
|
+
const.VSYNC = vsync
|
38
|
+
const.SCREEN = pygame.display.set_mode(
|
39
|
+
const.RESOLUTION,const.FLAGS, vsync=const.VSYNC
|
40
|
+
)
|
41
|
+
print(
|
42
|
+
f"Window : {resolution[0]}x{resolution[1]} [vsync:{pygame.display.is_vsync()}]"
|
43
|
+
)
|
44
|
+
|
45
|
+
def init(
|
46
|
+
resolution: tuple[int, int],
|
47
|
+
flags: int = 0,
|
48
|
+
vsync: int = 0,
|
49
|
+
default_text_size=None,
|
50
|
+
default_font=None,
|
51
|
+
resource_path: str | None = None,
|
52
|
+
window_title: str = "BatFramework Project",
|
53
|
+
fps_limit: int = 0):
|
54
|
+
pygame.display.set_caption(window_title)
|
55
|
+
init_screen(resolution,flags,vsync)
|
56
|
+
|
57
|
+
ResourceManager().set_resource_path(resource_path if resource_path is not None else ".")
|
58
|
+
ResourceManager().load_dir(ResourceManager().RESOURCE_PATH)
|
59
|
+
if default_text_size is not None : FontManager().set_default_text_size(default_text_size)
|
60
|
+
FontManager().init_font(default_font)
|
61
|
+
const.BF_INITIALIZED = True
|
62
|
+
const.set_fps_limit(fps_limit)
|
@@ -12,20 +12,21 @@ class Action:
|
|
12
12
|
Args:
|
13
13
|
name (str): The name of the action.
|
14
14
|
"""
|
15
|
-
self._name = name
|
16
|
-
self._active = False
|
17
|
-
self._type = ActionType.INSTANTANEOUS
|
18
|
-
self._key_control = set()
|
19
|
-
self._mouse_control = set()
|
20
|
-
self._gamepad_button_control = set()
|
21
|
-
self._gamepad_axis_control = set()
|
15
|
+
self._name :str= name
|
16
|
+
self._active :bool= False
|
17
|
+
self._type :ActionType = ActionType.INSTANTANEOUS
|
18
|
+
self._key_control : set= set()
|
19
|
+
self._mouse_control :set = set()
|
20
|
+
self._gamepad_button_control :set = set()
|
21
|
+
self._gamepad_axis_control :set = set()
|
22
22
|
self._holding = set()
|
23
23
|
self._unique = True
|
24
|
-
self.data
|
24
|
+
self.data: Any = None
|
25
25
|
|
26
26
|
def set_unique(self, val: bool) -> None:
|
27
27
|
"""
|
28
28
|
Set whether this action is unique (exclusive).
|
29
|
+
When in an action Container, unique actions -when active - break the propagation of their event to other actions.
|
29
30
|
|
30
31
|
Args:
|
31
32
|
val (bool): True if the action is unique, False otherwise.
|
@@ -51,7 +52,7 @@ class Action:
|
|
51
52
|
self._active = value
|
52
53
|
self._holding = set()
|
53
54
|
|
54
|
-
def add_key_control(self, *keys) ->
|
55
|
+
def add_key_control(self, *keys) -> "Action":
|
55
56
|
"""
|
56
57
|
Add key controls to the action.
|
57
58
|
|
@@ -64,7 +65,26 @@ class Action:
|
|
64
65
|
self._key_control.update(keys)
|
65
66
|
return self
|
66
67
|
|
67
|
-
def
|
68
|
+
def remove_key_control(self, *keys:int) -> "Action":
|
69
|
+
"""
|
70
|
+
Remove key controls to the action.
|
71
|
+
|
72
|
+
Args:
|
73
|
+
*keys (int): Key codes to control this action.
|
74
|
+
|
75
|
+
Returns:
|
76
|
+
Action: The updated Action object for method chaining.
|
77
|
+
"""
|
78
|
+
self._key_control = self._key_control - set(keys)
|
79
|
+
return self
|
80
|
+
|
81
|
+
def replace_key_control(self, key, new_key) -> "Action":
|
82
|
+
if not key in self._key_control : return self
|
83
|
+
self.remove_key_control(key)
|
84
|
+
self.add_key_control(new_key)
|
85
|
+
return self
|
86
|
+
|
87
|
+
def add_mouse_control(self, *mouse_buttons:int) -> "Action":
|
68
88
|
"""
|
69
89
|
Add mouse control to the action.
|
70
90
|
|
@@ -86,7 +106,7 @@ class Action:
|
|
86
106
|
"""
|
87
107
|
return self._name
|
88
108
|
|
89
|
-
def set_continuous(self) ->
|
109
|
+
def set_continuous(self) -> "Action":
|
90
110
|
"""
|
91
111
|
Set the action type to continuous.
|
92
112
|
|
@@ -106,7 +126,7 @@ class Action:
|
|
106
126
|
"""
|
107
127
|
return self._type == ActionType.CONTINUOUS
|
108
128
|
|
109
|
-
def set_instantaneous(self) ->
|
129
|
+
def set_instantaneous(self) -> "Action":
|
110
130
|
"""
|
111
131
|
Set the action type to instantaneous.
|
112
132
|
|
@@ -126,7 +146,7 @@ class Action:
|
|
126
146
|
"""
|
127
147
|
return self._type == ActionType.INSTANTANEOUS
|
128
148
|
|
129
|
-
def set_holding(self) ->
|
149
|
+
def set_holding(self) -> "Action":
|
130
150
|
"""
|
131
151
|
Set the action type to holding.
|
132
152
|
|
@@ -145,9 +165,14 @@ class Action:
|
|
145
165
|
"""
|
146
166
|
return self._type == ActionType.HOLDING
|
147
167
|
|
148
|
-
def process_update(self,event:pygame.Event)->None:
|
149
|
-
if
|
150
|
-
self.
|
168
|
+
def process_update(self, event: pygame.Event) -> None:
|
169
|
+
if (
|
170
|
+
self.is_active()
|
171
|
+
and event.type == pygame.MOUSEMOTION
|
172
|
+
and self.is_holding_type()
|
173
|
+
and pygame.MOUSEMOTION in self._mouse_control
|
174
|
+
):
|
175
|
+
self.data = {"pos": event.pos, "rel": event.rel}
|
151
176
|
|
152
177
|
def process_activate(self, event: pygame.event.Event) -> bool:
|
153
178
|
"""
|
@@ -205,10 +230,7 @@ class Action:
|
|
205
230
|
if not self._holding:
|
206
231
|
self._active = False
|
207
232
|
return True
|
208
|
-
elif
|
209
|
-
event.type == pygame.MOUSEMOTION
|
210
|
-
and event.type in self._mouse_control
|
211
|
-
):
|
233
|
+
elif event.type == pygame.MOUSEMOTION and event.type in self._mouse_control:
|
212
234
|
self.value = None
|
213
235
|
if event.type in self._holding:
|
214
236
|
self._holding.remove(event.type)
|
@@ -0,0 +1,77 @@
|
|
1
|
+
import batFramework as bf
|
2
|
+
import pygame
|
3
|
+
|
4
|
+
|
5
|
+
class ActionContainer:
|
6
|
+
def __init__(self, *actions: list[bf.Action]) -> None:
|
7
|
+
self._actions: dict[str, bf.Action] = {}
|
8
|
+
if actions:
|
9
|
+
self.add_action(*actions)
|
10
|
+
|
11
|
+
def clear(self):
|
12
|
+
self._actions = {}
|
13
|
+
|
14
|
+
def add_action(self, *actions: bf.Action):
|
15
|
+
for action in actions:
|
16
|
+
self._actions[action.get_name()] = action
|
17
|
+
|
18
|
+
def get(self, name: str) -> bf.Action:
|
19
|
+
return self._actions.get(name)
|
20
|
+
|
21
|
+
def has_action(self, name: str):
|
22
|
+
return name in self._actions
|
23
|
+
|
24
|
+
def get_all(self) -> list[bf.Action]:
|
25
|
+
return self._actions
|
26
|
+
|
27
|
+
def is_active(self, *names: str) -> bool:
|
28
|
+
return all(
|
29
|
+
self._actions.get(name).is_active() if name in self._actions else False
|
30
|
+
for name in names
|
31
|
+
)
|
32
|
+
|
33
|
+
def process_event(self, event):
|
34
|
+
for action in self._actions.values():
|
35
|
+
a = action.process_event(event)
|
36
|
+
if a and action._unique:
|
37
|
+
break
|
38
|
+
|
39
|
+
def reset(self):
|
40
|
+
for action in self._actions.values():
|
41
|
+
action.reset()
|
42
|
+
|
43
|
+
def hard_reset(self):
|
44
|
+
for action in self._actions.values():
|
45
|
+
action.hard_reset()
|
46
|
+
|
47
|
+
|
48
|
+
class DirectionalKeyControls(ActionContainer):
|
49
|
+
def __init__(self):
|
50
|
+
super().__init__(
|
51
|
+
bf.Action("up").add_key_control(pygame.K_UP).set_holding(),
|
52
|
+
bf.Action("down").add_key_control(pygame.K_DOWN).set_holding(),
|
53
|
+
bf.Action("left").add_key_control(pygame.K_LEFT).set_holding(),
|
54
|
+
bf.Action("right").add_key_control(pygame.K_RIGHT).set_holding(),
|
55
|
+
)
|
56
|
+
|
57
|
+
|
58
|
+
class WASDControls(ActionContainer):
|
59
|
+
def __init__(self):
|
60
|
+
super().__init__(
|
61
|
+
bf.Action("up").add_key_control(pygame.K_w).set_holding(),
|
62
|
+
bf.Action("down").add_key_control(pygame.K_s).set_holding(),
|
63
|
+
bf.Action("left").add_key_control(pygame.K_a).set_holding(),
|
64
|
+
bf.Action("right").add_key_control(pygame.K_d).set_holding(),
|
65
|
+
)
|
66
|
+
|
67
|
+
|
68
|
+
class HybridControls(ActionContainer):
|
69
|
+
def __init__(self):
|
70
|
+
super().__init__(
|
71
|
+
bf.Action("up").add_key_control(pygame.K_UP, pygame.K_w).set_holding(),
|
72
|
+
bf.Action("down").add_key_control(pygame.K_DOWN, pygame.K_s).set_holding(),
|
73
|
+
bf.Action("left").add_key_control(pygame.K_LEFT, pygame.K_a).set_holding(),
|
74
|
+
bf.Action("right")
|
75
|
+
.add_key_control(pygame.K_RIGHT, pygame.K_r)
|
76
|
+
.set_holding(),
|
77
|
+
)
|
@@ -2,7 +2,6 @@ import batFramework as bf
|
|
2
2
|
import pygame
|
3
3
|
|
4
4
|
|
5
|
-
|
6
5
|
def search_index(target, lst):
|
7
6
|
cumulative_sum = 0
|
8
7
|
for index, value in enumerate(lst):
|
@@ -13,12 +12,14 @@ def search_index(target, lst):
|
|
13
12
|
|
14
13
|
|
15
14
|
class AnimState:
|
16
|
-
def __init__(
|
15
|
+
def __init__(
|
16
|
+
self, name: str, file, width, height, frame_length_list: list | int
|
17
|
+
) -> None:
|
17
18
|
self.frames: list[pygame.Surface] = bf.utils.img_slice(file, width, height)
|
18
19
|
self.frames_flipX: list[pygame.Surface] = bf.utils.img_slice(
|
19
20
|
file, width, height, True
|
20
21
|
)
|
21
|
-
self.name= name
|
22
|
+
self.name = name
|
22
23
|
self.frame_length_list = []
|
23
24
|
self.ffl_length = 0
|
24
25
|
self.set_frame_length_list(frame_length_list)
|
@@ -26,34 +27,33 @@ class AnimState:
|
|
26
27
|
def __repr__(self):
|
27
28
|
return f"AnimState({self.name})"
|
28
29
|
|
29
|
-
def get_frame_index(self, counter:float|int):
|
30
|
+
def get_frame_index(self, counter: float | int):
|
30
31
|
return search_index(int(counter % self.ffl_length), self.frame_length_list)
|
31
32
|
|
32
33
|
def get_frame(self, counter, flip):
|
33
34
|
i = self.get_frame_index(counter)
|
34
35
|
return self.frames_flipX[i] if flip else self.frames[i]
|
35
36
|
|
36
|
-
def set_frame_length_list(self,frame_length_list:list[int]|int):
|
37
|
-
if isinstance(frame_length_list,int):
|
37
|
+
def set_frame_length_list(self, frame_length_list: list[int] | int):
|
38
|
+
if isinstance(frame_length_list, int):
|
38
39
|
frame_length_list = [frame_length_list] * len(self.frames)
|
39
|
-
if len(frame_length_list) != len(self.frames)
|
40
|
+
if len(frame_length_list) != len(self.frames):
|
40
41
|
raise ValueError("frame_length_list should have values for all frames")
|
41
42
|
self.frame_length_list = frame_length_list
|
42
43
|
self.ffl_length = sum(self.frame_length_list)
|
43
|
-
|
44
|
+
|
44
45
|
|
45
46
|
class AnimatedSprite(bf.DynamicEntity):
|
46
47
|
def __init__(self, size=None) -> None:
|
47
48
|
super().__init__(size, no_surface=True)
|
48
49
|
self.float_counter = 0
|
49
50
|
self.animStates: dict[str, AnimState] = {}
|
50
|
-
self.current_animState
|
51
|
+
self.current_animState: str = ""
|
51
52
|
self.flipX = False
|
52
53
|
self._locked = False
|
53
54
|
|
54
|
-
def set_counter(self,value:float):
|
55
|
+
def set_counter(self, value: float):
|
55
56
|
self.float_counter = value
|
56
|
-
|
57
57
|
|
58
58
|
def lock_animState(self):
|
59
59
|
self._locked = True
|
@@ -64,20 +64,25 @@ class AnimatedSprite(bf.DynamicEntity):
|
|
64
64
|
def set_flipX(self, value):
|
65
65
|
self.flipX = value
|
66
66
|
|
67
|
-
def remove_animState(self, name:str):
|
68
|
-
if not name in self.animStates
|
69
|
-
|
70
|
-
|
67
|
+
def remove_animState(self, name: str):
|
68
|
+
if not name in self.animStates:
|
69
|
+
return
|
70
|
+
self.animStates.pop(name)
|
71
|
+
if self.current_animState == name:
|
72
|
+
self.current_animState = (
|
73
|
+
list(self.animStates.keys())[0] if self.animStates else ""
|
74
|
+
)
|
71
75
|
|
72
76
|
def add_animState(
|
73
77
|
self, name: str, file: str, size: tuple[int, int], frame_length_list: list[int]
|
74
78
|
):
|
75
79
|
if name in self.animStates:
|
76
80
|
return
|
77
|
-
self.animStates[name] = AnimState(name,file, *size, frame_length_list)
|
78
|
-
if len(self.animStates) == 1
|
81
|
+
self.animStates[name] = AnimState(name, file, *size, frame_length_list)
|
82
|
+
if len(self.animStates) == 1:
|
83
|
+
self.set_animState(name)
|
79
84
|
|
80
|
-
def set_animState(self, state:str, reset_counter=True, lock=False):
|
85
|
+
def set_animState(self, state: str, reset_counter=True, lock=False):
|
81
86
|
if state not in self.animStates or self._locked:
|
82
87
|
return False
|
83
88
|
self.current_animState = state
|
@@ -95,7 +100,7 @@ class AnimatedSprite(bf.DynamicEntity):
|
|
95
100
|
return True
|
96
101
|
|
97
102
|
def get_state(self):
|
98
|
-
return self.animStates.get(self.current_animState,None)
|
103
|
+
return self.animStates.get(self.current_animState, None)
|
99
104
|
|
100
105
|
def get_frame_index(self):
|
101
106
|
return self.animStates[self.current_animState].get_frame_index(
|
@@ -103,7 +108,8 @@ class AnimatedSprite(bf.DynamicEntity):
|
|
103
108
|
)
|
104
109
|
|
105
110
|
def update(self, dt: float):
|
106
|
-
if not self.animStates
|
111
|
+
if not self.animStates:
|
112
|
+
return
|
107
113
|
self.float_counter += 60 * dt
|
108
114
|
if self.float_counter > self.get_state().ffl_length:
|
109
115
|
self.float_counter = 0
|
@@ -0,0 +1,253 @@
|
|
1
|
+
import pygame
|
2
|
+
from pygame.math import Vector2
|
3
|
+
import math
|
4
|
+
import batFramework as bf
|
5
|
+
|
6
|
+
|
7
|
+
class Camera:
|
8
|
+
_transform_cache = {} # Cache for transformed surfaces
|
9
|
+
|
10
|
+
def __init__(self, flags=0, size: tuple[int,int] | None = None,convert_alpha:bool=False) -> None:
|
11
|
+
"""
|
12
|
+
Initialize the Camera object.
|
13
|
+
|
14
|
+
Args:
|
15
|
+
flags (int): Flags for camera initialization.
|
16
|
+
size (tuple): Optional size for camera (defaults to window size)
|
17
|
+
"""
|
18
|
+
# Initialize camera attributes
|
19
|
+
size = size if size else bf.const.RESOLUTION
|
20
|
+
self.rect = pygame.Rect(0, 0, *size)
|
21
|
+
self.flags: int = flags
|
22
|
+
self.blit_special_flags: int = pygame.BLEND_ALPHA_SDL2
|
23
|
+
self._clear_color: pygame.Color = pygame.Color(0, 0, 0, 0)
|
24
|
+
self.zoom_factor = 1
|
25
|
+
self.cached_surfaces: dict[float, pygame.Surface] = {}
|
26
|
+
self.surface: pygame.Surface = pygame.Surface((0, 0))
|
27
|
+
if convert_alpha :
|
28
|
+
self.surface = self.surface.convert_alpha()
|
29
|
+
else:
|
30
|
+
self.surface = self.surface.convert()
|
31
|
+
self.follow_point_func = None
|
32
|
+
self.max_zoom = 2
|
33
|
+
self.min_zoom = 0.1
|
34
|
+
self.zoom(1)
|
35
|
+
|
36
|
+
def set_clear_color(self, color: pygame.Color | tuple | str) -> "Camera":
|
37
|
+
"""
|
38
|
+
Set the clear color for the camera surface.
|
39
|
+
|
40
|
+
Args:
|
41
|
+
color (pygame.Color | tuple): Color to set as the clear color.
|
42
|
+
|
43
|
+
Returns:
|
44
|
+
Camera: Returns the Camera object.
|
45
|
+
"""
|
46
|
+
if not isinstance(color, pygame.Color):
|
47
|
+
color = pygame.Color(color)
|
48
|
+
self._clear_color = color
|
49
|
+
return self
|
50
|
+
|
51
|
+
def set_max_zoom(self, value: float) -> "Camera":
|
52
|
+
"""
|
53
|
+
Set the maximum zoom value for the camera.
|
54
|
+
|
55
|
+
Args:
|
56
|
+
value (float): Maximum zoom value.
|
57
|
+
|
58
|
+
Returns:
|
59
|
+
Camera: Returns the Camera object.
|
60
|
+
"""
|
61
|
+
self.max_zoom = value
|
62
|
+
return self
|
63
|
+
|
64
|
+
def set_min_zoom(self, value: float) -> "Camera":
|
65
|
+
"""
|
66
|
+
Set the minimum zoom value for the camera.
|
67
|
+
|
68
|
+
Args:
|
69
|
+
value (float): Minimum zoom value.
|
70
|
+
|
71
|
+
Returns:
|
72
|
+
Camera: Returns the Camera object.
|
73
|
+
"""
|
74
|
+
self.min_zoom = value
|
75
|
+
return self
|
76
|
+
|
77
|
+
def clear(self) -> None:
|
78
|
+
"""
|
79
|
+
Clear the camera surface with the set clear color.
|
80
|
+
"""
|
81
|
+
self.surface.fill(self._clear_color)
|
82
|
+
|
83
|
+
def get_center(self) -> tuple[float,float]:
|
84
|
+
"""
|
85
|
+
Get the center of the camera's view.
|
86
|
+
|
87
|
+
Returns:
|
88
|
+
Vector2: Returns the center coordinates.
|
89
|
+
"""
|
90
|
+
return self.rect.center
|
91
|
+
|
92
|
+
def move(self, x, y) -> "Camera":
|
93
|
+
"""
|
94
|
+
Moves the camera rect by the given coordinates.
|
95
|
+
|
96
|
+
Args:
|
97
|
+
x: X-coordinate to move.
|
98
|
+
y: Y-coordinate to move.
|
99
|
+
|
100
|
+
Returns:
|
101
|
+
Camera: Returns the Camera object.
|
102
|
+
"""
|
103
|
+
self.rect.topleft += Vector2(x, y)
|
104
|
+
return self
|
105
|
+
|
106
|
+
def set_position(self, x, y) -> "Camera":
|
107
|
+
"""
|
108
|
+
Set the camera rect top-left position.
|
109
|
+
|
110
|
+
Args:
|
111
|
+
x: X-coordinate to set.
|
112
|
+
y: Y-coordinate to set.
|
113
|
+
|
114
|
+
Returns:
|
115
|
+
Camera: Returns the Camera object.
|
116
|
+
"""
|
117
|
+
self.rect.topleft = (x, y)
|
118
|
+
return self
|
119
|
+
|
120
|
+
def set_center(self, x, y) -> "Camera":
|
121
|
+
"""
|
122
|
+
Set the camera rect center position.
|
123
|
+
|
124
|
+
Args:
|
125
|
+
x: X-coordinate for the center.
|
126
|
+
y: Y-coordinate for the center.
|
127
|
+
|
128
|
+
Returns:
|
129
|
+
Camera: Returns the Camera object.
|
130
|
+
"""
|
131
|
+
self.rect.center = (x, y)
|
132
|
+
return self
|
133
|
+
|
134
|
+
def set_follow_point(self, func) -> "Camera":
|
135
|
+
"""
|
136
|
+
Set the following function (returns tuple x y).
|
137
|
+
Camera will center its position to the center of the given coordinates.
|
138
|
+
|
139
|
+
Args:
|
140
|
+
func: Function returning coordinates to follow.
|
141
|
+
|
142
|
+
Returns:
|
143
|
+
Camera: Returns the Camera object.
|
144
|
+
"""
|
145
|
+
self.follow_point_func = func
|
146
|
+
return self
|
147
|
+
|
148
|
+
def zoom_by(self, amount: float) -> "Camera":
|
149
|
+
"""
|
150
|
+
Zooms the camera by the given amount.
|
151
|
+
|
152
|
+
Args:
|
153
|
+
amount (float): Amount to zoom.
|
154
|
+
|
155
|
+
Returns:
|
156
|
+
Camera: Returns the Camera object.
|
157
|
+
"""
|
158
|
+
self.zoom(self.zoom_factor + amount)
|
159
|
+
return self
|
160
|
+
|
161
|
+
def zoom(self, factor) -> "Camera":
|
162
|
+
"""
|
163
|
+
Zooms the camera to the given factor.
|
164
|
+
|
165
|
+
Args:
|
166
|
+
factor: Factor to set for zooming.
|
167
|
+
|
168
|
+
Returns:
|
169
|
+
Camera: Returns the Camera object.
|
170
|
+
"""
|
171
|
+
if factor < self.min_zoom or factor > self.max_zoom:
|
172
|
+
return self
|
173
|
+
|
174
|
+
factor = round(factor, 2)
|
175
|
+
self.zoom_factor = factor
|
176
|
+
|
177
|
+
if factor not in self.cached_surfaces:
|
178
|
+
self.cached_surfaces[factor] = pygame.Surface(
|
179
|
+
tuple(i / factor for i in bf.const.RESOLUTION), flags=self.flags
|
180
|
+
).convert_alpha()
|
181
|
+
self.cached_surfaces[factor].fill((0, 0, 0, 0))
|
182
|
+
|
183
|
+
self.surface = self.cached_surfaces[self.zoom_factor]
|
184
|
+
self.rect = self.surface.get_rect(center=self.rect.center)
|
185
|
+
return self
|
186
|
+
|
187
|
+
def intersects(self, rect: pygame.Rect | pygame.FRect) -> bool:
|
188
|
+
"""
|
189
|
+
Check if the camera view intersects with the given rectangle.
|
190
|
+
|
191
|
+
Args:
|
192
|
+
rect (pygame.Rect | pygame.FRect): Rectangle to check intersection with.
|
193
|
+
|
194
|
+
Returns:
|
195
|
+
bool: True if intersection occurs, False otherwise.
|
196
|
+
"""
|
197
|
+
return (
|
198
|
+
self.rect.x < rect.right
|
199
|
+
and self.rect.right > rect.x
|
200
|
+
and self.rect.y < rect.bottom
|
201
|
+
and self.rect.bottom > rect.y
|
202
|
+
)
|
203
|
+
|
204
|
+
def transpose(self, rect: pygame.Rect | pygame.FRect) -> pygame.Rect | pygame.FRect:
|
205
|
+
"""
|
206
|
+
Transpose the given rectangle coordinates relative to the camera.
|
207
|
+
|
208
|
+
Args:
|
209
|
+
rect (pygame.Rect | pygame.FRect): Rectangle to transpose.
|
210
|
+
|
211
|
+
Returns:
|
212
|
+
pygame.FRect: Transposed rectangle.
|
213
|
+
"""
|
214
|
+
return pygame.FRect(rect.x - self.rect.left, rect.y - self.rect.top, *rect.size)
|
215
|
+
|
216
|
+
def convert_screen_to_world(self, x, y):
|
217
|
+
"""
|
218
|
+
Convert screen coordinates to world coordinates based on camera settings.
|
219
|
+
|
220
|
+
Args:
|
221
|
+
x: X-coordinate in screen space.
|
222
|
+
y: Y-coordinate in screen space.
|
223
|
+
|
224
|
+
Returns:
|
225
|
+
tuple: Converted world coordinates.
|
226
|
+
"""
|
227
|
+
return x / self.zoom_factor + self.rect.x, y / self.zoom_factor + self.rect.y
|
228
|
+
|
229
|
+
def update(self, dt):
|
230
|
+
"""
|
231
|
+
Update the camera position based on the follow point function.
|
232
|
+
|
233
|
+
Args:
|
234
|
+
dt: Time delta for updating the camera position.
|
235
|
+
"""
|
236
|
+
if self.follow_point_func:
|
237
|
+
target = self.follow_point_func()
|
238
|
+
self.rect.center = Vector2(self.rect.center).lerp(target, ((dt * 60) * 0.1))
|
239
|
+
|
240
|
+
def draw(self, surface: pygame.Surface):
|
241
|
+
"""
|
242
|
+
Draw the camera view onto the provided surface with proper scaling.
|
243
|
+
|
244
|
+
Args:
|
245
|
+
surface (pygame.Surface): Surface to draw the camera view onto.
|
246
|
+
"""
|
247
|
+
if self.zoom_factor == 1:
|
248
|
+
surface.blit(self.surface, (0, 0), special_flags=self.blit_special_flags)
|
249
|
+
return
|
250
|
+
|
251
|
+
# Scale the surface to match the resolution
|
252
|
+
scaled_surface = pygame.transform.scale(self.surface, bf.const.RESOLUTION)
|
253
|
+
surface.blit(scaled_surface, (0, 0), special_flags=self.blit_special_flags)
|