e2D 1.4.19__py3-none-any.whl → 1.4.23__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.
- e2D/__init__.py +79 -29
- e2D/__init__.pyi +293 -5
- e2D/colors.py +53 -23
- e2D/envs.py +91 -35
- e2D/utils.py +443 -53
- e2D/winrec.py +197 -12
- {e2d-1.4.19.dist-info → e2d-1.4.23.dist-info}/METADATA +3 -2
- e2d-1.4.23.dist-info/RECORD +13 -0
- {e2d-1.4.19.dist-info → e2d-1.4.23.dist-info}/WHEEL +1 -1
- {e2d-1.4.19.dist-info → e2d-1.4.23.dist-info/licenses}/LICENSE +21 -21
- e2d-1.4.19.dist-info/RECORD +0 -13
- {e2d-1.4.19.dist-info → e2d-1.4.23.dist-info}/top_level.txt +0 -0
e2D/colors.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
1
2
|
from colorsys import hsv_to_rgb as __hsv_to_rgb_def__, hls_to_rgb as __hls_to_rgb_def__, rgb_to_hls as __rgb_to_hls__, rgb_to_hsv as __rgb_to_hsv__
|
|
2
3
|
from typing import Any, Callable, Generator, Literal
|
|
3
4
|
from pygame.color import Color as __color_pygame__
|
|
4
|
-
from random import
|
|
5
|
+
from random import random as __rand__
|
|
5
6
|
|
|
6
7
|
RGB_COLOR_MODE = "rgb"
|
|
7
8
|
RGBA_COLOR_MODE = "rgba"
|
|
@@ -15,11 +16,11 @@ HLS_COLOR_MODE = "hls"
|
|
|
15
16
|
|
|
16
17
|
__LITERAL_COLOR_MODES__ = Literal["rgb","rgba","bgr","bgra","g","hsv","hls"] #,"cmyk","lab"]
|
|
17
18
|
|
|
18
|
-
def __hsv_to_rgb__(h:int|float, s:int|float, v:int|float) -> tuple[int|float, int|float, int|float]:
|
|
19
|
+
def __hsv_to_rgb__(h:"int|float", s:"int|float", v:"int|float") -> tuple["int|float", "int|float", "int|float"]:
|
|
19
20
|
r,g,b = __hsv_to_rgb_def__(h, s, v)
|
|
20
21
|
return r*255, g*255, b*255
|
|
21
22
|
|
|
22
|
-
def __hls_to_rgb__(h:int|float, s:int|float, v:int|float) -> tuple[int|float, int|float, int|float]:
|
|
23
|
+
def __hls_to_rgb__(h:"int|float", s:"int|float", v:"int|float") -> tuple["int|float", "int|float", "int|float"]:
|
|
23
24
|
r,g,b = __hls_to_rgb_def__(h, s, v)
|
|
24
25
|
return r*255, g*255, b*255
|
|
25
26
|
|
|
@@ -82,6 +83,12 @@ __conversion_table__ :dict[__LITERAL_COLOR_MODES__, dict[__LITERAL_COLOR_MODES__
|
|
|
82
83
|
},
|
|
83
84
|
}
|
|
84
85
|
|
|
86
|
+
def pygamize_color(color: "__color_pygame__|Color") -> "__color_pygame__":
|
|
87
|
+
return color() if isinstance(color, Color) else color
|
|
88
|
+
|
|
89
|
+
def unpygamize_color(color: "__color_pygame__|Color") -> "Color":
|
|
90
|
+
return Color(*color[:], mode=RGBA_COLOR_MODE) if isinstance(color, __color_pygame__) else color
|
|
91
|
+
|
|
85
92
|
class Color:
|
|
86
93
|
def __init__(self, *values, mode:__LITERAL_COLOR_MODES__=RGB_COLOR_MODE) -> None:
|
|
87
94
|
self.__dict__ = dict(zip(mode, values))
|
|
@@ -104,35 +111,35 @@ class Color:
|
|
|
104
111
|
return (d ** .5) if rooted else d
|
|
105
112
|
|
|
106
113
|
@classmethod
|
|
107
|
-
def new_rgb(cls, r:int|float, g:int|float, b:int|float) -> "Color":
|
|
114
|
+
def new_rgb(cls, r:"int|float", g:"int|float", b:"int|float") -> "Color":
|
|
108
115
|
return Color(r,g,b, mode=RGB_COLOR_MODE)
|
|
109
116
|
@classmethod
|
|
110
|
-
def new_rgba(cls, r:int|float, g:int|float, b:int|float, a:int|float) -> "Color":
|
|
117
|
+
def new_rgba(cls, r:"int|float", g:"int|float", b:"int|float", a:"int|float") -> "Color":
|
|
111
118
|
return Color(r,g,b,a, mode=RGBA_COLOR_MODE)
|
|
112
119
|
@classmethod
|
|
113
|
-
def new_bgr(cls, b:int|float, g:int|float, r:int|float) -> "Color":
|
|
120
|
+
def new_bgr(cls, b:"int|float", g:"int|float", r:"int|float") -> "Color":
|
|
114
121
|
return Color(b,g,r, mode=BGR_COLOR_MODE)
|
|
115
122
|
@classmethod
|
|
116
|
-
def new_bgra(cls, b:int|float, g:int|float, r:int|float, a:int|float) -> "Color":
|
|
123
|
+
def new_bgra(cls, b:"int|float", g:"int|float", r:"int|float", a:"int|float") -> "Color":
|
|
117
124
|
return Color(b,g,r,a, mode=BGRA_COLOR_MODE)
|
|
118
125
|
@classmethod
|
|
119
126
|
def new_g(cls, g) -> "Color":
|
|
120
127
|
return Color(g, mode=GRAY_COLOR_MODE)
|
|
121
128
|
@classmethod
|
|
122
|
-
def new_hsv(cls, h:int|float, s:int|float, v:int|float) -> "Color":
|
|
129
|
+
def new_hsv(cls, h:"int|float", s:"int|float", v:"int|float") -> "Color":
|
|
123
130
|
return Color(h,s,v, mode=HSV_COLOR_MODE)
|
|
124
131
|
@classmethod
|
|
125
|
-
def new_hls(cls, h:int|float, l:int|float, s:int|float) -> "Color":
|
|
132
|
+
def new_hls(cls, h:"int|float", l:"int|float", s:"int|float") -> "Color":
|
|
126
133
|
return Color(h,l,s, mode=HLS_COLOR_MODE)
|
|
127
134
|
# @classmethod
|
|
128
|
-
# def new_cmyk(cls, c:int|float, m:int|float, y:int|float, k:int|float) -> Color:
|
|
135
|
+
# def new_cmyk(cls, c:"int|float", m:"int|float", y:"int|float", k:"int|float") -> Color:
|
|
129
136
|
# return Color(c,m,y,k, mode=CMYK_COLOR_MODE)
|
|
130
137
|
# @classmethod
|
|
131
|
-
# def new_lab(cls, l:int|float, a:int|float, b:int|float) -> Color:
|
|
138
|
+
# def new_lab(cls, l:"int|float", a:"int|float", b:"int|float") -> Color:
|
|
132
139
|
# return Color(l,a,b, mode=LAB_COLOR_MODE)
|
|
133
140
|
|
|
134
141
|
@property
|
|
135
|
-
def values(self) -> tuple[int|float, ...]:
|
|
142
|
+
def values(self) -> tuple["int|float", ...]:
|
|
136
143
|
return tuple(self.__dict__.values())[:-1]
|
|
137
144
|
|
|
138
145
|
@property
|
|
@@ -140,7 +147,7 @@ class Color:
|
|
|
140
147
|
return tuple(self.__dict__.keys())[:-1]
|
|
141
148
|
|
|
142
149
|
@property
|
|
143
|
-
def items(self) -> tuple[tuple[str, int|float], ...]:
|
|
150
|
+
def items(self) -> tuple[tuple[str, "int|float"], ...]:
|
|
144
151
|
return tuple(self.__dict__.items())[:-1]
|
|
145
152
|
|
|
146
153
|
def copy(self) -> "Color":
|
|
@@ -179,7 +186,7 @@ class Color:
|
|
|
179
186
|
return "Color(" + ", ".join(f"{k}:{v}" for k, v in self.items) + ")"
|
|
180
187
|
|
|
181
188
|
def __call__(self) -> __color_pygame__:
|
|
182
|
-
return __color_pygame__(int(self.r), int(self.g), int(self.b))
|
|
189
|
+
return __color_pygame__(int(self.r), int(self.g), int(self.b)) if self.mode == RGB_COLOR_MODE else __color_pygame__(int(self.r), int(self.g), int(self.b), int(self.a))
|
|
183
190
|
|
|
184
191
|
# fast operations Vector2D.operation(both,x,y)
|
|
185
192
|
def add(self, all3=.0, r=.0, g=.0, b=.0) -> "Color":
|
|
@@ -386,7 +393,7 @@ class Color:
|
|
|
386
393
|
def __float__(self) -> "Color":
|
|
387
394
|
return Color(float(self.r), float(self.g), float(self.b))
|
|
388
395
|
|
|
389
|
-
def __getitem__(self, n) -> int|float:
|
|
396
|
+
def __getitem__(self, n) -> "int|float":
|
|
390
397
|
return self.values[n] if isinstance(n, int) else self.values[self.keys.index(n)]
|
|
391
398
|
|
|
392
399
|
def __iter__(self) -> Generator[float, Any, None]:
|
|
@@ -406,8 +413,10 @@ class Color:
|
|
|
406
413
|
try:
|
|
407
414
|
return cls(*other.values, mode=other.mode)
|
|
408
415
|
except:
|
|
409
|
-
raise TypeError(f"The value {other} of type {type(other)} is not a num type: [
|
|
416
|
+
raise TypeError(f"The value {other} of type {type(other)} is not a num type: [int|float] nor an array type: [list|tuple]")
|
|
410
417
|
|
|
418
|
+
@classmethod
|
|
419
|
+
def transparent(cls) -> "Color": return Color(0,0,0,0, mode=RGBA_COLOR_MODE)
|
|
411
420
|
@classmethod
|
|
412
421
|
def white(cls) -> "Color": return Color(255,255,255)
|
|
413
422
|
@classmethod
|
|
@@ -418,23 +427,44 @@ class Color:
|
|
|
418
427
|
def green(cls) -> "Color": return Color(0,255,0)
|
|
419
428
|
@classmethod
|
|
420
429
|
def blue(cls) -> "Color": return Color(0,0,255)
|
|
421
|
-
|
|
422
|
-
# @classmethod
|
|
423
|
-
# def (cls) -> "Color": return Color(0,0,255)
|
|
424
|
-
|
|
425
430
|
@classmethod
|
|
426
|
-
def
|
|
427
|
-
|
|
428
|
-
|
|
431
|
+
def cyan(cls) -> "Color": return Color(0,255,255)
|
|
432
|
+
@classmethod
|
|
433
|
+
def magenta(cls) -> "Color": return Color(255,0,255)
|
|
434
|
+
@classmethod
|
|
435
|
+
def yellow(cls) -> "Color": return Color(255,255,0)
|
|
429
436
|
|
|
437
|
+
@classmethod
|
|
438
|
+
def randomize(cls, start=0, end=255, func=lambda val:val) -> "Color":
|
|
439
|
+
if not isinstance(start, Color):
|
|
440
|
+
if isinstance(start, (int, float)):
|
|
441
|
+
start = Color(start, start, start)
|
|
442
|
+
else:
|
|
443
|
+
raise Exception(f"\nArg start must be in [Color, int, float, tuple, list] not a [{type(start)}]\n")
|
|
444
|
+
if not isinstance(end, Color):
|
|
445
|
+
if isinstance(end, (int, float)):
|
|
446
|
+
end = Color(end, end, end)
|
|
447
|
+
else:
|
|
448
|
+
raise Exception(f"\nArg end must be in [Color, int, float, tuple, list] not a [{type(end)}]\n")
|
|
449
|
+
return start + Color(func(__rand__()), func(__rand__()), func(__rand__())) * (end - start)
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
TRANSPARENT_COLOR = Color.transparent()
|
|
430
453
|
WHITE_COLOR = Color.white()
|
|
431
454
|
BLACK_COLOR = Color.black()
|
|
432
455
|
RED_COLOR = Color.red()
|
|
433
456
|
GREEN_COLOR = Color.green()
|
|
434
457
|
BLUE_COLOR = Color.blue()
|
|
458
|
+
CYAN_COLOR = Color.cyan()
|
|
459
|
+
MAGENTA_COLOR = Color.magenta()
|
|
460
|
+
YELLOW_COLOR = Color.yellow()
|
|
435
461
|
|
|
462
|
+
TRANSPARENT_COLOR_PYG = TRANSPARENT_COLOR()
|
|
436
463
|
WHITE_COLOR_PYG = WHITE_COLOR()
|
|
437
464
|
BLACK_COLOR_PYG = BLACK_COLOR()
|
|
438
465
|
RED_COLOR_PYG = RED_COLOR()
|
|
439
466
|
GREEN_COLOR_PYG = GREEN_COLOR()
|
|
440
467
|
BLUE_COLOR_PYG = BLUE_COLOR()
|
|
468
|
+
CYAN_COLOR_PYG = CYAN_COLOR()
|
|
469
|
+
MAGENTA_COLOR_PYG = MAGENTA_COLOR()
|
|
470
|
+
YELLOW_COLOR_PYG = YELLOW_COLOR()
|
e2D/envs.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from typing import Literal
|
|
2
|
+
from typing import Literal, Optional
|
|
3
3
|
|
|
4
4
|
from .utils import *
|
|
5
5
|
import pygame as pg
|
|
@@ -42,13 +42,15 @@ class RootEnv:
|
|
|
42
42
|
quit_on_key_pressed : None|int = pg.K_x,
|
|
43
43
|
vsync : bool = True,
|
|
44
44
|
window_flags : int = pg.DOUBLEBUF,
|
|
45
|
+
display_index : int = 0,
|
|
45
46
|
clear_screen_each_frame : bool = True) -> None:
|
|
46
47
|
self.quit = False
|
|
47
48
|
self.__screen_size__ :Vector2D= screen_size
|
|
48
49
|
|
|
49
50
|
self.__vsync__ = vsync
|
|
50
51
|
self.__flags__ = window_flags
|
|
51
|
-
self.
|
|
52
|
+
self.__display_index__ = display_index
|
|
53
|
+
self.screen = pg.display.set_mode(self.__screen_size__(), vsync=self.__vsync__, flags=self.__flags__, display=self.__display_index__)
|
|
52
54
|
|
|
53
55
|
self.clock = pg.time.Clock()
|
|
54
56
|
self.keyboard = Keyboard()
|
|
@@ -56,15 +58,38 @@ class RootEnv:
|
|
|
56
58
|
|
|
57
59
|
self.target_fps = target_fps
|
|
58
60
|
self.current_fps = self.target_fps if self.target_fps != 0 else 1
|
|
61
|
+
self.__dt__ = 1 / self.current_fps
|
|
59
62
|
self.current_frame = 0
|
|
60
63
|
self.show_fps = show_fps
|
|
61
64
|
self.events :list[pg.event.Event]= []
|
|
62
|
-
|
|
65
|
+
|
|
66
|
+
# Track start time for accurate runtime calculation (excluding compilation time)
|
|
67
|
+
self.set_starting_timer()
|
|
68
|
+
|
|
69
|
+
self.__background_color__ :pg.Color= BLACK_COLOR_PYG
|
|
70
|
+
|
|
63
71
|
self.clear_screen_each_frame = clear_screen_each_frame
|
|
64
72
|
self.utils :dict[int|str, Util]= {}
|
|
65
73
|
self.selected_util :Util|None = None
|
|
66
74
|
self.__quit_on_key_pressed__ = quit_on_key_pressed
|
|
67
75
|
|
|
76
|
+
self.fps_label = Label(str(round(self.current_fps,2)), self.screen_size * .01, V2(250, 50), BLACK_COLOR_PYG, TRANSPARENT_COLOR_PYG, WHITE_COLOR_PYG, border_width=0, starting_hidden=(not self.show_fps), pivot_position="top_left", font=FONT_ARIAL_32)
|
|
77
|
+
self.add_utils(self.fps_label)
|
|
78
|
+
|
|
79
|
+
def set_starting_timer(self) -> None:
|
|
80
|
+
self.__start_time__ = pg.time.get_ticks()
|
|
81
|
+
|
|
82
|
+
def init_rec(self, fps:int=30, draw_on_screen:bool=True, path:str='output.mp4', font:pg.font.Font=FONT_MONOSPACE_16) -> None:
|
|
83
|
+
from .winrec import WinRec
|
|
84
|
+
self.__winrecorder__ = WinRec(self, fps=fps, draw_on_screen=draw_on_screen, path=path, font=font)
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def background_color(self) -> Color:
|
|
88
|
+
return unpygamize_color(self.__background_color__)
|
|
89
|
+
@background_color.setter
|
|
90
|
+
def background_color(self, color: Color|pg.Color) -> None:
|
|
91
|
+
self.__background_color__ = pygamize_color(color)
|
|
92
|
+
|
|
68
93
|
@property
|
|
69
94
|
def screen_size(self) -> Vector2D:
|
|
70
95
|
return self.__screen_size__
|
|
@@ -72,97 +97,127 @@ class RootEnv:
|
|
|
72
97
|
@screen_size.setter
|
|
73
98
|
def screen_size(self, new_size:Vector2D) -> None:
|
|
74
99
|
self.__screen_size__ = new_size
|
|
75
|
-
self.screen = pg.display.set_mode(self.__screen_size__(), vsync=self.__vsync__, flags=self.__flags__)
|
|
100
|
+
self.screen = pg.display.set_mode(self.__screen_size__(), vsync=self.__vsync__, flags=self.__flags__, display=self.__display_index__)
|
|
101
|
+
|
|
102
|
+
def update_screen_to_new_size(self) -> None:
|
|
103
|
+
self.screen = pg.display.set_mode(self.__screen_size__(), vsync=self.__vsync__, flags=self.__flags__, display=self.__display_index__)
|
|
76
104
|
|
|
77
105
|
@property
|
|
78
|
-
def delta(self) ->
|
|
79
|
-
return self.
|
|
106
|
+
def delta(self) -> float:
|
|
107
|
+
return self.__dt__
|
|
80
108
|
|
|
81
109
|
def get_teoric_max_fps(self) -> float:
|
|
82
110
|
rawdelta = self.clock.get_rawtime()
|
|
83
111
|
return (1000 / rawdelta) if rawdelta != 0 else 1
|
|
84
112
|
|
|
85
|
-
def update_screen_mode(self, vsync:
|
|
86
|
-
self.__vsync__ = vsync
|
|
87
|
-
self.__flags__ = flags
|
|
113
|
+
def update_screen_mode(self, vsync:Optional[bool]=None, flags:Optional[int]=None, display_index:Optional[int]=None) -> None:
|
|
114
|
+
if vsync is not None: self.__vsync__ = vsync
|
|
115
|
+
if flags is not None: self.__flags__ = flags
|
|
116
|
+
if display_index is not None: self.__display_index__ = display_index
|
|
117
|
+
self.screen = pg.display.set_mode(self.__screen_size__(), vsync=self.__vsync__, flags=self.__flags__, display=self.__display_index__)
|
|
88
118
|
|
|
89
119
|
def sleep(self, seconds:int|float, precise_delay=False) -> None:
|
|
90
120
|
if precise_delay:
|
|
91
|
-
pg.time.delay(seconds * 1000)
|
|
121
|
+
pg.time.delay(int(seconds * 1000))
|
|
92
122
|
else:
|
|
93
|
-
pg.time.wait(seconds * 1000)
|
|
123
|
+
pg.time.wait(int(seconds * 1000))
|
|
94
124
|
|
|
95
125
|
def add_utils(self, *utils:Util) -> None:
|
|
96
126
|
for util in utils:
|
|
97
127
|
if util.surface == None: util.surface = self.screen
|
|
98
128
|
util.rootEnv = self
|
|
129
|
+
util.id = self.__new_util_id__()
|
|
130
|
+
util.__render__()
|
|
99
131
|
self.utils[util.id] = util
|
|
100
132
|
|
|
101
133
|
def remove_utils(self, *utils:int|str|Util) -> None:
|
|
102
134
|
for uid in utils:
|
|
103
|
-
if uid
|
|
104
|
-
del self.utils[uid]
|
|
105
|
-
elif isinstance(uid, Util):
|
|
135
|
+
if isinstance(uid, Util):
|
|
106
136
|
del self.utils[uid.id]
|
|
137
|
+
elif uid in self.utils:
|
|
138
|
+
del self.utils[uid]
|
|
107
139
|
else:
|
|
108
140
|
raise Exception(f"Unknown util type: {uid}")
|
|
141
|
+
|
|
142
|
+
def __new_util_id__(self) -> int:
|
|
143
|
+
if not self.utils: return 0
|
|
144
|
+
else: return len(self.utils.keys()) + 1
|
|
145
|
+
|
|
146
|
+
def get_util(self, uid:int|str) -> Util|None:
|
|
147
|
+
if isinstance(uid, Util):
|
|
148
|
+
return self.utils.get(uid.id)
|
|
149
|
+
elif isinstance(uid, int) or isinstance(uid, str):
|
|
150
|
+
return self.utils.get(uid)
|
|
151
|
+
else:
|
|
152
|
+
raise Exception(f"Unknown util type: {uid}")
|
|
109
153
|
|
|
110
154
|
@property
|
|
111
155
|
def runtime_seconds(self) -> float:
|
|
112
|
-
return pg.time.get_ticks() / 1e3
|
|
156
|
+
return (pg.time.get_ticks() - self.__start_time__) / 1e3
|
|
113
157
|
|
|
114
158
|
def init(self, sub_env:DefEnv) -> None:
|
|
115
159
|
self.env = sub_env
|
|
116
160
|
|
|
117
161
|
def clear(self) -> None:
|
|
118
|
-
self.screen.fill(self.
|
|
162
|
+
self.screen.fill(self.__background_color__)
|
|
119
163
|
|
|
120
164
|
def clear_rect(self, position:Vector2D, size:Vector2D) -> None:
|
|
121
|
-
self.screen.fill(self.
|
|
165
|
+
self.screen.fill(self.__background_color__, position() + size())
|
|
122
166
|
|
|
123
167
|
def print(self,
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
) ->
|
|
168
|
+
text : str,
|
|
169
|
+
position : Vector2D,
|
|
170
|
+
color : pg.color.Color = WHITE_COLOR_PYG,
|
|
171
|
+
pivot_position : __LITERAL_PIVOT_POSITIONS__ = "top_left",
|
|
172
|
+
font : pg.font.Font = FONT_ARIAL_32,
|
|
173
|
+
bg_color : None|pg.color.Color = None,
|
|
174
|
+
border_color : pg.color.Color = WHITE_COLOR_PYG,
|
|
175
|
+
border_width : float = 0.0,
|
|
176
|
+
border_radius : int|list[int]|tuple[int,int,int,int] = -1,
|
|
177
|
+
margin : Vector2D = Vector2D.zero(),
|
|
178
|
+
personalized_surface : pg.Surface|None = None
|
|
179
|
+
) -> Vector2D:
|
|
180
|
+
|
|
136
181
|
text_box = font.render(text, True, color)
|
|
137
182
|
size = Vector2D(*text_box.get_size()) + margin * 2
|
|
138
183
|
pivotted_position = position - size * __PIVOT_POSITIONS_MULTIPLIER__[pivot_position] + margin
|
|
139
|
-
if not any(isinstance(border_radius, cls) for cls in {tuple, list}): border_radius = [border_radius]*4
|
|
184
|
+
if not any(isinstance(border_radius, cls) for cls in {tuple, list}): border_radius = [border_radius] * 4
|
|
140
185
|
surface = (self.screen if personalized_surface == None else personalized_surface)
|
|
141
186
|
if bg_color != None:
|
|
142
187
|
pg.draw.rect(surface, bg_color, (pivotted_position - margin)() + size(), 0, -1, *border_radius)
|
|
143
188
|
if border_width:
|
|
144
189
|
pg.draw.rect(surface, border_color, (pivotted_position - margin)() + size(), border_width, -1, *border_radius)
|
|
145
190
|
surface.blit(text_box, pivotted_position())
|
|
191
|
+
return size
|
|
146
192
|
|
|
147
193
|
def __draw__(self) -> None:
|
|
148
|
-
self.clock.tick(self.target_fps)
|
|
194
|
+
self.__dt__ = self.clock.tick(self.target_fps) / 1000.0
|
|
149
195
|
self.current_fps = self.clock.get_fps()
|
|
196
|
+
self.fps_label.text = str(round(self.current_fps, 2))
|
|
197
|
+
|
|
150
198
|
if self.clear_screen_each_frame: self.clear()
|
|
151
199
|
|
|
152
200
|
self.env.draw()
|
|
153
|
-
for util in self.utils.values(): util.
|
|
201
|
+
for util in self.utils.values(): util.__draw__()
|
|
202
|
+
|
|
203
|
+
# Save frame first (clean), then draw info overlay (not saved)
|
|
204
|
+
if hasattr(self, "__winrecorder__"):
|
|
205
|
+
self.__winrecorder__.update() # Captures frame without stats
|
|
206
|
+
self.__winrecorder__.draw() # Draws stats on screen only
|
|
154
207
|
|
|
155
|
-
if self.show_fps: self.print(str(round(self.current_fps,2)), self.screen_size * .01, bg_color=BLACK_COLOR_PYG)
|
|
156
208
|
pg.display.flip()
|
|
157
209
|
|
|
158
210
|
def __update__(self) -> None:
|
|
159
211
|
self.mouse.update()
|
|
160
212
|
self.keyboard.update()
|
|
161
213
|
self.env.update()
|
|
162
|
-
for util in self.utils.values(): util.
|
|
214
|
+
for util in self.utils.values(): util.__update__()
|
|
163
215
|
|
|
164
216
|
def frame(self) -> None:
|
|
165
|
-
|
|
217
|
+
try:
|
|
218
|
+
self.events = pg.event.get()
|
|
219
|
+
except SystemError:
|
|
220
|
+
raise Warning(f"Pygame error with event drivers. Try restarting the program. If the error persists, try restarting your computer.")
|
|
166
221
|
self.current_frame += 1
|
|
167
222
|
self.__update__()
|
|
168
223
|
self.__draw__()
|
|
@@ -170,4 +225,5 @@ class RootEnv:
|
|
|
170
225
|
for event in self.events:
|
|
171
226
|
if event.type == pg.QUIT or ((event.type == pg.KEYDOWN and event.key == self.__quit_on_key_pressed__ and self.selected_util == None) if self.__quit_on_key_pressed__ != None else False):
|
|
172
227
|
pg.quit()
|
|
228
|
+
if hasattr(self, "__winrecorder__"): self.__winrecorder__.quit()
|
|
173
229
|
self.quit = True
|