batframework 1.0.8a3__py3-none-any.whl → 1.0.8a6__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 +16 -2
- batFramework/animatedSprite.py +94 -85
- batFramework/audioManager.py +2 -2
- batFramework/character.py +27 -0
- batFramework/cutscene.py +5 -2
- batFramework/cutsceneBlocks.py +3 -5
- batFramework/dynamicEntity.py +11 -4
- batFramework/enums.py +2 -2
- batFramework/fontManager.py +2 -2
- batFramework/gui/clickableWidget.py +10 -9
- batFramework/gui/constraints/constraints.py +282 -57
- batFramework/gui/image.py +14 -14
- batFramework/gui/interactiveWidget.py +16 -1
- batFramework/gui/label.py +58 -37
- batFramework/gui/layout.py +23 -14
- batFramework/gui/meter.py +10 -7
- batFramework/gui/radioButton.py +1 -1
- batFramework/gui/root.py +7 -1
- batFramework/gui/shape.py +21 -37
- batFramework/gui/slider.py +52 -58
- batFramework/gui/textInput.py +161 -51
- batFramework/gui/toggle.py +27 -41
- batFramework/gui/widget.py +68 -35
- batFramework/manager.py +17 -5
- batFramework/object.py +17 -8
- batFramework/particle.py +22 -8
- batFramework/resourceManager.py +18 -2
- batFramework/scene.py +50 -20
- batFramework/sceneManager.py +52 -28
- batFramework/scrollingSprite.py +7 -8
- 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 +54 -28
- batFramework/transition.py +25 -12
- batFramework/triggerZone.py +1 -1
- batFramework/utils.py +92 -2
- {batframework-1.0.8a3.dist-info → batframework-1.0.8a6.dist-info}/METADATA +3 -15
- batframework-1.0.8a6.dist-info/RECORD +62 -0
- {batframework-1.0.8a3.dist-info → batframework-1.0.8a6.dist-info}/WHEEL +1 -1
- batframework-1.0.8a3.dist-info/RECORD +0 -58
- {batframework-1.0.8a3.dist-info → batframework-1.0.8a6.dist-info}/LICENCE +0 -0
- {batframework-1.0.8a3.dist-info → batframework-1.0.8a6.dist-info}/top_level.txt +0 -0
batFramework/scrollingSprite.py
CHANGED
@@ -99,17 +99,16 @@ class ScrollingSprite(bf.Sprite):
|
|
99
99
|
x += self.original_width
|
100
100
|
return self
|
101
101
|
|
102
|
-
def draw(self, camera: bf.Camera) ->
|
102
|
+
def draw(self, camera: bf.Camera) -> None:
|
103
103
|
if not (
|
104
104
|
self.visible
|
105
105
|
and (self.surface is not None)
|
106
106
|
and camera.rect.colliderect(self.rect)
|
107
107
|
):
|
108
|
-
return
|
109
|
-
self.surface.fill((0, 0, 0, 0))
|
110
|
-
|
111
|
-
[(self.original_surface, r) for r in self._get_mosaic_rect_list()]
|
108
|
+
return
|
109
|
+
# self.surface.fill((0, 0, 0, 0))
|
110
|
+
camera.surface.fblits(
|
111
|
+
[(self.original_surface, r.move(self.rect.x-camera.rect.x,self.rect.y-camera.rect.y)) for r in self._get_mosaic_rect_list()]
|
112
112
|
)
|
113
|
-
#
|
114
|
-
|
115
|
-
return 1
|
113
|
+
# camera.surface.blit(self.surface, camera.world_to_screen(self.rect))
|
114
|
+
return
|
batFramework/stateMachine.py
CHANGED
@@ -7,11 +7,11 @@ class StateMachine: ...
|
|
7
7
|
class State:
|
8
8
|
def __init__(self, name: str) -> None:
|
9
9
|
self.name = name
|
10
|
-
self.
|
10
|
+
self.parent: bf.Entity | bf.AnimatedSprite = None
|
11
11
|
self.state_machine: StateMachine = None
|
12
12
|
|
13
|
-
def
|
14
|
-
self.
|
13
|
+
def set_parent(self, parent: bf.Entity | bf.AnimatedSprite):
|
14
|
+
self.parent = parent
|
15
15
|
|
16
16
|
def set_stateMachine(self, stateMachine):
|
17
17
|
self.state_machine = stateMachine
|
@@ -27,16 +27,19 @@ class State:
|
|
27
27
|
|
28
28
|
|
29
29
|
class StateMachine:
|
30
|
-
def __init__(self,
|
30
|
+
def __init__(self, parent) -> None:
|
31
31
|
self.states: dict[str, State] = {}
|
32
|
-
self.
|
32
|
+
self.parent = parent
|
33
33
|
self.current_state = None
|
34
34
|
|
35
35
|
def add_state(self, state: State):
|
36
36
|
self.states[state.name] = state
|
37
|
-
state.
|
37
|
+
state.set_parent(self.parent)
|
38
38
|
state.set_stateMachine(self)
|
39
39
|
|
40
|
+
def remove_state(self,state_name: str):
|
41
|
+
self.states.pop(state_name,default=None)
|
42
|
+
|
40
43
|
def set_state(self, state_name: str):
|
41
44
|
if state_name in self.states:
|
42
45
|
if self.current_state:
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import batFramework as bf
|
2
|
+
import pygame
|
3
|
+
from .states import *
|
4
|
+
|
5
|
+
class Platform2DCharacter(bf.Character):
|
6
|
+
def __init__(self):
|
7
|
+
super().__init__()
|
8
|
+
self.actions = bf.ActionContainer(
|
9
|
+
*bf.DirectionalKeyControls(),
|
10
|
+
bf.Action("jump").add_key_control(pygame.K_SPACE).set_holding()
|
11
|
+
)
|
12
|
+
self.on_ground : bool = False
|
13
|
+
self.max_jumps = 2
|
14
|
+
self.jump_counter = 0
|
15
|
+
self.jump_force = 150
|
16
|
+
self.speed = 100
|
17
|
+
self.acceleration = 30
|
18
|
+
self.friction = 0.7
|
19
|
+
self.gravity = 300
|
20
|
+
self.terminal_velocity = 1000
|
21
|
+
self.state_machine.set_state("idle")
|
22
|
+
|
23
|
+
|
24
|
+
def do_setup_animations(self):
|
25
|
+
self.add_animation(bf.Animation("idle"))
|
26
|
+
self.add_animation(bf.Animation("run"))
|
27
|
+
self.add_animation(bf.Animation("jump"))
|
28
|
+
self.add_animation(bf.Animation("fall"))
|
29
|
+
|
30
|
+
|
31
|
+
def do_setup_states(self):
|
32
|
+
self.state_machine.add_state(Platform2DIdle())
|
33
|
+
self.state_machine.add_state(Platform2DRun())
|
34
|
+
self.state_machine.add_state(Platform2DJump())
|
35
|
+
self.state_machine.add_state(Platform2DFall())
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
def do_reset_actions(self) -> None:
|
40
|
+
self.actions.reset()
|
41
|
+
|
42
|
+
def do_process_actions(self, event: pygame.Event) -> None:
|
43
|
+
self.actions.process_event(event)
|
44
|
+
|
@@ -0,0 +1,166 @@
|
|
1
|
+
import batFramework as bf
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
4
|
+
if TYPE_CHECKING:
|
5
|
+
from .character import Platform2DCharacter
|
6
|
+
|
7
|
+
|
8
|
+
class CharacterState(bf.State):
|
9
|
+
def set_parent(self, parent):
|
10
|
+
"""Initialize the parent character."""
|
11
|
+
res = super().set_parent(parent)
|
12
|
+
if res:
|
13
|
+
self.parent: Platform2DCharacter = parent
|
14
|
+
return res
|
15
|
+
|
16
|
+
def on_enter(self):
|
17
|
+
"""Handle state entry."""
|
18
|
+
self.parent.set_animation(self.name)
|
19
|
+
|
20
|
+
def handle_input(self):
|
21
|
+
"""Process input and update movement direction."""
|
22
|
+
if self.parent.actions.is_active("right"):
|
23
|
+
self._apply_horizontal_input(self.parent.acceleration, self.parent.speed)
|
24
|
+
if self.parent.actions.is_active("left"):
|
25
|
+
self._apply_horizontal_input(-self.parent.acceleration, -self.parent.speed)
|
26
|
+
|
27
|
+
if self.parent.velocity.x > 0:
|
28
|
+
self.parent.set_flipX(False)
|
29
|
+
elif self.parent.velocity.x < 0:
|
30
|
+
self.parent.set_flipX(True)
|
31
|
+
|
32
|
+
|
33
|
+
def _apply_horizontal_input(self, acceleration, limit):
|
34
|
+
"""Apply input acceleration and enforce speed limit."""
|
35
|
+
|
36
|
+
self.parent.velocity.x += acceleration
|
37
|
+
if abs(self.parent.velocity.x) > abs(limit):
|
38
|
+
self.parent.velocity.x = limit
|
39
|
+
|
40
|
+
def apply_friction(self):
|
41
|
+
"""Apply friction to horizontal velocity."""
|
42
|
+
if (self.parent.actions.is_active("right") or self.parent.actions.is_active("left")):
|
43
|
+
return
|
44
|
+
|
45
|
+
if abs(self.parent.velocity.x) < 0.01: # Threshold for negligible velocity
|
46
|
+
self.parent.velocity.x = 0
|
47
|
+
else:
|
48
|
+
self.parent.velocity.x *= self.parent.friction
|
49
|
+
|
50
|
+
def apply_gravity(self, dt):
|
51
|
+
"""Apply gravity to vertical velocity."""
|
52
|
+
self.parent.velocity.y += self.parent.gravity * dt
|
53
|
+
self.parent.velocity.y = min(self.parent.velocity.y, self.parent.terminal_velocity)
|
54
|
+
|
55
|
+
def move_character(self, dt):
|
56
|
+
"""Move the character based on velocity."""
|
57
|
+
self.parent.rect.x += self.parent.velocity.x * dt
|
58
|
+
self.parent.rect.y += self.parent.velocity.y * dt
|
59
|
+
|
60
|
+
def update(self, dt):
|
61
|
+
"""Update the character state."""
|
62
|
+
self.handle_input()
|
63
|
+
self.apply_physics(dt)
|
64
|
+
self.handle_collision()
|
65
|
+
|
66
|
+
def apply_physics(self, dt):
|
67
|
+
"""Apply all physics effects."""
|
68
|
+
self.apply_friction()
|
69
|
+
self.move_character(dt)
|
70
|
+
if self.parent.on_ground:
|
71
|
+
self.parent.velocity.y = 0 # Stop downward movement on ground
|
72
|
+
|
73
|
+
def handle_collision(self):
|
74
|
+
"""Placeholder for collision detection and resolution."""
|
75
|
+
pass # Future collision code goes here
|
76
|
+
|
77
|
+
|
78
|
+
class Platform2DIdle(CharacterState):
|
79
|
+
def __init__(self) -> None:
|
80
|
+
super().__init__("idle")
|
81
|
+
|
82
|
+
def on_enter(self):
|
83
|
+
self.parent.jump_counter = 0
|
84
|
+
super().on_enter()
|
85
|
+
|
86
|
+
def update(self, dt):
|
87
|
+
super().update(dt)
|
88
|
+
|
89
|
+
if not self.parent.on_ground:
|
90
|
+
self.parent.set_state("fall")
|
91
|
+
elif self.parent.velocity.x != 0:
|
92
|
+
self.parent.set_state("run")
|
93
|
+
elif self.parent.actions.is_active("jump"):
|
94
|
+
self.parent.set_state("jump")
|
95
|
+
|
96
|
+
|
97
|
+
class Platform2DRun(CharacterState):
|
98
|
+
def __init__(self) -> None:
|
99
|
+
super().__init__("run")
|
100
|
+
|
101
|
+
|
102
|
+
def on_enter(self):
|
103
|
+
self.parent.jump_counter = 0
|
104
|
+
super().on_enter()
|
105
|
+
|
106
|
+
def update(self, dt):
|
107
|
+
super().update(dt)
|
108
|
+
|
109
|
+
if self.parent.velocity.x :
|
110
|
+
if (self.parent.actions.is_active("right") or self.parent.actions.is_active("left")):
|
111
|
+
if self.parent.get_current_animation().name != "run" : self.parent.set_animation("run")
|
112
|
+
else:
|
113
|
+
if self.parent.get_current_animation().name != "idle" : self.parent.set_animation("idle")
|
114
|
+
|
115
|
+
if self.parent.actions.is_active("jump"):
|
116
|
+
self.parent.set_state("jump")
|
117
|
+
elif self.parent.velocity.x == 0:
|
118
|
+
if not (self.parent.actions.is_active("right") or self.parent.actions.is_active("left")):
|
119
|
+
self.parent.set_state("idle")
|
120
|
+
elif not self.parent.on_ground:
|
121
|
+
self.parent.set_state("fall")
|
122
|
+
|
123
|
+
|
124
|
+
|
125
|
+
|
126
|
+
class Platform2DJump(CharacterState):
|
127
|
+
def __init__(self) -> None:
|
128
|
+
super().__init__("jump")
|
129
|
+
|
130
|
+
def on_enter(self):
|
131
|
+
super().on_enter()
|
132
|
+
self.parent.on_ground = False
|
133
|
+
self.parent.velocity.y = -self.parent.jump_force
|
134
|
+
self.parent.jump_counter += 1
|
135
|
+
|
136
|
+
def update(self, dt):
|
137
|
+
super().update(dt)
|
138
|
+
self.apply_gravity(dt)
|
139
|
+
|
140
|
+
|
141
|
+
if self.parent.jump_counter < self.parent.max_jumps:
|
142
|
+
if self.parent.actions.is_active("jump") and (self.parent.velocity.y//10)*10 == 0:
|
143
|
+
self.parent.set_state("jump")
|
144
|
+
return
|
145
|
+
|
146
|
+
|
147
|
+
if self.parent.velocity.y > 0:
|
148
|
+
self.parent.set_state("fall")
|
149
|
+
|
150
|
+
|
151
|
+
class Platform2DFall(CharacterState):
|
152
|
+
def __init__(self) -> None:
|
153
|
+
super().__init__("fall")
|
154
|
+
|
155
|
+
def update(self, dt):
|
156
|
+
super().update(dt)
|
157
|
+
self.apply_gravity(dt)
|
158
|
+
|
159
|
+
if self.parent.on_ground:
|
160
|
+
if abs(self.parent.velocity.x) > 0.01:
|
161
|
+
self.parent.set_state("run")
|
162
|
+
else:
|
163
|
+
self.parent.set_state("idle")
|
164
|
+
|
165
|
+
if self.parent.actions.is_active("jump") and self.parent.jump_counter < self.parent.max_jumps:
|
166
|
+
self.parent.set_state("jump")
|
batFramework/time.py
CHANGED
@@ -2,13 +2,21 @@ import batFramework as bf
|
|
2
2
|
from typing import Self
|
3
3
|
|
4
4
|
|
5
|
+
from typing import Callable, Union, Self
|
6
|
+
|
7
|
+
|
5
8
|
class Timer:
|
6
9
|
_count: int = 0
|
10
|
+
_available_ids: set[int] = set()
|
7
11
|
|
8
|
-
def __init__(self, duration: float
|
9
|
-
|
10
|
-
|
12
|
+
def __init__(self, duration: Union[float, int], end_callback: Callable, loop: bool = False, register: str = "global") -> None:
|
13
|
+
if Timer._available_ids:
|
14
|
+
self.uid = Timer._available_ids.pop()
|
15
|
+
else:
|
16
|
+
self.uid = Timer._count
|
17
|
+
Timer._count += 1
|
11
18
|
|
19
|
+
self.register = register
|
12
20
|
self.duration: int | float = duration
|
13
21
|
self.end_callback = end_callback
|
14
22
|
|
@@ -18,8 +26,11 @@ class Timer:
|
|
18
26
|
self.is_paused: bool = False
|
19
27
|
self.do_delete: bool = False
|
20
28
|
|
21
|
-
def
|
22
|
-
return
|
29
|
+
def __bool__(self)->bool:
|
30
|
+
return self.elapsed_time==-1 or self.is_over
|
31
|
+
|
32
|
+
def __str__(self) -> str:
|
33
|
+
return f"Timer ({self.uid}) {self.elapsed_time}/{self.duration} | {'loop ' if self.is_looping else ''} {'(D) ' if self.do_delete else ''}"
|
23
34
|
|
24
35
|
def stop(self) -> Self:
|
25
36
|
self.elapsed_time = -1
|
@@ -30,7 +41,7 @@ class Timer:
|
|
30
41
|
def start(self, force: bool = False) -> Self:
|
31
42
|
if self.elapsed_time != -1 and not force:
|
32
43
|
return self
|
33
|
-
if not bf.TimeManager().add_timer(self):
|
44
|
+
if not bf.TimeManager().add_timer(self,self.register):
|
34
45
|
return self
|
35
46
|
self.elapsed_time = 0
|
36
47
|
self.is_paused = False
|
@@ -79,36 +90,42 @@ class Timer:
|
|
79
90
|
def should_delete(self) -> bool:
|
80
91
|
return self.is_over or self.do_delete
|
81
92
|
|
93
|
+
def _release_id(self):
|
94
|
+
Timer._available_ids.add(self.uid)
|
82
95
|
|
83
|
-
class TimerRegister:
|
84
|
-
def __init__(self, active=True):
|
85
|
-
self.active = active
|
86
|
-
self.timers: dict[int | str, Timer] = {}
|
87
|
-
|
88
|
-
def __iter__(self):
|
89
|
-
return iter(self.timers.values())
|
90
|
-
|
91
|
-
def add_timer(self, timer: Timer):
|
92
|
-
self.timers[timer.name] = timer
|
93
|
-
|
94
|
-
def update(self, dt):
|
95
|
-
expired_timers = []
|
96
|
-
for timer in list(self.timers.values()):
|
97
|
-
if not timer.is_paused:
|
98
|
-
timer.update(dt)
|
99
|
-
if timer.should_delete():
|
100
|
-
expired_timers.append(timer.name)
|
101
|
-
for name in expired_timers:
|
102
|
-
del self.timers[name]
|
103
96
|
|
97
|
+
class SceneTimer(Timer):
|
98
|
+
def __init__(self, duration: float | int, end_callback, loop: bool = False, scene_name:str = "global") -> None:
|
99
|
+
super().__init__(duration, end_callback, loop, scene_name)
|
104
100
|
|
105
101
|
class TimeManager(metaclass=bf.Singleton):
|
102
|
+
class TimerRegister:
|
103
|
+
def __init__(self, active=True):
|
104
|
+
self.active = active
|
105
|
+
self.timers: dict[int | str, Timer] = {}
|
106
|
+
|
107
|
+
def __iter__(self):
|
108
|
+
return iter(self.timers.values())
|
109
|
+
|
110
|
+
def add_timer(self, timer: Timer):
|
111
|
+
self.timers[timer.uid] = timer
|
112
|
+
|
113
|
+
def update(self, dt):
|
114
|
+
expired_timers = []
|
115
|
+
for timer in list(self.timers.values()):
|
116
|
+
if not timer.is_paused:
|
117
|
+
timer.update(dt)
|
118
|
+
if timer.should_delete():
|
119
|
+
expired_timers.append(timer.uid)
|
120
|
+
for uid in expired_timers:
|
121
|
+
del self.timers[uid]
|
122
|
+
|
106
123
|
def __init__(self):
|
107
|
-
self.registers = {"global": TimerRegister()}
|
124
|
+
self.registers = {"global": TimeManager.TimerRegister()}
|
108
125
|
|
109
126
|
def add_register(self, name, active=True):
|
110
127
|
if name not in self.registers:
|
111
|
-
self.registers[name] = TimerRegister(active)
|
128
|
+
self.registers[name] = TimeManager.TimerRegister(active)
|
112
129
|
|
113
130
|
def add_timer(self, timer, register="global") -> bool:
|
114
131
|
if register in self.registers:
|
@@ -133,3 +150,12 @@ class TimeManager(metaclass=bf.Singleton):
|
|
133
150
|
|
134
151
|
def deactivate_register(self, name):
|
135
152
|
self.activate_register(name, active=False)
|
153
|
+
|
154
|
+
def __str__(self)->str:
|
155
|
+
res = ""
|
156
|
+
for name,reg in self.registers.items():
|
157
|
+
if not reg.timers:continue
|
158
|
+
res +=name+"\n"
|
159
|
+
for t in reg.timers.values():
|
160
|
+
res +="\t"+str(t)+"\n"
|
161
|
+
return res
|
batFramework/transition.py
CHANGED
@@ -87,10 +87,10 @@ class Transition:
|
|
87
87
|
class FadeColor(Transition):
|
88
88
|
def __init__(
|
89
89
|
self,
|
90
|
-
color: tuple
|
90
|
+
color: tuple,
|
91
91
|
middle_duration: float,
|
92
|
-
first_duration: float = None,
|
93
|
-
second_duration: float = None,
|
92
|
+
first_duration: float | None = None,
|
93
|
+
second_duration: float | None = None,
|
94
94
|
easing_function: bf.easing = bf.easing.LINEAR,
|
95
95
|
) -> None:
|
96
96
|
super().__init__(0, easing_function)
|
@@ -98,16 +98,25 @@ class FadeColor(Transition):
|
|
98
98
|
first_duration = middle_duration
|
99
99
|
if second_duration is None:
|
100
100
|
second_duration = middle_duration
|
101
|
-
|
101
|
+
|
102
102
|
self.first = Fade(first_duration)
|
103
|
+
self.second = Fade(second_duration)
|
103
104
|
self.color = color
|
104
|
-
self.
|
105
|
-
|
106
|
-
|
107
|
-
self.timer = bf.Timer(
|
108
|
-
|
109
|
-
)
|
110
|
-
|
105
|
+
self.middle_duration = middle_duration
|
106
|
+
self.index = 0
|
107
|
+
|
108
|
+
self.timer = bf.Timer(middle_duration, self.transition_to_second)
|
109
|
+
self.first.set_end_callback(self.transition_to_middle)
|
110
|
+
self.second.set_end_callback(self.transition_to_end)
|
111
|
+
|
112
|
+
def transition_to_middle(self):
|
113
|
+
self.next_step(self.timer.start)
|
114
|
+
|
115
|
+
def transition_to_second(self):
|
116
|
+
self.next_step(self.second.start)
|
117
|
+
|
118
|
+
def transition_to_end(self):
|
119
|
+
self.next_step(self.end)
|
111
120
|
|
112
121
|
def next_step(self, callback=None) -> None:
|
113
122
|
self.index += 1
|
@@ -125,6 +134,7 @@ class FadeColor(Transition):
|
|
125
134
|
def start(self):
|
126
135
|
if self.start_callback:
|
127
136
|
self.start_callback()
|
137
|
+
|
128
138
|
self.color_surf = pygame.Surface(self.source.get_size())
|
129
139
|
self.color_surf.fill(self.color)
|
130
140
|
|
@@ -141,7 +151,7 @@ class FadeColor(Transition):
|
|
141
151
|
self.second.draw(surface)
|
142
152
|
|
143
153
|
def skip(self, no_callback: bool = False):
|
144
|
-
if
|
154
|
+
if not no_callback and self.end_callback:
|
145
155
|
self.end_callback()
|
146
156
|
|
147
157
|
self.first.controller.stop()
|
@@ -149,6 +159,7 @@ class FadeColor(Transition):
|
|
149
159
|
self.second.controller.stop()
|
150
160
|
|
151
161
|
|
162
|
+
|
152
163
|
class Fade(Transition):
|
153
164
|
def end(self):
|
154
165
|
self.dest.set_alpha(255)
|
@@ -213,3 +224,5 @@ class CircleIn(Transition):
|
|
213
224
|
)
|
214
225
|
mask = pygame.mask.from_surface(self.circle_surf)
|
215
226
|
mask.to_surface(surface=surface, setsurface=self.source, unsetsurface=self.dest)
|
227
|
+
|
228
|
+
|
batFramework/triggerZone.py
CHANGED
@@ -4,7 +4,7 @@ import batFramework as bf
|
|
4
4
|
class TriggerZone(bf.Entity):
|
5
5
|
def __init__(self, size, trigger, callback, active=True) -> None:
|
6
6
|
super().__init__(size, True)
|
7
|
-
self.set_debug_color(bf.color.
|
7
|
+
self.set_debug_color(bf.color.RED)
|
8
8
|
self.active = active
|
9
9
|
self.callback = callback
|
10
10
|
self.trigger = trigger
|
batFramework/utils.py
CHANGED
@@ -5,6 +5,11 @@ import batFramework as bf
|
|
5
5
|
import json
|
6
6
|
from .enums import *
|
7
7
|
import re
|
8
|
+
from typing import Callable, TYPE_CHECKING, Any
|
9
|
+
from functools import cache
|
10
|
+
if TYPE_CHECKING:
|
11
|
+
from .object import Object
|
12
|
+
from .entity import Entity
|
8
13
|
|
9
14
|
|
10
15
|
class Singleton(type):
|
@@ -27,8 +32,6 @@ class Utils:
|
|
27
32
|
with their tuple coordinates as keys.
|
28
33
|
Exemple : '(0,0) : Surface'
|
29
34
|
"""
|
30
|
-
if surface is None:
|
31
|
-
return None
|
32
35
|
width, height = surface.get_size()
|
33
36
|
res = {}
|
34
37
|
for iy, y in enumerate(range(0, height, split_size[1])):
|
@@ -57,3 +60,90 @@ class Utils:
|
|
57
60
|
return pattern.sub("", s)
|
58
61
|
|
59
62
|
return filter_function
|
63
|
+
|
64
|
+
|
65
|
+
@staticmethod
|
66
|
+
@cache
|
67
|
+
def create_spotlight(inside_color, outside_color, radius, radius_stop=None, dest_surf=None,size=None):
|
68
|
+
"""
|
69
|
+
Draws a circle spotlight centered on a surface
|
70
|
+
inner color on the center
|
71
|
+
gradient towards outside color from radius to radius stop
|
72
|
+
surface background is made transparent
|
73
|
+
if des_surf is None:
|
74
|
+
if size is None : size is radius_stop*radius_stop
|
75
|
+
returns the newly created surface of size 'size' with the spotlight drawn
|
76
|
+
|
77
|
+
"""
|
78
|
+
if radius_stop is None:
|
79
|
+
radius_stop = radius
|
80
|
+
diameter = radius_stop * 2
|
81
|
+
|
82
|
+
if dest_surf is None:
|
83
|
+
if size is None:
|
84
|
+
size = (diameter,diameter)
|
85
|
+
dest_surf = pygame.Surface(size, pygame.SRCALPHA)
|
86
|
+
|
87
|
+
dest_surf.fill((0,0,0,0))
|
88
|
+
|
89
|
+
|
90
|
+
center = dest_surf.get_rect().center
|
91
|
+
|
92
|
+
if radius_stop != radius:
|
93
|
+
for r in range(radius_stop, radius - 1, -1):
|
94
|
+
color = [
|
95
|
+
inside_color[i] + (outside_color[i] - inside_color[i]) * (r - radius) / (radius_stop - radius)
|
96
|
+
for i in range(3)
|
97
|
+
] + [255] # Preserve the alpha channel as fully opaque
|
98
|
+
pygame.draw.circle(dest_surf, color, center, r)
|
99
|
+
else:
|
100
|
+
pygame.draw.circle(dest_surf, inside_color, center, radius)
|
101
|
+
|
102
|
+
return dest_surf
|
103
|
+
|
104
|
+
@staticmethod
|
105
|
+
def draw_spotlight(dest_surf:pygame.Surface,inside_color,outside_color,radius,radius_stop=None,center=None):
|
106
|
+
if radius_stop is None:
|
107
|
+
radius_stop = radius
|
108
|
+
center = dest_surf.get_rect().center if center is None else center
|
109
|
+
if radius_stop != radius:
|
110
|
+
for r in range(radius_stop, radius - 1, -1):
|
111
|
+
color = [
|
112
|
+
inside_color[i] + (outside_color[i] - inside_color[i]) * (r - radius) / (radius_stop - radius)
|
113
|
+
for i in range(3)
|
114
|
+
] + [255]
|
115
|
+
pygame.draw.circle(dest_surf, color, center, r)
|
116
|
+
else:
|
117
|
+
pygame.draw.circle(dest_surf, inside_color, center, radius)
|
118
|
+
|
119
|
+
@staticmethod
|
120
|
+
def animate_move(entity:"Object", start_pos : tuple[float,float], end_pos:tuple[float,float])->Callable[[float],None]:
|
121
|
+
def func(x):
|
122
|
+
entity.set_center(start_pos[0]+(end_pos[0]-start_pos[0])*x,start_pos[1]+(end_pos[1]-start_pos[1])*x)
|
123
|
+
return func
|
124
|
+
|
125
|
+
def animate_move_to(entity: "Object", end_pos: tuple[float, float]) -> Callable[[float], None]:
|
126
|
+
# Start position will be captured once when the animation starts
|
127
|
+
start_pos = [None]
|
128
|
+
|
129
|
+
def update_position(progression: float):
|
130
|
+
if start_pos[0] is None:
|
131
|
+
start_pos[0] = entity.rect.center # Capture the start position at the start of the animation
|
132
|
+
|
133
|
+
# Calculate new position based on progression
|
134
|
+
new_x = start_pos[0][0] + (end_pos[0] - start_pos[0][0]) * progression
|
135
|
+
new_y = start_pos[0][1] + (end_pos[1] - start_pos[0][1]) * progression
|
136
|
+
|
137
|
+
# Set the entity's new position
|
138
|
+
entity.set_center(new_x, new_y)
|
139
|
+
|
140
|
+
return update_position
|
141
|
+
|
142
|
+
@staticmethod
|
143
|
+
def animate_alpha(entity:"Entity", start : int, end:int)->Callable[[float],None]:
|
144
|
+
def func(x):
|
145
|
+
entity.set_alpha(int(pygame.math.clamp(start+(end-start)*x,0,255)))
|
146
|
+
return func
|
147
|
+
|
148
|
+
|
149
|
+
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: batframework
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.8a6
|
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
|
@@ -12,9 +12,9 @@ Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENCE
|
13
13
|
Requires-Dist: pygame-ce
|
14
14
|
|
15
|
-
# batFramework
|
15
|
+
# batFramework
|
16
16
|
|
17
|
-
Welcome to the `batFramework
|
17
|
+
Welcome to the `batFramework`. This README provides an overview of the game framework.
|
18
18
|
|
19
19
|
## batFramework
|
20
20
|
|
@@ -38,18 +38,6 @@ The `batFramework` is a Python game development framework based on pygame, desig
|
|
38
38
|
|
39
39
|
For more detailed information on how to use the framework, refer to the documentation (if available) or explore the source code in the `batFramework` directory.
|
40
40
|
|
41
|
-
## gamejam Project
|
42
41
|
|
43
|
-
The `gamejam` project is a specific game developed using the `batFramework`. It serves as an example of how the framework can be used to create a game from scratch.
|
44
|
-
|
45
|
-
### Play the gamejam Project
|
46
|
-
|
47
|
-
1. Install Python (version 3.10 or higher) and the latest stable version of pygame-ce.
|
48
|
-
2. Clone or download this repository.
|
49
|
-
3. Navigate to the `gamejam` directory.
|
50
|
-
4. Run the game by executing the main script (e.g., `python main.py`).
|
51
|
-
5. Play the game and have fun!
|
52
|
-
|
53
|
-
Feel free to explore the code in the `gamejam` directory to see how the `batFramework` is utilized to create the game. You can modify, extend, or use the project as a starting point for your own games.
|
54
42
|
|
55
43
|
|