batframework 1.0.6__py3-none-any.whl → 1.0.8a1__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 +23 -14
- batFramework/action.py +95 -106
- batFramework/actionContainer.py +11 -8
- batFramework/animatedSprite.py +60 -43
- batFramework/audioManager.py +52 -22
- batFramework/camera.py +87 -72
- batFramework/constants.py +19 -41
- batFramework/cutscene.py +12 -11
- batFramework/cutsceneBlocks.py +12 -14
- batFramework/dynamicEntity.py +5 -4
- batFramework/easingController.py +58 -0
- batFramework/entity.py +37 -130
- batFramework/enums.py +93 -3
- batFramework/fontManager.py +15 -7
- batFramework/gui/__init__.py +5 -1
- batFramework/gui/button.py +6 -144
- batFramework/gui/clickableWidget.py +206 -0
- batFramework/gui/constraints/__init__.py +1 -0
- batFramework/gui/constraints/constraints.py +378 -0
- batFramework/gui/container.py +147 -34
- batFramework/gui/debugger.py +39 -22
- batFramework/gui/dialogueBox.py +69 -43
- batFramework/gui/draggableWidget.py +38 -0
- batFramework/gui/image.py +33 -28
- batFramework/gui/indicator.py +30 -16
- batFramework/gui/interactiveWidget.py +72 -20
- batFramework/gui/label.py +240 -98
- batFramework/gui/layout.py +125 -53
- batFramework/gui/meter.py +76 -0
- batFramework/gui/radioButton.py +62 -0
- batFramework/gui/root.py +72 -48
- batFramework/gui/shape.py +257 -49
- batFramework/gui/slider.py +217 -2
- batFramework/gui/textInput.py +106 -60
- batFramework/gui/toggle.py +85 -42
- batFramework/gui/widget.py +259 -288
- batFramework/manager.py +30 -16
- batFramework/object.py +115 -0
- batFramework/{particles.py → particle.py} +37 -34
- batFramework/renderGroup.py +62 -0
- batFramework/resourceManager.py +36 -24
- batFramework/scene.py +94 -88
- batFramework/sceneManager.py +140 -57
- batFramework/scrollingSprite.py +113 -0
- batFramework/sprite.py +35 -23
- batFramework/tileset.py +34 -52
- batFramework/time.py +105 -56
- batFramework/transition.py +213 -1
- batFramework/utils.py +38 -18
- {batframework-1.0.6.dist-info → batframework-1.0.8a1.dist-info}/METADATA +1 -1
- batframework-1.0.8a1.dist-info/RECORD +56 -0
- {batframework-1.0.6.dist-info → batframework-1.0.8a1.dist-info}/WHEEL +1 -1
- batFramework/easing.py +0 -76
- batFramework/gui/constraints.py +0 -277
- batFramework/gui/frame.py +0 -25
- batFramework/transitionManager.py +0 -0
- batframework-1.0.6.dist-info/RECORD +0 -50
- {batframework-1.0.6.dist-info → batframework-1.0.8a1.dist-info}/LICENCE +0 -0
- {batframework-1.0.6.dist-info → batframework-1.0.8a1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
from typing import Self, Iterator
|
2
|
+
from pygame.math import Vector2
|
3
|
+
import batFramework as bf
|
4
|
+
import pygame
|
5
|
+
|
6
|
+
|
7
|
+
class ScrollingSprite(bf.Sprite):
|
8
|
+
def __init__(
|
9
|
+
self,
|
10
|
+
data: pygame.Surface | str,
|
11
|
+
size: None | tuple[int, int] = None,
|
12
|
+
convert_alpha: bool = True,
|
13
|
+
):
|
14
|
+
self.scroll_value = Vector2(0, 0)
|
15
|
+
self.auto_scroll = Vector2(0, 0)
|
16
|
+
|
17
|
+
# Use integer values for the starting points, converted from floating point scroll values
|
18
|
+
|
19
|
+
super().__init__(data, size, convert_alpha)
|
20
|
+
self.original_width, self.original_height = self.original_surface.get_size()
|
21
|
+
|
22
|
+
def get_debug_outlines(self):
|
23
|
+
yield from super().get_debug_outlines()
|
24
|
+
for r in self._get_mosaic_rect_list():
|
25
|
+
yield r.move(*self.rect.topleft)
|
26
|
+
|
27
|
+
def set_image(
|
28
|
+
self, data: pygame.Surface | str, size: None | tuple[int, int] = None
|
29
|
+
) -> Self:
|
30
|
+
super().set_image(data, size)
|
31
|
+
self.original_width, self.original_height = self.original_surface.get_size()
|
32
|
+
return self
|
33
|
+
|
34
|
+
def set_autoscroll(self, x: float, y: float) -> Self:
|
35
|
+
self.auto_scroll.update(x, y)
|
36
|
+
return self
|
37
|
+
|
38
|
+
def set_scroll(self, x: float = None, y: float = None) -> Self:
|
39
|
+
self.scroll_value.update(
|
40
|
+
x if x else self.scroll_value.x, y if y else self.scroll_value.y
|
41
|
+
)
|
42
|
+
return self
|
43
|
+
|
44
|
+
def scroll(self, x: float, y: float) -> Self:
|
45
|
+
self.scroll_value += x, y
|
46
|
+
return self
|
47
|
+
|
48
|
+
def update(self, dt: float) -> None:
|
49
|
+
if self.auto_scroll:
|
50
|
+
self.scroll(*self.auto_scroll * dt)
|
51
|
+
original_width, original_height = self.original_surface.get_size()
|
52
|
+
|
53
|
+
# Use integer values for the starting points, converted from floating point scroll values
|
54
|
+
|
55
|
+
if self.scroll_value.x > self.original_width:
|
56
|
+
self.scroll_value.x -= self.original_width
|
57
|
+
if self.scroll_value.y > self.original_height:
|
58
|
+
self.scroll_value.y -= self.original_height
|
59
|
+
|
60
|
+
super().update(dt)
|
61
|
+
|
62
|
+
def set_size(self, size: tuple[int | None, int | None]) -> Self:
|
63
|
+
size = list(size)
|
64
|
+
if size[0] is None: size[0] = self.rect.w
|
65
|
+
if size[1] is None: size[1] = self.rect.h
|
66
|
+
|
67
|
+
self.surface = pygame.Surface(size).convert_alpha()
|
68
|
+
self.rect = self.surface.get_frect(center=self.rect.center)
|
69
|
+
return self
|
70
|
+
|
71
|
+
def _get_mosaic_rect_list(self) -> Iterator[pygame.Rect]:
|
72
|
+
# Use integer values for the starting points, converted from floating point scroll values
|
73
|
+
start_x = int(self.scroll_value.x % self.original_width)
|
74
|
+
start_y = int(self.scroll_value.y % self.original_height)
|
75
|
+
|
76
|
+
# Adjust start_x and start_y to begin tiling off-screen to the top-left, covering all visible area
|
77
|
+
if start_x != 0:
|
78
|
+
start_x -= self.original_width
|
79
|
+
if start_y != 0:
|
80
|
+
start_y -= self.original_height
|
81
|
+
|
82
|
+
# Set the region in which to tile
|
83
|
+
end_x = self.rect.w
|
84
|
+
end_y = self.rect.h
|
85
|
+
|
86
|
+
# Starting y_position for the inner loop
|
87
|
+
y_position = start_y
|
88
|
+
|
89
|
+
# if self.rect.w-1 < self.scroll_value.x < self.rect.w+1 : print(self.scroll_value.x,int(self.scroll_value.x % self.rect.w),start_x,self.rect.w,original_width)
|
90
|
+
# Generate all necessary rectangles
|
91
|
+
x = start_x
|
92
|
+
while x < end_x:
|
93
|
+
y = y_position
|
94
|
+
while y < end_y:
|
95
|
+
yield pygame.Rect(x, y, self.original_width, self.original_height)
|
96
|
+
y += self.original_height
|
97
|
+
x += self.original_width
|
98
|
+
return self
|
99
|
+
|
100
|
+
def draw(self, camera: bf.Camera) -> int:
|
101
|
+
if not (
|
102
|
+
self.visible
|
103
|
+
and (self.surface is not None)
|
104
|
+
and camera.rect.colliderect(self.rect)
|
105
|
+
):
|
106
|
+
return 0
|
107
|
+
self.surface.fill((0, 0, 0, 0))
|
108
|
+
self.surface.fblits(
|
109
|
+
[(self.original_surface, r) for r in self._get_mosaic_rect_list()]
|
110
|
+
)
|
111
|
+
# pygame.draw.rect(camera.surface,"green",next(self._get_mosaic_rect_list()).move(*self.rect.topleft),1)
|
112
|
+
camera.surface.blit(self.surface, camera.world_to_screen(self.rect))
|
113
|
+
return 1
|
batFramework/sprite.py
CHANGED
@@ -2,32 +2,44 @@ import batFramework as bf
|
|
2
2
|
import pygame
|
3
3
|
from typing import Self
|
4
4
|
|
5
|
-
|
5
|
+
|
6
|
+
class Sprite(bf.Entity):
|
6
7
|
def __init__(
|
7
8
|
self,
|
8
|
-
|
9
|
+
path=None,
|
9
10
|
size: None | tuple[int, int] = None,
|
10
11
|
convert_alpha: bool = True,
|
11
12
|
):
|
12
|
-
self.original_surface = None
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
13
|
+
self.original_surface: pygame.Surface = None
|
14
|
+
|
15
|
+
super().__init__(convert_alpha = convert_alpha)
|
16
|
+
if path is not None:
|
17
|
+
self.from_path(path)
|
18
|
+
if size is not None and self.original_surface:
|
19
|
+
self.set_size(self.original_surface.get_size())
|
20
|
+
|
21
|
+
|
22
|
+
def set_size(self,size:tuple[float,float]) -> Self:
|
23
|
+
if size == self.rect.size : return self
|
24
|
+
self.rect.size = size
|
25
|
+
self.surface = pygame.Surface((int(self.rect.w),int(self.rect.h)),self.surface_flags)
|
26
|
+
if self.convert_alpha : self.surface = self.surface.convert_alpha()
|
27
|
+
self.surface.fill((0,0,0,0 if self.convert_alpha else 255))
|
28
|
+
self.surface.blit(pygame.transform.scale(self.original_surface,self.rect.size),(0,0))
|
29
|
+
return self
|
30
|
+
|
31
|
+
def from_path(self,path:str)->Self:
|
32
|
+
tmp = bf.ResourceManager().get_image(path,self.convert_alpha)
|
33
|
+
if tmp is None:
|
34
|
+
return self
|
35
|
+
self.original_surface = tmp
|
36
|
+
size = self.original_surface.get_size()
|
37
|
+
self.set_size(size)
|
38
|
+
return self
|
33
39
|
|
40
|
+
def from_surface(self,surface: pygame.Surface)->Self:
|
41
|
+
if surface is None : return self
|
42
|
+
self.original_surface = surface
|
43
|
+
size = self.original_surface.get_size()
|
44
|
+
self.set_size(size)
|
45
|
+
return self
|
batFramework/tileset.py
CHANGED
@@ -1,64 +1,46 @@
|
|
1
1
|
import pygame
|
2
|
-
from .utils import Utils
|
3
2
|
from .resourceManager import ResourceManager
|
3
|
+
import batFramework as bf
|
4
4
|
|
5
|
-
class Tileset:
|
6
|
-
_tilesets = {}
|
7
|
-
_flip_cache = {} # {"tileset":tileset,"index","flipX","flipY"}
|
8
5
|
|
9
|
-
def __init__(self, source: pygame.Surface | str, tilesize) -> None:
|
10
|
-
if isinstance(source, str):
|
11
|
-
source = ResourceManager().get_image(source,convert_alpha=True)
|
12
6
|
|
13
|
-
|
7
|
+
class Tileset:
|
8
|
+
def __init__(self, source: pygame.Surface, tilesize: tuple[int, int]) -> None:
|
14
9
|
self.surface = source
|
15
10
|
self.tile_size = tilesize
|
16
|
-
self.
|
11
|
+
self.tile_width = source.get_width() // tilesize[0]
|
12
|
+
self.tile_height = source.get_height() // tilesize[1]
|
13
|
+
# Create flipped versions of the tileset surface
|
14
|
+
self.flipped_surfaces = {
|
15
|
+
(False, False): self.surface,
|
16
|
+
(False, True): pygame.transform.flip(self.surface, False, True),
|
17
|
+
(True, False): pygame.transform.flip(self.surface, True, False),
|
18
|
+
(True, True): pygame.transform.flip(self.surface, True, True),
|
19
|
+
}
|
20
|
+
|
21
|
+
# Split each of the surfaces into tiles
|
22
|
+
self.tile_dict = {}
|
23
|
+
for flip_state, surf in self.flipped_surfaces.items():
|
24
|
+
tiles = bf.utils.split_surface(surf, self.tile_size)
|
25
|
+
for coord, tile in tiles.items():
|
26
|
+
if coord not in self.tile_dict:
|
27
|
+
self.tile_dict[coord] = {}
|
28
|
+
self.tile_dict[coord][flip_state] = tile
|
17
29
|
|
18
|
-
def split_surface(self, surface: pygame.Surface):
|
19
|
-
width, height = surface.get_size()
|
20
|
-
num_tiles_x = width // self.tile_size
|
21
|
-
num_tiles_y = height // self.tile_size
|
22
|
-
# Iterate over the tiles vertically and horizontally
|
23
|
-
for y in range(num_tiles_y):
|
24
|
-
for x in range(num_tiles_x):
|
25
|
-
# Calculate the coordinates of the current tile in the tileset
|
26
|
-
tile_x = x * self.tile_size
|
27
|
-
tile_y = y * self.tile_size
|
28
|
-
# Create a subsurface for the current tile
|
29
|
-
tile_surface = surface.subsurface(
|
30
|
-
pygame.Rect(tile_x, tile_y, self.tile_size, self.tile_size)
|
31
|
-
)
|
32
|
-
# Calculate the unique key for the tile (e.g., based on its coordinates)
|
33
|
-
tile_key = (x, y)
|
34
|
-
# Store the subsurface in the dictionary with the corresponding key
|
35
|
-
self.tile_dict[tile_key] = tile_surface
|
36
|
-
# print(self.tile_dict)
|
37
30
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
if not key in self._flip_cache:
|
44
|
-
self._flip_cache[key] = pygame.transform.flip(
|
45
|
-
self.tile_dict[(x, y)], flipX, flipY
|
46
|
-
)
|
47
|
-
return self._flip_cache[key]
|
48
|
-
return self.tile_dict[(x, y)]
|
31
|
+
def __str__(self)->str:
|
32
|
+
num_tiles = 0
|
33
|
+
if self.tile_dict:
|
34
|
+
num_tiles = len(self.tile_dict.values())
|
35
|
+
return f"{num_tiles} tiles | Tile size : {self.tile_size}"
|
49
36
|
|
50
|
-
|
51
|
-
def load_tileset(path: str, name: str, tilesize) -> "Tileset":
|
52
|
-
if name in Tileset._tilesets:
|
53
|
-
return Tileset._tilesets[name]
|
54
|
-
else:
|
55
|
-
img = ResourceManager().get_image(path,convert_alpha=True)
|
56
|
-
tileset = Tileset(img, tilesize)
|
57
|
-
Tileset._tilesets[name] = tileset
|
58
|
-
return tileset
|
37
|
+
def get_tile(self, x, y, flipX=False, flipY=False) -> pygame.Surface | None:
|
59
38
|
|
60
|
-
|
61
|
-
|
62
|
-
if
|
39
|
+
if flipX:
|
40
|
+
x = self.tile_width - 1 - x
|
41
|
+
if flipY:
|
42
|
+
y = self.tile_height - 1 - y
|
43
|
+
tile_data = self.tile_dict.get((x, y), None)
|
44
|
+
if tile_data is None:
|
63
45
|
return None
|
64
|
-
return
|
46
|
+
return tile_data.get((flipX, flipY), None)
|
batFramework/time.py
CHANGED
@@ -1,86 +1,135 @@
|
|
1
|
-
import pygame
|
2
1
|
import batFramework as bf
|
3
2
|
from typing import Self
|
4
3
|
|
4
|
+
|
5
5
|
class Timer:
|
6
|
-
_count
|
7
|
-
|
8
|
-
|
9
|
-
Timer._count
|
6
|
+
_count: int = 0
|
7
|
+
|
8
|
+
def __init__(self, duration: float | int, end_callback, loop: bool = False) -> None:
|
9
|
+
self.name: int = Timer._count
|
10
|
+
Timer._count += 1
|
11
|
+
|
12
|
+
self.duration: int | float = duration
|
10
13
|
self.end_callback = end_callback
|
11
|
-
|
12
|
-
self.
|
13
|
-
self.
|
14
|
-
self.
|
15
|
-
self.
|
16
|
-
self.
|
17
|
-
|
18
|
-
def
|
19
|
-
self.elapsed_time
|
20
|
-
|
21
|
-
|
14
|
+
|
15
|
+
self.elapsed_time: float = -1
|
16
|
+
self.is_over: bool = False
|
17
|
+
self.is_looping: bool = loop
|
18
|
+
self.is_paused: bool = False
|
19
|
+
self.do_delete: bool = False
|
20
|
+
|
21
|
+
def __repr__(self) -> str:
|
22
|
+
return f"Timer ({self.name}) {self.elapsed_time}/{self.duration} | {'loop ' if self.is_looping else ''} {'(D) ' if self.do_delete else ''}"
|
23
|
+
|
24
|
+
def stop(self) -> Self:
|
25
|
+
self.elapsed_time = -1
|
26
|
+
self.is_over = False
|
27
|
+
self.is_paused = False
|
22
28
|
return self
|
23
|
-
|
24
|
-
def start(self)->Self:
|
25
|
-
if self.elapsed_time
|
29
|
+
|
30
|
+
def start(self, force: bool = False) -> Self:
|
31
|
+
if self.elapsed_time != -1 and not force:
|
32
|
+
return self
|
33
|
+
if not bf.TimeManager().add_timer(self):
|
34
|
+
return self
|
26
35
|
self.elapsed_time = 0
|
27
|
-
self.
|
28
|
-
self.
|
29
|
-
bf.TimeManager().add_timer(self)
|
36
|
+
self.is_paused = False
|
37
|
+
self.is_over = False
|
30
38
|
return self
|
31
|
-
|
32
|
-
def pause(self)->Self:
|
33
|
-
self.
|
39
|
+
|
40
|
+
def pause(self) -> Self:
|
41
|
+
self.is_paused = True
|
34
42
|
return self
|
35
43
|
|
36
|
-
def resume(self)->Self:
|
37
|
-
self.
|
44
|
+
def resume(self) -> Self:
|
45
|
+
self.is_paused = False
|
38
46
|
return self
|
39
|
-
|
47
|
+
|
48
|
+
def delete(self) -> Self:
|
40
49
|
self.do_delete = True
|
41
50
|
return self
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
51
|
+
|
52
|
+
def has_started(self) -> bool:
|
53
|
+
return self.elapsed_time != -1
|
54
|
+
|
55
|
+
def get_progression(self) -> float:
|
56
|
+
if self.elapsed_time < 0:
|
57
|
+
return 0
|
58
|
+
if self.elapsed_time >= self.duration:
|
59
|
+
return 1
|
60
|
+
return self.elapsed_time / self.duration
|
61
|
+
|
62
|
+
def update(self, dt) -> None:
|
63
|
+
if self.elapsed_time < 0 or self.is_paused or self.is_over:
|
64
|
+
return
|
49
65
|
self.elapsed_time += dt
|
50
66
|
# print("update :",self.elapsed_time,self.duration)
|
51
67
|
if self.get_progression() == 1:
|
52
68
|
self.end()
|
53
|
-
|
69
|
+
|
54
70
|
def end(self):
|
55
|
-
self.end_callback
|
71
|
+
if self.end_callback:
|
72
|
+
self.end_callback()
|
73
|
+
self.elapsed_time = -1
|
74
|
+
self.is_over = True
|
56
75
|
if self.is_looping:
|
57
|
-
self.elapsed_time = -1
|
58
76
|
self.start()
|
59
77
|
return
|
60
|
-
|
61
|
-
self.over = True
|
62
78
|
|
63
|
-
def
|
64
|
-
return self.
|
79
|
+
def should_delete(self) -> bool:
|
80
|
+
return self.is_over or self.do_delete
|
81
|
+
|
82
|
+
|
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]
|
65
103
|
|
66
104
|
|
67
105
|
class TimeManager(metaclass=bf.Singleton):
|
68
106
|
def __init__(self):
|
69
|
-
|
70
|
-
self.timers = {}
|
107
|
+
self.registers = {"global": TimerRegister()}
|
71
108
|
|
72
|
-
def
|
73
|
-
|
74
|
-
|
109
|
+
def add_register(self, name, active=True):
|
110
|
+
if name not in self.registers:
|
111
|
+
self.registers[name] = TimerRegister(active)
|
112
|
+
|
113
|
+
def add_timer(self, timer, register="global") -> bool:
|
114
|
+
if register in self.registers:
|
115
|
+
self.registers[register].add_timer(timer)
|
116
|
+
return True
|
117
|
+
print(f"Register '{register}' does not exist.")
|
118
|
+
return False
|
119
|
+
|
120
|
+
def get_active_registers(self) -> list[TimerRegister]:
|
121
|
+
return [t for t in self.registers.values() if t.active]
|
75
122
|
|
76
|
-
def update(self,dt):
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
timer.update(dt)
|
123
|
+
def update(self, dt):
|
124
|
+
for register_name, register in self.registers.items():
|
125
|
+
if register.active:
|
126
|
+
register.update(dt)
|
81
127
|
|
82
|
-
|
128
|
+
def activate_register(self, name, active=True):
|
129
|
+
if name in self.registers:
|
130
|
+
self.registers[name].active = active
|
131
|
+
else:
|
132
|
+
print(f"Register '{name}' does not exist.")
|
83
133
|
|
84
|
-
|
85
|
-
|
86
|
-
self.timers.pop(name)
|
134
|
+
def deactivate_register(self, name):
|
135
|
+
self.activate_register(name, active=False)
|
batFramework/transition.py
CHANGED
@@ -1,3 +1,215 @@
|
|
1
|
-
import pygame
|
2
1
|
import batFramework as bf
|
2
|
+
from typing import Self
|
3
|
+
import pygame
|
4
|
+
|
5
|
+
"""
|
6
|
+
Both surfaces to transition need to be the same size
|
7
|
+
|
8
|
+
"""
|
9
|
+
|
10
|
+
|
11
|
+
class Transition:
|
12
|
+
def __init__(
|
13
|
+
self, duration: float, easing_function: bf.easing = bf.easing.LINEAR
|
14
|
+
) -> None:
|
15
|
+
"""
|
16
|
+
duration : time in seconds
|
17
|
+
easing function : controls the progression rate
|
18
|
+
"""
|
19
|
+
self.duration: float = duration
|
20
|
+
self.controller = bf.EasingController(
|
21
|
+
easing_function,
|
22
|
+
duration,
|
23
|
+
update_callback=self.update,
|
24
|
+
end_callback=self.end,
|
25
|
+
)
|
26
|
+
self.start_callback = None
|
27
|
+
self.update_callback = None
|
28
|
+
self.end_callback = None
|
29
|
+
self.source: pygame.Surface = None
|
30
|
+
self.dest: pygame.Surface = None
|
31
|
+
|
32
|
+
def __repr__(self) -> str:
|
33
|
+
return f"Transition {self.__class__},{self.duration}"
|
34
|
+
|
35
|
+
def set_start_callback(self, func) -> Self:
|
36
|
+
self.start_callback = func
|
37
|
+
return self
|
38
|
+
|
39
|
+
def set_update_callback(self, func) -> Self:
|
40
|
+
self.update_callback = func
|
41
|
+
return self
|
42
|
+
|
43
|
+
def set_end_callback(self, func) -> Self:
|
44
|
+
self.end_callback = func
|
45
|
+
return self
|
46
|
+
|
47
|
+
def set_source(self, surface: pygame.Surface) -> None:
|
48
|
+
self.source = surface
|
49
|
+
|
50
|
+
def set_dest(self, surface: pygame.Surface) -> None:
|
51
|
+
self.dest = surface
|
52
|
+
|
53
|
+
def start(self):
|
54
|
+
if self.controller.has_started():
|
55
|
+
return
|
56
|
+
if self.duration:
|
57
|
+
self.controller.start()
|
58
|
+
if self.start_callback:
|
59
|
+
self.start_callback()
|
60
|
+
return
|
61
|
+
|
62
|
+
self.controller.start()
|
63
|
+
if self.start_callback:
|
64
|
+
self.start_callback()
|
65
|
+
self.controller.end()
|
66
|
+
self.update(1)
|
67
|
+
self.end()
|
68
|
+
|
69
|
+
def update(self, progression: float) -> None:
|
70
|
+
if self.update_callback:
|
71
|
+
self.update_callback(progression)
|
72
|
+
|
73
|
+
def end(self):
|
74
|
+
self.controller.stop()
|
75
|
+
if self.end_callback:
|
76
|
+
self.end_callback()
|
77
|
+
|
78
|
+
def draw(self, surface: pygame.Surface) -> None:
|
79
|
+
pass
|
80
|
+
|
81
|
+
def skip(self, no_callback: bool = False):
|
82
|
+
self.controller.stop()
|
83
|
+
if self.end_callback and (no_callback == False):
|
84
|
+
self.end_callback()
|
85
|
+
|
86
|
+
|
87
|
+
class FadeColor(Transition):
|
88
|
+
def __init__(
|
89
|
+
self,
|
90
|
+
color: tuple | str,
|
91
|
+
middle_duration: float,
|
92
|
+
first_duration: float = None,
|
93
|
+
second_duration: float = None,
|
94
|
+
easing_function: bf.easing = bf.easing.LINEAR,
|
95
|
+
) -> None:
|
96
|
+
super().__init__(0, easing_function)
|
97
|
+
if first_duration is None:
|
98
|
+
first_duration = middle_duration
|
99
|
+
if second_duration is None:
|
100
|
+
second_duration = middle_duration
|
101
|
+
self.index = 0
|
102
|
+
self.first = Fade(first_duration)
|
103
|
+
self.color = color
|
104
|
+
self.second = Fade(second_duration).set_end_callback(
|
105
|
+
lambda: self.next_step(self.end)
|
106
|
+
)
|
107
|
+
self.timer = bf.Timer(
|
108
|
+
middle_duration, lambda: self.next_step(self.second.start)
|
109
|
+
)
|
110
|
+
self.first.set_end_callback(lambda: self.next_step(self.timer.start))
|
111
|
+
|
112
|
+
def next_step(self, callback=None) -> None:
|
113
|
+
self.index += 1
|
114
|
+
if callback:
|
115
|
+
callback()
|
116
|
+
|
117
|
+
def set_source(self, surface) -> None:
|
118
|
+
super().set_source(surface)
|
119
|
+
self.first.set_source(surface)
|
120
|
+
|
121
|
+
def set_dest(self, surface) -> None:
|
122
|
+
super().set_dest(surface)
|
123
|
+
self.second.set_dest(surface)
|
124
|
+
|
125
|
+
def start(self):
|
126
|
+
if self.start_callback:
|
127
|
+
self.start_callback()
|
128
|
+
self.color_surf = pygame.Surface(self.source.get_size())
|
129
|
+
self.color_surf.fill(self.color)
|
130
|
+
|
131
|
+
self.first.set_dest(self.color_surf)
|
132
|
+
self.second.set_source(self.color_surf)
|
133
|
+
self.first.start()
|
134
|
+
|
135
|
+
def draw(self, surface):
|
136
|
+
if self.index == 0:
|
137
|
+
self.first.draw(surface)
|
138
|
+
elif self.index == 1:
|
139
|
+
surface.blit(self.color_surf, (0, 0))
|
140
|
+
else:
|
141
|
+
self.second.draw(surface)
|
142
|
+
|
143
|
+
def skip(self, no_callback: bool = False):
|
144
|
+
if (no_callback == False) and self.end_callback:
|
145
|
+
self.end_callback()
|
146
|
+
|
147
|
+
self.first.controller.stop()
|
148
|
+
self.timer.stop()
|
149
|
+
self.second.controller.stop()
|
150
|
+
|
151
|
+
|
152
|
+
class Fade(Transition):
|
153
|
+
def end(self):
|
154
|
+
self.dest.set_alpha(255)
|
155
|
+
return super().end()
|
156
|
+
|
157
|
+
def draw(self, surface):
|
158
|
+
dest_alpha = 255 * self.controller.get_value()
|
159
|
+
self.dest.set_alpha(dest_alpha)
|
160
|
+
surface.blit(self.source, (0, 0))
|
161
|
+
surface.blit(self.dest, (0, 0))
|
162
|
+
|
163
|
+
|
164
|
+
class GlideRight(Transition):
|
165
|
+
def draw(self, surface):
|
166
|
+
width = surface.get_width()
|
167
|
+
source_x = -self.controller.get_value() * width
|
168
|
+
surface.blit(self.source, (source_x, 0))
|
169
|
+
surface.blit(self.dest, (width + source_x, 0))
|
170
|
+
|
171
|
+
|
172
|
+
class GlideLeft(Transition):
|
173
|
+
def draw(self, surface):
|
174
|
+
width = surface.get_width()
|
175
|
+
source_x = self.controller.get_value() * width
|
176
|
+
surface.blit(self.source, (source_x, 0))
|
177
|
+
surface.blit(self.dest, (source_x - width, 0))
|
178
|
+
|
179
|
+
|
180
|
+
class CircleOut(Transition):
|
181
|
+
def start(self):
|
182
|
+
super().start()
|
183
|
+
self.circle_surf = self.source.copy()
|
184
|
+
self.circle_surf.set_colorkey((0, 0, 0))
|
185
|
+
self.circle_surf.fill((0, 0, 0))
|
186
|
+
self.surface_width = self.circle_surf.get_width()
|
187
|
+
|
188
|
+
def draw(self, surface):
|
189
|
+
v = self.controller.get_value()
|
190
|
+
|
191
|
+
radius = self.surface_width * v
|
192
|
+
pygame.draw.circle(
|
193
|
+
self.circle_surf, "white", self.circle_surf.get_rect().center, radius
|
194
|
+
)
|
195
|
+
mask = pygame.mask.from_surface(self.circle_surf)
|
196
|
+
mask.to_surface(surface=surface, setsurface=self.dest, unsetsurface=self.source)
|
197
|
+
|
198
|
+
|
199
|
+
class CircleIn(Transition):
|
200
|
+
def start(self):
|
201
|
+
super().start()
|
202
|
+
self.circle_surf = self.source.copy()
|
203
|
+
self.circle_surf.set_colorkey((0, 0, 0))
|
204
|
+
self.circle_surf.fill((0, 0, 0))
|
205
|
+
self.surface_width = self.circle_surf.get_width()
|
3
206
|
|
207
|
+
def draw(self, surface):
|
208
|
+
v = self.controller.get_value()
|
209
|
+
radius = self.surface_width - (self.surface_width * v)
|
210
|
+
self.circle_surf.fill((0, 0, 0))
|
211
|
+
pygame.draw.circle(
|
212
|
+
self.circle_surf, "white", self.circle_surf.get_rect().center, radius
|
213
|
+
)
|
214
|
+
mask = pygame.mask.from_surface(self.circle_surf)
|
215
|
+
mask.to_surface(surface=surface, setsurface=self.source, unsetsurface=self.dest)
|