e2D 1.4.18__tar.gz → 1.4.20__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.
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2023 Riko Mari
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
+ MIT License
2
+
3
+ Copyright (c) 2025 Riccardo Mariani
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,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: e2D
3
- Version: 1.4.18
3
+ Version: 1.4.20
4
4
  Summary: Python library for 2D games. Streamlines dev with keyboard/mouse input, vector calculations, color manipulation, and collision detection. Simplify game creation and unleash creativity!
5
5
  Home-page: https://github.com/marick-py/e2D
6
6
  Author: Riccardo Mariani
@@ -13,6 +13,7 @@ Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: numpy
15
15
  Requires-Dist: pygame
16
+ Dynamic: license-file
16
17
 
17
18
  # e2D
18
19
  ## A Python Game Development Library
@@ -10,6 +10,7 @@ PI_QUARTER = PI/4
10
10
  PI_DOUBLE = PI*2
11
11
 
12
12
  sign = lambda val: -1 if val < 0 else (1 if val > 0 else 0)
13
+ clamp = lambda x, minn, maxx: x if x > minn and x < maxx else (minn if x < minn else maxx)
13
14
 
14
15
  class Vector2D:
15
16
  round_values_on_print = 2
@@ -17,7 +18,7 @@ class Vector2D:
17
18
  self.x = x
18
19
  self.y = y
19
20
 
20
- def distance_to(self, other, rooted=True) -> float:
21
+ def distance_to(self, other, rooted=True) -> int|float:
21
22
  d = (self.x - other.x)**2 + (self.y - other.y)**2
22
23
  return d**(1/2) if rooted else d
23
24
 
@@ -42,6 +43,13 @@ class Vector2D:
42
43
  @property
43
44
  def sign(self) -> "Vector2D":
44
45
  return Vector2D(sign(self.x), sign(self.y))
46
+
47
+ def clamp(self, min_val: Vector2D, max_val: Vector2D) -> "Vector2D":
48
+ return Vector2D(clamp(self.x, min_val.x, max_val.x), clamp(self.y, min_val.y, max_val.y))
49
+
50
+ def iclamp(self, min_val: Vector2D, max_val: Vector2D) -> None:
51
+ self.x = clamp(self.x, min_val.x, max_val.x)
52
+ self.y = clamp(self.y, min_val.y, max_val.y)
45
53
 
46
54
  @property
47
55
  def normalize(self) -> "Vector2D":
@@ -71,7 +79,7 @@ class Vector2D:
71
79
  return self.__round__(n)
72
80
 
73
81
  @classmethod
74
- def randomize(cls, start, end) -> "Vector2D":
82
+ def randomize(cls, start, end, func=lambda val:val) -> "Vector2D":
75
83
  if not isinstance(start, Vector2D):
76
84
  if isinstance(start, (int, float)):
77
85
  start = Vector2D(start, start)
@@ -82,7 +90,7 @@ class Vector2D:
82
90
  end = Vector2D(end, end)
83
91
  else:
84
92
  raise Exception(f"\nArg end must be in [Vector2D, int, float, tuple, list] not a [{type(end)}]\n")
85
- return start + Vector2D(_rnd.random(), _rnd.random()) * (end - start)
93
+ return start + Vector2D(func(_rnd.random()), func(_rnd.random())) * (end - start)
86
94
 
87
95
  def dot_product(self, other) -> float:
88
96
  return self.x * other.x + self.y * other.y
@@ -12,6 +12,7 @@ PI_DOUBLE : float
12
12
  #
13
13
 
14
14
  sign : Callable[[int|float], Literal[-1,0,1]]
15
+ clamp: Callable[[int|float, int|float, int|float], int|float]
15
16
 
16
17
  class Vector2D:
17
18
  round_values_on_print : int|float
@@ -39,7 +40,7 @@ class Vector2D:
39
40
  self.x : int|float
40
41
  self.y : int|float
41
42
 
42
- def distance_to(self:"Vector2D", other:"Vector2D", rooted:bool=True) -> float:
43
+ def distance_to(self:"Vector2D", other:"Vector2D", rooted:bool=True) -> int|float:
43
44
  """
44
45
  # Calculate the distance between the current Vector2D other and another other.
45
46
 
@@ -211,6 +212,54 @@ class Vector2D:
211
212
  """
212
213
  ...
213
214
 
215
+ def clamp(self, min_val: Vector2D, max_val: Vector2D) -> "Vector2D":
216
+ """
217
+ # Clamp the vector's components between the corresponding components of two other vectors.
218
+
219
+ ## Parameters:
220
+ min_val (Vector2D): The minimum vector for clamping.
221
+ max_val (Vector2D): The maximum vector for clamping.
222
+
223
+ ## Returns:
224
+ Vector2D: A new vector with its components clamped between the corresponding components of `min_val` and `max_val`.
225
+
226
+ ## Example:
227
+ v = Vector2D(5, 10)
228
+ min_val = Vector2D(0, 8)
229
+ max_val = Vector2D(6, 12)
230
+ clamped_v = v.clamp(min_val, max_val)
231
+ print(clamped_v) # Output: (5, 10)
232
+
233
+ ## Explanation:
234
+ This method clamps the x and y components of the current vector between the corresponding x and y components
235
+ of the `min_val` and `max_val` vectors. The resulting vector is returned as a new Vector2D instance.
236
+ """
237
+ ...
238
+
239
+ def iclamp(self, min_val: Vector2D, max_val: Vector2D) -> None:
240
+ """
241
+ # Clamp the vector's components in place between the corresponding components of two other vectors.
242
+
243
+ ## Parameters:
244
+ min_val (Vector2D): The minimum vector for clamping.
245
+ max_val (Vector2D): The maximum vector for clamping.
246
+
247
+ ## Returns:
248
+ None
249
+
250
+ ## Example:
251
+ v = Vector2D(5, 10)
252
+ min_val = Vector2D(0, 8)
253
+ max_val = Vector2D(6, 12)
254
+ v.iclamp(min_val, max_val)
255
+ print(v) # Output: (5, 10)
256
+
257
+ ## Explanation:
258
+ This method clamps the x and y components of the current vector in place between the corresponding x and y components
259
+ of the `min_val` and `max_val` vectors. The method modifies the current vector directly.
260
+ """
261
+ ...
262
+
214
263
  @property
215
264
  def normalize(self:"Vector2D") -> "Vector2D":
216
265
  """
@@ -264,7 +313,7 @@ class Vector2D:
264
313
  ...
265
314
 
266
315
  @classmethod
267
- def randomize(cls, start:"int|float|Vector2D", end:"int|float|Vector2D") -> "Vector2D":
316
+ def randomize(cls, start:"int|float|Vector2D", end:"int|float|Vector2D", func:Callable[[int|float], int|float]=lambda val:val) -> "Vector2D":
268
317
  """
269
318
  # Generate a random Vector2D point within the specified range.
270
319
 
@@ -82,6 +82,12 @@ __conversion_table__ :dict[__LITERAL_COLOR_MODES__, dict[__LITERAL_COLOR_MODES__
82
82
  },
83
83
  }
84
84
 
85
+ def pygamize_color(color: "__color_pygame__|Color") -> "__color_pygame__":
86
+ return color() if isinstance(color, Color) else color
87
+
88
+ def unpygamize_color(color: "__color_pygame__|Color") -> "Color":
89
+ return Color(*color[:], mode=RGBA_COLOR_MODE) if isinstance(color, __color_pygame__) else color
90
+
85
91
  class Color:
86
92
  def __init__(self, *values, mode:__LITERAL_COLOR_MODES__=RGB_COLOR_MODE) -> None:
87
93
  self.__dict__ = dict(zip(mode, values))
@@ -179,7 +185,7 @@ class Color:
179
185
  return "Color(" + ", ".join(f"{k}:{v}" for k, v in self.items) + ")"
180
186
 
181
187
  def __call__(self) -> __color_pygame__:
182
- return __color_pygame__(int(self.r), int(self.g), int(self.b))
188
+ 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
189
 
184
190
  # fast operations Vector2D.operation(both,x,y)
185
191
  def add(self, all3=.0, r=.0, g=.0, b=.0) -> "Color":
@@ -408,6 +414,8 @@ class Color:
408
414
  except:
409
415
  raise TypeError(f"The value {other} of type {type(other)} is not a num type: [{int|float}] nor an array type: [{list|tuple}]")
410
416
 
417
+ @classmethod
418
+ def transparent(cls) -> "Color": return Color(0,0,0,0, mode=RGBA_COLOR_MODE)
411
419
  @classmethod
412
420
  def white(cls) -> "Color": return Color(255,255,255)
413
421
  @classmethod
@@ -427,12 +435,14 @@ class Color:
427
435
  return Color(__randint__(0,255), __randint__(0,255), __randint__(0,255))
428
436
 
429
437
 
438
+ TRANSPARENT_COLOR = Color.transparent()
430
439
  WHITE_COLOR = Color.white()
431
440
  BLACK_COLOR = Color.black()
432
441
  RED_COLOR = Color.red()
433
442
  GREEN_COLOR = Color.green()
434
443
  BLUE_COLOR = Color.blue()
435
444
 
445
+ TRANSPARENT_COLOR_PYG = TRANSPARENT_COLOR()
436
446
  WHITE_COLOR_PYG = WHITE_COLOR()
437
447
  BLACK_COLOR_PYG = BLACK_COLOR()
438
448
  RED_COLOR_PYG = RED_COLOR()
@@ -59,12 +59,21 @@ class RootEnv:
59
59
  self.current_frame = 0
60
60
  self.show_fps = show_fps
61
61
  self.events :list[pg.event.Event]= []
62
- self.background_color = BLACK_COLOR_PYG
62
+
63
+ self.__background_color__ :Color= BLACK_COLOR_PYG
64
+
63
65
  self.clear_screen_each_frame = clear_screen_each_frame
64
66
  self.utils :dict[int|str, Util]= {}
65
67
  self.selected_util :Util|None = None
66
68
  self.__quit_on_key_pressed__ = quit_on_key_pressed
67
69
 
70
+ @property
71
+ def background_color(self) -> Color:
72
+ return unpygamize_color(self.__background_color__)
73
+ @background_color.setter
74
+ def background_color(self, color: Color|pg.Color) -> None:
75
+ self.__background_color__ = pygamize_color(color)
76
+
68
77
  @property
69
78
  def screen_size(self) -> Vector2D:
70
79
  return self.__screen_size__
@@ -76,7 +85,7 @@ class RootEnv:
76
85
 
77
86
  @property
78
87
  def delta(self) -> int:
79
- return self.clock.get_time()
88
+ return self.clock.get_time() / 1000
80
89
 
81
90
  def get_teoric_max_fps(self) -> float:
82
91
  rawdelta = self.clock.get_rawtime()
@@ -96,6 +105,8 @@ class RootEnv:
96
105
  for util in utils:
97
106
  if util.surface == None: util.surface = self.screen
98
107
  util.rootEnv = self
108
+ util.id = self.__new_util_id__()
109
+ util.render()
99
110
  self.utils[util.id] = util
100
111
 
101
112
  def remove_utils(self, *utils:int|str|Util) -> None:
@@ -106,6 +117,18 @@ class RootEnv:
106
117
  del self.utils[uid.id]
107
118
  else:
108
119
  raise Exception(f"Unknown util type: {uid}")
120
+
121
+ def __new_util_id__(self) -> int:
122
+ if not self.utils: return 0
123
+ else: return max(self.utils.keys()) + 1
124
+
125
+ def get_util(self, uid:int|str) -> Util|None:
126
+ if isinstance(uid, Util):
127
+ return self.utils.get(uid.id)
128
+ elif isinstance(uid, int) or isinstance(uid, str):
129
+ return self.utils.get(uid)
130
+ else:
131
+ raise Exception(f"Unknown util type: {uid}")
109
132
 
110
133
  @property
111
134
  def runtime_seconds(self) -> float:
@@ -115,24 +138,25 @@ class RootEnv:
115
138
  self.env = sub_env
116
139
 
117
140
  def clear(self) -> None:
118
- self.screen.fill(self.background_color)
141
+ self.screen.fill(self.__background_color__)
119
142
 
120
143
  def clear_rect(self, position:Vector2D, size:Vector2D) -> None:
121
- self.screen.fill(self.background_color, position() + size())
144
+ self.screen.fill(self.__background_color__, position() + size())
122
145
 
123
146
  def print(self,
124
- text : str,
125
- position : Vector2D,
126
- color : pg.Color = WHITE_COLOR_PYG,
127
- pivot_position : __LITERAL_PIVOT_POSITIONS__ = "top_left",
128
- font : pg.font.Font = FONT_ARIAL_32,
129
- bg_color : None|pg.Color = None,
130
- border_color : pg.Color = WHITE_COLOR_PYG,
131
- border_width : float = 0.0,
132
- border_radius : int|list[int]|tuple[int,int,int,int] = -1,
133
- margin : Vector2D = Vector2D.zero(),
134
- personalized_surface : pg.Surface|None = None
147
+ text : str,
148
+ position : Vector2D,
149
+ color : pg.color.Color = WHITE_COLOR_PYG,
150
+ pivot_position : __LITERAL_PIVOT_POSITIONS__ = "top_left",
151
+ font : pg.font.Font = FONT_ARIAL_32,
152
+ bg_color : None|pg.color.Color = None,
153
+ border_color : pg.color.Color = WHITE_COLOR_PYG,
154
+ border_width : float = 0.0,
155
+ border_radius : int|list[int]|tuple[int,int,int,int] = -1,
156
+ margin : Vector2D = Vector2D.zero(),
157
+ personalized_surface : pg.Surface|None = None
135
158
  ) -> None:
159
+
136
160
  text_box = font.render(text, True, color)
137
161
  size = Vector2D(*text_box.get_size()) + margin * 2
138
162
  pivotted_position = position - size * __PIVOT_POSITIONS_MULTIPLIER__[pivot_position] + margin
@@ -0,0 +1,545 @@
1
+ from __future__ import annotations
2
+ from typing import Any, Callable, Literal
3
+ import pygame as pg
4
+ from e2D import *
5
+ from e2D.colors import *
6
+
7
+ import math as _mt
8
+
9
+ pg.font.init()
10
+
11
+ __KEY_MODE_TYPES_DICT__ = dict(zip(["pressed", "just_pressed", "just_released"], range(3)))
12
+ __LITERAL_KEY_MODE_TYPES__ = Literal["pressed", "just_pressed", "just_released"]
13
+
14
+ __LITERAL_FONTS__ = Literal['arial', 'arialblack', 'bahnschrift', 'calibri', 'cambria', 'cambriamath', 'candara', 'comicsansms', 'consolas', 'constantia', 'corbel', 'couriernew', 'ebrima', 'franklingothicmedium', 'gabriola', 'gadugi', 'georgia', 'impact', 'inkfree', 'javanesetext', 'leelawadeeui', 'leelawadeeuisemilight', 'lucidaconsole', 'lucidasans', 'malgungothic', 'malgungothicsemilight', 'microsofthimalaya', 'microsoftjhenghei', 'microsoftjhengheiui', 'microsoftnewtailue', 'microsoftphagspa', 'microsoftsansserif', 'microsofttaile', 'microsoftyahei', 'microsoftyaheiui', 'microsoftyibaiti', 'mingliuextb', 'pmingliuextb', 'mingliuhkscsextb', 'mongolianbaiti', 'msgothic', 'msuigothic', 'mspgothic', 'mvboli', 'myanmartext', 'nirmalaui', 'nirmalauisemilight', 'palatinolinotype', 'segoemdl2assets', 'segoeprint', 'segoescript', 'segoeui', 'segoeuiblack', 'segoeuiemoji', 'segoeuihistoric', 'segoeuisemibold', 'segoeuisemilight', 'segoeuisymbol', 'simsun', 'nsimsun', 'simsunextb', 'sitkasmall', 'sitkatext', 'sitkasubheading', 'sitkaheading', 'sitkadisplay', 'sitkabanner', 'sylfaen', 'symbol', 'tahoma', 'timesnewroman', 'trebuchetms', 'verdana', 'webdings', 'wingdings', 'yugothic', 'yugothicuisemibold', 'yugothicui', 'yugothicmedium', 'yugothicuiregular', 'yugothicregular', 'yugothicuisemilight', 'holomdl2assets', 'bizudgothic', 'bizudpgothictruetype', 'bizudminchomedium', 'bizudpminchomediumtruetype', 'meiryo', 'meiryoui', 'msmincho', 'mspmincho', 'uddigikyokashonb', 'uddigikyokashonpb', 'uddigikyokashonkb', 'uddigikyokashonr', 'uddigikyokashonpr', 'uddigikyokashonkr', 'yumincho', 'lcd', 'glassgauge', 'maiandragd', 'maiandragddemi', 'newsgothic', 'quartz', 'kievitoffcpro', 'agencyfbgrassetto', 'agencyfb', 'algerian', 'bookantiquagrassetto', 'bookantiquagrassettocorsivo', 'bookantiquacorsivo', 'arialcorsivo', 'arialrounded', 'baskervilleoldface', 'bauhaus93', 'bell', 'bellgrassetto', 'bellcorsivo', 'bernardcondensed', 'bookantiqua', 'bodonigrassetto', 'bodonigrassettocorsivo', 'bodoniblackcorsivo', 'bodoniblack', 'bodonicondensedgrassetto', 'bodonicondensedgrassettocorsivo', 'bodonicondensedcorsivo', 'bodonicondensed', 'bodonicorsivo', 'bodonipostercompressed', 'bodoni', 'bookmanoldstyle', 'bookmanoldstylegrassetto', 'bookmanoldstylegrassettocorsivo', 'bookmanoldstylecorsivo', 'bradleyhanditc', 'britannic', 'berlinsansfbgrassetto', 'berlinsansfbdemigrassetto', 'berlinsansfb', 'broadway', 'brushscriptcorsivo', 'bookshelfsymbol7', 'californianfbgrassetto', 'californianfbcorsivo', 'californianfb', 'calisto', 'calistograssetto', 'calistograssettocorsivo', 'calistocorsivo', 'castellar', 'centuryschoolbook', 'centaur', 'century', 'chiller', 'colonna', 'cooperblack', 'copperplategothic', 'curlz', 'dubai', 'dubaimedium', 'dubairegular', 'elephant', 'elephantcorsivo', 'engravers', 'erasitc', 'erasdemiitc', 'erasmediumitc', 'felixtitling', 'forte', 'franklingothicbook', 'franklingothicbookcorsivo', 'franklingothicdemi', 'franklingothicdemicond', 'franklingothicdemicorsivo', 'franklingothicheavy', 'franklingothicheavycorsivo', 'franklingothicmediumcond', 'freestylescript', 'frenchscript', 'footlight', 'garamond', 'garamondgrassetto', 'garamondcorsivo', 'gigi', 'gillsansgrassettocorsivo', 'gillsansgrassetto', 'gillsanscondensed', 'gillsanscorsivo', 'gillsansultracondensed', 'gillsansultra', 'gillsans', 'gloucesterextracondensed', 'gillsansextcondensed', 'centurygothic', 'centurygothicgrassetto', 'centurygothicgrassettocorsivo', 'centurygothiccorsivo', 'goudyoldstyle', 'goudyoldstylegrassetto', 'goudyoldstylecorsivo', 'goudystout', 'harlowsolid', 'harrington', 'haettenschweiler', 'hightowertext', 'hightowertextcorsivo', 'imprintshadow', 'informalroman', 'blackadderitc', 'kristenitc', 'jokerman', 'juiceitc', 'kunstlerscript', 'widelatin', 'lucidabright', 'lucidacalligraphy', 'leelawadee', 'leelawadeegrassetto', 'lucidafax', 'lucidafaxdemigrassetto', 'lucidafaxdemigrassettocorsivo', 'lucidafaxcorsivo', 'lucidahandwritingcorsivo', 'lucidasansdemigrassetto', 'lucidasansdemigrassettocorsivo', 'lucidasanscorsivo', 'lucidasanstypewriter', 'lucidasanstypewritergrassetto', 'lucidasanstypewritergrassettooblique', 'lucidasanstypewriteroblique', 'magnetograssetto', 'maturascriptcapitals', 'mistral', 'modernno20', 'microsoftuighurgrassetto', 'microsoftuighur', 'monotypecorsiva', 'extra', 'niagaraengraved', 'niagarasolid', 'ocraextended', 'oldenglishtext', 'onyx', 'msoutlook', 'palacescript', 'papyrus', 'parchment', 'perpetuagrassettocorsivo', 'perpetuagrassetto', 'perpetuacorsivo', 'perpetuatitlinggrassetto', 'perpetuatitlingchiarissimo', 'perpetua', 'playbill', 'poorrichard', 'pristina', 'rage', 'ravie', 'msreferencesansserif', 'msreferencespecialty', 'rockwellcondensedgrassetto', 'rockwellcondensed', 'rockwell', 'rockwellgrassetto', 'rockwellgrassettocorsivo', 'rockwellextra', 'rockwellcorsivo', 'centuryschoolbookgrassetto', 'centuryschoolbookgrassettocorsivo', 'centuryschoolbookcorsivo', 'script', 'showcardgothic', 'snapitc', 'stencil', 'twcengrassettocorsivo', 'twcengrassetto', 'twcencondensedgrassetto', 'twcencondensedextra', 'twcencondensed', 'twcencorsivo', 'twcen', 'tempussansitc', 'vinerhanditc', 'vivaldicorsivo', 'vladimirscript', 'wingdings2', 'wingdings3', 'cascadiacoderegular', 'cascadiamonoregular', 'edwardianscriptitcnormale', 'stoneharbourregular', 'mregular', 'xirodregular', 'minecraft']
15
+
16
+ def NEW_FONT(size, name:__LITERAL_FONTS__="arial", bold:bool=False, italic:bool=False) -> pg.font.Font:
17
+ return pg.font.SysFont(name, size, bold, italic)
18
+ FONT_ARIAL_16 = NEW_FONT(16)
19
+ FONT_ARIAL_32 = NEW_FONT(32)
20
+ FONT_ARIAL_64 = NEW_FONT(64)
21
+
22
+
23
+ __LITERAL_PIVOT_POSITIONS__ = Literal["top_left", "top_center", "top_right", "center_left", "center_center", "center_right", "bottom_left", "bottom_center", "bottom_right"]
24
+ __PIVOT_POSITIONS_MULTIPLIER__ = dict(zip(("top_left", "top_center", "top_right", "center_left", "center_center", "center_right", "bottom_left", "bottom_center", "bottom_right"), (Vector2D(x,y) for y in [0, .5, 1] for x in [0, .5, 1])))
25
+
26
+
27
+ # INPUT_CELL_ASCII_TYPE = 0
28
+ # INPUT_CELL_ALPHANUM_TYPE = 1
29
+ # INPUT_CELL_ALPHA_TYPE = 2
30
+ # INPUT_CELL_NUM_TYPE = 3
31
+ # LITERAL_INPUT_CELL_TYPES = Literal[0,1,2,3]
32
+
33
+ class Mouse:
34
+ def __init__(self, parent) -> None:
35
+ self.parent = parent
36
+ self.__last_frame_position_count__ = 0
37
+ self.__last_frame_position__ = Vector2D.new_zero()
38
+ self.__last_frame_movement_count__ = 0
39
+ self.__last_frame_movement__ = Vector2D.new_zero()
40
+
41
+ self.__pressed__ : tuple[bool, bool, bool] = (False, False, False)
42
+ self.update()
43
+
44
+ @property
45
+ def position(self) -> Vector2D:
46
+ if self.__last_frame_position_count__ != self.parent.current_frame:
47
+ self.__last_frame_position__ = Vector2D(*pg.mouse.get_pos())
48
+ self.__last_frame_position_count__ = self.parent.current_frame
49
+ return self.__last_frame_position__
50
+ @position.setter
51
+ def position(self, new_position:Vector2D) -> None:
52
+ self.__last_frame_position_count__ = self.parent.current_frame
53
+ self.__last_frame_position__ = new_position
54
+ pg.mouse.set_pos(self.__last_frame_position__())
55
+
56
+ @property
57
+ def last_frame_movement(self) -> Vector2D:
58
+ if self.__last_frame_movement_count__ != self.parent.current_frame:
59
+ self.__last_frame_movement__ = Vector2D(*pg.mouse.get_rel())
60
+ self.__last_frame_movement_count__ = self.parent.current_frame
61
+ return self.__last_frame_movement__
62
+
63
+ def update(self) -> None:
64
+ self.__last_pressed__ = self.__pressed__
65
+ self.__pressed__ = pg.mouse.get_pressed()
66
+
67
+ def get_key(self, button_id:Literal[0,1,2]=0, mode:__LITERAL_KEY_MODE_TYPES__="pressed") -> bool:
68
+ if mode == "pressed":
69
+ return self.__pressed__[button_id]
70
+ elif mode == "just_pressed":
71
+ return self.__pressed__[button_id] and (not self.__last_pressed__[button_id])
72
+ elif mode == "just_released":
73
+ return (not self.__pressed__[button_id]) and self.__last_pressed__[button_id]
74
+ else:
75
+ raise Exception(f"Unknown mode type: {mode}")
76
+
77
+ class Keyboard:
78
+ def __init__(self) -> None:
79
+ self.__pressed__ :pg.key.ScancodeWrapper= pg.key.get_pressed()
80
+ self.update()
81
+
82
+ def update(self) -> None:
83
+ self.__last_pressed__ = self.__pressed__
84
+ self.__pressed__ = pg.key.get_pressed()
85
+
86
+ def get_key(self, scan_code:int, mode:__LITERAL_KEY_MODE_TYPES__="pressed") -> bool:
87
+ if mode == "pressed":
88
+ return self.__pressed__[scan_code]
89
+ elif mode == "just_pressed":
90
+ return self.__pressed__[scan_code] and (not self.__last_pressed__[scan_code])
91
+ elif mode == "just_released":
92
+ return (not self.__pressed__[scan_code]) and self.__last_pressed__[scan_code]
93
+ else:
94
+ raise Exception(f"Unknown mode type: {mode}")
95
+
96
+ class Util:
97
+ def __init__(self) -> None:
98
+ self.rootEnv = None
99
+ self.surface : pg.Surface = pg.SurfaceType
100
+ self.id : int|str
101
+ self.is_hovered :bool= False
102
+ self.hidden :bool= False
103
+ def hide(self) -> None:
104
+ self.hidden = True
105
+ def show(self) -> None:
106
+ self.hidden = False
107
+ def render(self) -> None: pass
108
+ def draw(self) -> None: pass
109
+ def update(self) -> None: pass
110
+
111
+ class InputCell(Util):
112
+ def __init__(self,
113
+ initial_value : str,
114
+ position : Vector2D,
115
+ size : Vector2D,
116
+ prefix : str|None = None,
117
+ text_color : Color|pg.Color = Color.white(),
118
+ bg_color : None|Color|pg.Color = None,
119
+ border_color : Color|pg.Color = Color.white(),
120
+ border_width : float = 0,
121
+ border_radius : int|list[int]|tuple[int,int,int,int] = -1,
122
+ margin : Vector2D = Vector2D.zero(),
123
+ pivot_position : __LITERAL_PIVOT_POSITIONS__ = "center_center",
124
+ font : pg.font.Font = FONT_ARIAL_32,
125
+ personalized_surface : pg.Surface|None = None,
126
+ on_enter_pressed : Callable[[str], Any] = lambda full_text: ...,
127
+ check_when_adding : Callable[[str], str] = lambda new_text: new_text,
128
+ ) -> None:
129
+ super().__init__()
130
+
131
+ self.value = initial_value
132
+
133
+ # size = Vector2D(*self.text_box.get_size()) + self.margin * 2
134
+ self.size = size
135
+ self.position = (position - size * __PIVOT_POSITIONS_MULTIPLIER__[pivot_position] + margin)
136
+
137
+ self.prefix = prefix if prefix != None else ""
138
+
139
+ self.font = font
140
+
141
+ self.bg_rect = [0, 0] + size()
142
+
143
+ self.border_radius = [border_radius]*4 if not any(isinstance(border_radius, cls) for cls in {tuple, list}) else border_radius
144
+ self.border_width = border_width
145
+
146
+ self.margin_rect = (margin * -1)() + size()
147
+
148
+ self.on_enter_pressed = on_enter_pressed
149
+ self.check_when_adding = check_when_adding
150
+
151
+ self.update_text()
152
+
153
+ self.surface = personalized_surface
154
+ self.text_surface = pg.Surface(self.size(), pg.SRCALPHA, 32).convert_alpha()
155
+
156
+ self.text_color = text_color
157
+ self.bg_color = bg_color
158
+ self.border_color = border_color
159
+
160
+ @property
161
+ def text_color(self) -> Color:
162
+ return unpygamize_color(self.__text_color__)
163
+ @text_color.setter
164
+ def text_color(self, new_color:Color|pg.Color) -> None:
165
+ self.__text_color__ = pygamize_color(new_color)
166
+ @property
167
+ def bg_color(self) -> Color|None:
168
+ return unpygamize_color(self.__bg_color__) if self.__bg_color__ else None
169
+ @bg_color.setter
170
+ def bg_color(self, new_color:Color|pg.Color|None) -> None:
171
+ self.__bg_color__ = pygamize_color(new_color) if new_color else None
172
+ @property
173
+ def border_color(self) -> Color:
174
+ return unpygamize_color(self.__border_color__)
175
+ @border_color.setter
176
+ def border_color(self, new_color:Color|pg.Color) -> None:
177
+ self.__border_color__ = pygamize_color(new_color)
178
+
179
+ def draw(self) -> None:
180
+ if self.hidden: return
181
+ self.text_surface.fill(TRANSPARENT_COLOR_PYG)
182
+
183
+ if self.__bg_color__ is not None:
184
+ pg.draw.rect(self.text_surface, self.__bg_color__(), self.bg_rect, 0, -1, *self.border_radius)
185
+
186
+ self.text_surface.blit(self.text_box, self.text_position())
187
+
188
+ if self.rootEnv.selected_util != self:
189
+ if self.border_width:
190
+ pg.draw.rect(self.text_surface, self.__border_color__(), self.margin_rect, self.border_width, -1, *self.border_radius)
191
+ else:
192
+ k = 127.5 + 127.5 * _mt.sin(self.rootEnv.runtime_seconds * 10)
193
+ pg.draw.rect(self.text_surface, pg.Color(k, k, k), self.margin_rect, self.border_width if self.border_width else 10, -1, *self.border_radius)
194
+
195
+ self.surface.blit(self.text_surface, self.position())
196
+
197
+ def update(self) -> None:
198
+ if self.hidden: return
199
+ self.is_hovered = self.position.x < self.rootEnv.mouse.position.x < self.position.x + self.size.x and\
200
+ self.position.y < self.rootEnv.mouse.position.y < self.position.y + self.size.y
201
+
202
+ if self.rootEnv.mouse.get_key(0, "just_pressed"):
203
+ if self.is_hovered:
204
+ self.rootEnv.selected_util = self if self.rootEnv.selected_util != self else None
205
+ self.update_text()
206
+
207
+ if self.rootEnv.selected_util == self:
208
+ for event in self.rootEnv.events:
209
+ if event.type == pg.TEXTINPUT:
210
+ self.value += self.check_when_adding(event.text)
211
+ elif event.type == pg.KEYDOWN and event.key == pg.K_BACKSPACE:
212
+ self.value = self.value[:-1]
213
+ if self.rootEnv.keyboard.get_key(pg.K_DELETE):
214
+ self.value = self.value[:-1]
215
+ if self.rootEnv.keyboard.get_key(pg.K_RETURN, "just_pressed"):
216
+ self.on_enter_pressed(self.value)
217
+ if self.rootEnv.keyboard.get_key(pg.K_ESCAPE, "just_pressed"):
218
+ self.rootEnv.selected_util = self if self.rootEnv.selected_util != self else None
219
+ self.update_text()
220
+
221
+ def update_text(self) -> None:
222
+ self.text_box = self.font.render(self.prefix + self.value, True, self.__text_color__())
223
+ if self.rootEnv != None and self.rootEnv.selected_util == self:
224
+ # self.text_position = self.position + self.size * Vector2D(.85, .5) - Vector2D(*self.text_box.get_size()) * Vector2D(1, .5) - self.position
225
+ self.text_position = self.position + self.size * .5 - Vector2D(*self.text_box.get_size()) * Vector2D(.5, .5) - self.position
226
+ else:
227
+ self.text_position = self.position + self.size * .5 - Vector2D(*self.text_box.get_size()) * Vector2D(.5, .5) - self.position
228
+
229
+ class Slider(Util):
230
+ def __init__(self,
231
+ text : str,
232
+ position : Vector2D,
233
+ size : Vector2D,
234
+ min_value : float = 0,
235
+ max_value : float = 100,
236
+ step : float = 1,
237
+ color : Color|pg.Color = Color(200, 200, 200),
238
+ handleColour : Color|pg.Color = Color.white(),
239
+ initial_value : float = 0,
240
+ rounded : bool = True,
241
+ handleRadius : float = 10,
242
+ text_offset : V2 = V2(1.1, .5),
243
+ text_pivot : __LITERAL_PIVOT_POSITIONS__ = "center_center",
244
+ personalized_surface : pg.Surface|None = None,
245
+ ) -> None:
246
+ super().__init__()
247
+
248
+ self.text = text
249
+ self.selected = False
250
+ self.min = min_value
251
+ self.max = max_value
252
+ self.step = step
253
+
254
+ self.position = position
255
+ self.size = size
256
+
257
+ self.value = clamp(initial_value, self.min, self.max)
258
+
259
+ self.radius = self.size.y // 2 if rounded else 0
260
+ self.text_offset = text_offset
261
+ self.text_pivot = text_pivot
262
+
263
+ self.handleRadius = handleRadius
264
+ self.surface = personalized_surface
265
+
266
+ self.hidden = False
267
+
268
+ self.color = color
269
+ self.handleColour = handleColour
270
+
271
+ @property
272
+ def color(self) -> Color:
273
+ return unpygamize_color(self.__color__)
274
+ @color.setter
275
+ def color(self, new_color:Color|pg.Color) -> None:
276
+ self.__color__ = pygamize_color(new_color)
277
+ @property
278
+ def handleColour(self) -> Color:
279
+ return unpygamize_color(self.__handleColour__)
280
+ @handleColour.setter
281
+ def handleColour(self, new_color:Color|pg.Color) -> None:
282
+ self.__handleColour__ = pygamize_color(new_color)
283
+
284
+ def draw(self) -> None:
285
+ if self.hidden: return
286
+ pg.draw.rect(self.rootEnv.screen, self.__color__, self.position() + self.size())
287
+
288
+ if self.radius:
289
+ pg.draw.circle(self.rootEnv.screen, self.__color__, (self.position.x, self.position.y + self.size.y // 2), self.radius)
290
+ pg.draw.circle(self.rootEnv.screen, self.__color__, (self.position.x + self.size.x, self.position.y + self.size.y // 2), self.radius)
291
+
292
+ circle = V2(int(self.position.x + (self.value - self.min) / (self.max - self.min) * self.size.x), self.position.y + self.size.y // 2)
293
+
294
+ pg.draw.circle(self.rootEnv.screen, self.__color__, circle(), self.handleRadius * 1.25)
295
+ pg.draw.circle(self.rootEnv.screen, self.__handleColour__, circle(), self.handleRadius)
296
+ self.rootEnv.print(self.text.format(round(self.value, 2)), self.position + self.size * self.text_offset, pivot_position=self.text_pivot)
297
+
298
+ def update(self) -> None:
299
+ if self.hidden: return
300
+ x,y = self.rootEnv.mouse.position
301
+
302
+ if self.rootEnv.mouse.get_key(0, "just_pressed") and self.__contains__(x, y):
303
+ self.rootEnv.selected_util = self
304
+ elif self.rootEnv.mouse.get_key(0, "just_released"):
305
+ self.rootEnv.selected_util = None
306
+
307
+ if self.rootEnv.selected_util == self:
308
+ new_value = (x - self.position.x) / self.size.x * self.max + self.min
309
+ self.value = clamp(new_value, self.min, self.max)
310
+
311
+ def __contains__(self, x, y) -> bool:
312
+ handleX = self.position.x + (self.value - self.min) / (self.max - self.min) * self.size.x
313
+ handleY = self.position.y + self.size.y // 2
314
+ return (handleX - x) ** 2 + (handleY - y) ** 2 <= self.handleRadius ** 2
315
+
316
+ def setValue(self, value) -> None:
317
+ self.value = clamp(value, self.min, self.max)
318
+
319
+ def getValue(self) -> float:
320
+ return self.value
321
+
322
+ class Button(Util):
323
+ def __init__(self,
324
+ text : str,
325
+ position : V2|Vector2D,
326
+ size : V2|Vector2D,
327
+ callback : Callable[[...], None]|Callable[[], None],
328
+ default_color : Color|pg.Color,
329
+ hovered_color : Color|pg.Color,
330
+ border_color : Color|pg.Color,
331
+ text_color : Color|pg.Color = WHITE_COLOR_PYG,
332
+ font : pg.font.Font = FONT_ARIAL_32,
333
+ border_radius : float = 10,
334
+ border_width : float = 10,
335
+ starting_hiddden : bool = False,
336
+ args : list = [],
337
+ activation_mode : __LITERAL_KEY_MODE_TYPES__ = "just_pressed",
338
+ pivot_position : __LITERAL_PIVOT_POSITIONS__ = "top_left",
339
+ personalized_surface : pg.Surface|None = None,
340
+ ) -> None:
341
+ super().__init__()
342
+
343
+ self.text = text
344
+ self.font = font
345
+
346
+ self.callback = callback
347
+
348
+ self.border_radius = border_radius
349
+ self.__size__ = size
350
+ self.__border_width__ = border_width
351
+
352
+ self.update_position(position, pivot_position)
353
+
354
+ self.hidden = starting_hiddden
355
+ self.args = args
356
+
357
+ self.activation_mode = activation_mode
358
+
359
+ self.hovered = False
360
+
361
+ self.text_color = text_color
362
+ self.default_color = default_color
363
+ self.border_color = border_color
364
+ self.hovered_color = hovered_color
365
+
366
+ self.surface = personalized_surface
367
+ self.update_surface()
368
+
369
+ def update_position(self, new_position:V2, pivot_position:__LITERAL_PIVOT_POSITIONS__="top_left") -> None:
370
+ self.position = new_position - (self.__size__ + self.border_width * 2) * __PIVOT_POSITIONS_MULTIPLIER__[pivot_position]
371
+
372
+ def update_surface(self, render=False) -> None:
373
+ self.buffer_surface = pg.Surface((self.__size__ + self.__border_width__ * 2)(), pg.SRCALPHA, 32).convert_alpha()
374
+ if render: self.render()
375
+
376
+ @property
377
+ def size(self) -> V2:
378
+ return self.__size__
379
+ @size.setter
380
+ def size(self, new_size:V2|Vector2D) -> None:
381
+ self.__size__ = new_size
382
+ self.update_surface(render=True)
383
+
384
+ @property
385
+ def border_width(self) -> float:
386
+ return self.__border_width__
387
+ @border_width.setter
388
+ def border_width(self, new_width:float) -> None:
389
+ self.__border_width__ = new_width
390
+ self.update_surface(render=True)
391
+
392
+ @property
393
+ def text_color(self) -> Color:
394
+ return unpygamize_color(self.__text_color__)
395
+ @text_color.setter
396
+ def text_color(self, new_color:Color|pg.Color) -> None:
397
+ self.__text_color__ = pygamize_color(new_color)
398
+ @property
399
+ def default_color(self) -> Color:
400
+ return unpygamize_color(self.__default_color__)
401
+ @default_color.setter
402
+ def default_color(self, new_color:Color|pg.Color) -> None:
403
+ self.__default_color__ = pygamize_color(new_color)
404
+ @property
405
+ def border_color(self) -> Color:
406
+ return unpygamize_color(self.__border_color__)
407
+ @border_color.setter
408
+ def border_color(self, new_color:Color|pg.Color) -> None:
409
+ self.__border_color__ = pygamize_color(new_color)
410
+ @property
411
+ def hovered_color(self) -> Color:
412
+ return unpygamize_color(self.__hovered_color__)
413
+ @hovered_color.setter
414
+ def hovered_color(self, new_color:Color|pg.Color) -> None:
415
+ self.__hovered_color__ = pygamize_color(new_color)
416
+
417
+ def render(self) -> None:
418
+ print("rendering button")
419
+ self.buffer_surface.fill(TRANSPARENT_COLOR_PYG)
420
+
421
+ color = self.__hovered_color__ if self.hovered else self.__default_color__
422
+ pg.draw.rect(self.buffer_surface, self.__border_color__, V2.zero()() + (self.size + self.border_width * 2)(), border_radius=self.border_radius)
423
+ pg.draw.rect(self.buffer_surface, color, (V2.zero() + self.border_width)() + self.size(), border_radius=self.border_radius)
424
+
425
+ self.rootEnv.print(self.text, self.border_width + self.size * .5, color=self.__text_color__, font=self.font, pivot_position="center_center", personalized_surface=self.buffer_surface)
426
+
427
+ def draw(self) -> None:
428
+ if self.hidden: return
429
+ self.surface.blit(self.buffer_surface, (self.position)())
430
+
431
+ def update(self) -> None:
432
+ if self.hidden: return
433
+
434
+ old_overed = self.hovered
435
+ self.hovered = \
436
+ self.position.x < self.rootEnv.mouse.position.x < self.position.x + self.size.x and \
437
+ self.position.y < self.rootEnv.mouse.position.y < self.position.y + self.size.y
438
+ if self.hovered != old_overed:
439
+ self.render()
440
+
441
+ if self.hovered and self.rootEnv.mouse.get_key(0, self.activation_mode):
442
+ self.callback(*self.args)
443
+ self.rootEnv.selected_util = self
444
+ self.render()
445
+ elif self.rootEnv.selected_util == self:
446
+ self.rootEnv.selected_util = None
447
+ self.render()
448
+
449
+ class Label(Util):
450
+ def __init__(self,
451
+ text : str,
452
+ position : V2|Vector2D,
453
+ size : V2|Vector2D,
454
+ default_color : Color|pg.Color = TRANSPARENT_COLOR_PYG,
455
+ border_color : Color|pg.Color = WHITE_COLOR_PYG,
456
+ text_color : Color|pg.Color = WHITE_COLOR_PYG,
457
+ font : pg.font.Font = FONT_ARIAL_32,
458
+ border_radius : float = 10,
459
+ border_width : float = 10,
460
+ starting_hiddden : bool = False,
461
+ personalized_surface : pg.Surface|None = None,
462
+ pivot_position : __LITERAL_PIVOT_POSITIONS__ = "top_left",
463
+ ) -> None:
464
+ super().__init__()
465
+
466
+ self.__text__ = text
467
+ self.font = font
468
+
469
+ self.border_radius = border_radius
470
+ self.__size__ = size
471
+ self.__border_width__ = border_width
472
+
473
+ self.position = self.update_position(position, pivot_position)
474
+
475
+ self.hidden = starting_hiddden
476
+
477
+ self.text_color = text_color
478
+ self.default_color = default_color
479
+ self.border_color = border_color
480
+
481
+ self.surface = personalized_surface
482
+ self.update_surface()
483
+
484
+ def update_position(self, new_position:V2, pivot_position:__LITERAL_PIVOT_POSITIONS__="top_left") -> None:
485
+ self.position = new_position - (self.__size__ + self.border_width * 2) * __PIVOT_POSITIONS_MULTIPLIER__[pivot_position]
486
+
487
+ def update_surface(self, render=False) -> None:
488
+ self.buffer_surface = pg.Surface((self.__size__ + self.__border_width__ * 2)(), pg.SRCALPHA, 32).convert_alpha()
489
+ if render: self.render()
490
+
491
+ @property
492
+ def text(self) -> str:
493
+ return self.__text__
494
+ @text.setter
495
+ def text(self, new_text:str) -> None:
496
+ self.__text__ = new_text
497
+ self.render()
498
+
499
+ @property
500
+ def size(self) -> V2:
501
+ return self.__size__
502
+ @size.setter
503
+ def size(self, new_size:V2|Vector2D) -> None:
504
+ self.__size__ = new_size
505
+ self.update_surface(render=True)
506
+
507
+ @property
508
+ def border_width(self) -> float:
509
+ return self.__border_width__
510
+ @border_width.setter
511
+ def border_width(self, new_width:float) -> None:
512
+ self.__border_width__ = new_width
513
+ self.update_surface(render=True)
514
+
515
+ @property
516
+ def text_color(self) -> Color:
517
+ return unpygamize_color(self.__text_color__)
518
+ @text_color.setter
519
+ def text_color(self, new_color:Color|pg.Color) -> None:
520
+ self.__text_color__ = pygamize_color(new_color)
521
+ @property
522
+ def default_color(self) -> Color:
523
+ return unpygamize_color(self.__default_color__)
524
+ @default_color.setter
525
+ def default_color(self, new_color:Color|pg.Color) -> None:
526
+ self.__default_color__ = pygamize_color(new_color)
527
+ @property
528
+ def border_color(self) -> Color:
529
+ return unpygamize_color(self.__border_color__)
530
+ @border_color.setter
531
+ def border_color(self, new_color:Color|pg.Color) -> None:
532
+ self.__border_color__ = pygamize_color(new_color)
533
+
534
+ def render(self) -> None:
535
+ print("rendering label")
536
+ self.buffer_surface.fill(TRANSPARENT_COLOR_PYG)
537
+
538
+ pg.draw.rect(self.buffer_surface, self.__border_color__, V2.zero()() + (self.size + self.border_width * 2)(), border_radius=self.border_radius)
539
+ pg.draw.rect(self.buffer_surface, self.__default_color__, (V2.zero() + self.border_width)() + self.size(), border_radius=self.border_radius)
540
+
541
+ self.rootEnv.print(self.text, self.border_width + self.size * .5, color=self.__text_color__, font=self.font, pivot_position="center_center", personalized_surface=self.buffer_surface)
542
+
543
+ def draw(self) -> None:
544
+ if self.hidden: return
545
+ self.surface.blit(self.buffer_surface, (self.position)())
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: e2D
3
- Version: 1.4.18
3
+ Version: 1.4.20
4
4
  Summary: Python library for 2D games. Streamlines dev with keyboard/mouse input, vector calculations, color manipulation, and collision detection. Simplify game creation and unleash creativity!
5
5
  Home-page: https://github.com/marick-py/e2D
6
6
  Author: Riccardo Mariani
@@ -13,6 +13,7 @@ Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
14
  Requires-Dist: numpy
15
15
  Requires-Dist: pygame
16
+ Dynamic: license-file
16
17
 
17
18
  # e2D
18
19
  ## A Python Game Development Library
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = e2D
3
- version = 1.4.18
3
+ version = 1.4.20
4
4
  author = Riccardo Mariani
5
5
  author_email = ricomari2006@gmail.com
6
6
  description = Python library for 2D games. Streamlines dev with keyboard/mouse input, vector calculations, color manipulation, and collision detection. Simplify game creation and unleash creativity!
e2d-1.4.18/e2D/utils.py DELETED
@@ -1,191 +0,0 @@
1
- from __future__ import annotations
2
- from typing import Any, Callable, Literal
3
- import pygame as pg
4
- from e2D import *
5
- from e2D.colors import *
6
-
7
- import math as _mt
8
-
9
- pg.font.init()
10
-
11
- __KEY_MODE_TYPES_DICT__ = dict(zip(["pressed", "just_pressed", "just_released"], range(3)))
12
- __LITERAL_KEY_MODE_TYPES__ = Literal["pressed", "just_pressed", "just_released"]
13
-
14
- __LITERAL_FONTS__ = Literal['arial', 'arialblack', 'bahnschrift', 'calibri', 'cambria', 'cambriamath', 'candara', 'comicsansms', 'consolas', 'constantia', 'corbel', 'couriernew', 'ebrima', 'franklingothicmedium', 'gabriola', 'gadugi', 'georgia', 'impact', 'inkfree', 'javanesetext', 'leelawadeeui', 'leelawadeeuisemilight', 'lucidaconsole', 'lucidasans', 'malgungothic', 'malgungothicsemilight', 'microsofthimalaya', 'microsoftjhenghei', 'microsoftjhengheiui', 'microsoftnewtailue', 'microsoftphagspa', 'microsoftsansserif', 'microsofttaile', 'microsoftyahei', 'microsoftyaheiui', 'microsoftyibaiti', 'mingliuextb', 'pmingliuextb', 'mingliuhkscsextb', 'mongolianbaiti', 'msgothic', 'msuigothic', 'mspgothic', 'mvboli', 'myanmartext', 'nirmalaui', 'nirmalauisemilight', 'palatinolinotype', 'segoemdl2assets', 'segoeprint', 'segoescript', 'segoeui', 'segoeuiblack', 'segoeuiemoji', 'segoeuihistoric', 'segoeuisemibold', 'segoeuisemilight', 'segoeuisymbol', 'simsun', 'nsimsun', 'simsunextb', 'sitkasmall', 'sitkatext', 'sitkasubheading', 'sitkaheading', 'sitkadisplay', 'sitkabanner', 'sylfaen', 'symbol', 'tahoma', 'timesnewroman', 'trebuchetms', 'verdana', 'webdings', 'wingdings', 'yugothic', 'yugothicuisemibold', 'yugothicui', 'yugothicmedium', 'yugothicuiregular', 'yugothicregular', 'yugothicuisemilight', 'holomdl2assets', 'bizudgothic', 'bizudpgothictruetype', 'bizudminchomedium', 'bizudpminchomediumtruetype', 'meiryo', 'meiryoui', 'msmincho', 'mspmincho', 'uddigikyokashonb', 'uddigikyokashonpb', 'uddigikyokashonkb', 'uddigikyokashonr', 'uddigikyokashonpr', 'uddigikyokashonkr', 'yumincho', 'lcd', 'glassgauge', 'maiandragd', 'maiandragddemi', 'newsgothic', 'quartz', 'kievitoffcpro', 'agencyfbgrassetto', 'agencyfb', 'algerian', 'bookantiquagrassetto', 'bookantiquagrassettocorsivo', 'bookantiquacorsivo', 'arialcorsivo', 'arialrounded', 'baskervilleoldface', 'bauhaus93', 'bell', 'bellgrassetto', 'bellcorsivo', 'bernardcondensed', 'bookantiqua', 'bodonigrassetto', 'bodonigrassettocorsivo', 'bodoniblackcorsivo', 'bodoniblack', 'bodonicondensedgrassetto', 'bodonicondensedgrassettocorsivo', 'bodonicondensedcorsivo', 'bodonicondensed', 'bodonicorsivo', 'bodonipostercompressed', 'bodoni', 'bookmanoldstyle', 'bookmanoldstylegrassetto', 'bookmanoldstylegrassettocorsivo', 'bookmanoldstylecorsivo', 'bradleyhanditc', 'britannic', 'berlinsansfbgrassetto', 'berlinsansfbdemigrassetto', 'berlinsansfb', 'broadway', 'brushscriptcorsivo', 'bookshelfsymbol7', 'californianfbgrassetto', 'californianfbcorsivo', 'californianfb', 'calisto', 'calistograssetto', 'calistograssettocorsivo', 'calistocorsivo', 'castellar', 'centuryschoolbook', 'centaur', 'century', 'chiller', 'colonna', 'cooperblack', 'copperplategothic', 'curlz', 'dubai', 'dubaimedium', 'dubairegular', 'elephant', 'elephantcorsivo', 'engravers', 'erasitc', 'erasdemiitc', 'erasmediumitc', 'felixtitling', 'forte', 'franklingothicbook', 'franklingothicbookcorsivo', 'franklingothicdemi', 'franklingothicdemicond', 'franklingothicdemicorsivo', 'franklingothicheavy', 'franklingothicheavycorsivo', 'franklingothicmediumcond', 'freestylescript', 'frenchscript', 'footlight', 'garamond', 'garamondgrassetto', 'garamondcorsivo', 'gigi', 'gillsansgrassettocorsivo', 'gillsansgrassetto', 'gillsanscondensed', 'gillsanscorsivo', 'gillsansultracondensed', 'gillsansultra', 'gillsans', 'gloucesterextracondensed', 'gillsansextcondensed', 'centurygothic', 'centurygothicgrassetto', 'centurygothicgrassettocorsivo', 'centurygothiccorsivo', 'goudyoldstyle', 'goudyoldstylegrassetto', 'goudyoldstylecorsivo', 'goudystout', 'harlowsolid', 'harrington', 'haettenschweiler', 'hightowertext', 'hightowertextcorsivo', 'imprintshadow', 'informalroman', 'blackadderitc', 'kristenitc', 'jokerman', 'juiceitc', 'kunstlerscript', 'widelatin', 'lucidabright', 'lucidacalligraphy', 'leelawadee', 'leelawadeegrassetto', 'lucidafax', 'lucidafaxdemigrassetto', 'lucidafaxdemigrassettocorsivo', 'lucidafaxcorsivo', 'lucidahandwritingcorsivo', 'lucidasansdemigrassetto', 'lucidasansdemigrassettocorsivo', 'lucidasanscorsivo', 'lucidasanstypewriter', 'lucidasanstypewritergrassetto', 'lucidasanstypewritergrassettooblique', 'lucidasanstypewriteroblique', 'magnetograssetto', 'maturascriptcapitals', 'mistral', 'modernno20', 'microsoftuighurgrassetto', 'microsoftuighur', 'monotypecorsiva', 'extra', 'niagaraengraved', 'niagarasolid', 'ocraextended', 'oldenglishtext', 'onyx', 'msoutlook', 'palacescript', 'papyrus', 'parchment', 'perpetuagrassettocorsivo', 'perpetuagrassetto', 'perpetuacorsivo', 'perpetuatitlinggrassetto', 'perpetuatitlingchiarissimo', 'perpetua', 'playbill', 'poorrichard', 'pristina', 'rage', 'ravie', 'msreferencesansserif', 'msreferencespecialty', 'rockwellcondensedgrassetto', 'rockwellcondensed', 'rockwell', 'rockwellgrassetto', 'rockwellgrassettocorsivo', 'rockwellextra', 'rockwellcorsivo', 'centuryschoolbookgrassetto', 'centuryschoolbookgrassettocorsivo', 'centuryschoolbookcorsivo', 'script', 'showcardgothic', 'snapitc', 'stencil', 'twcengrassettocorsivo', 'twcengrassetto', 'twcencondensedgrassetto', 'twcencondensedextra', 'twcencondensed', 'twcencorsivo', 'twcen', 'tempussansitc', 'vinerhanditc', 'vivaldicorsivo', 'vladimirscript', 'wingdings2', 'wingdings3', 'cascadiacoderegular', 'cascadiamonoregular', 'edwardianscriptitcnormale', 'stoneharbourregular', 'mregular', 'xirodregular', 'minecraft']
15
-
16
- def NEW_FONT(size, name:__LITERAL_FONTS__="arial", bold:bool=False, italic:bool=False) -> pg.font.Font:
17
- return pg.font.SysFont(name, size, bold, italic)
18
- FONT_ARIAL_16 = NEW_FONT(16)
19
- FONT_ARIAL_32 = NEW_FONT(32)
20
- FONT_ARIAL_64 = NEW_FONT(64)
21
-
22
-
23
- __LITERAL_PIVOT_POSITIONS__ = Literal["top_left", "top_center", "top_right", "center_left", "center_center", "center_right", "bottom_left", "bottom_center", "bottom_right"]
24
- __PIVOT_POSITIONS_MULTIPLIER__ = dict(zip(("top_left", "top_center", "top_right", "center_left", "center_center", "center_right", "bottom_left", "bottom_center", "bottom_right"), (Vector2D(x,y) for y in [0, .5, 1] for x in [0, .5, 1])))
25
-
26
-
27
- # INPUT_CELL_ASCII_TYPE = 0
28
- # INPUT_CELL_ALPHANUM_TYPE = 1
29
- # INPUT_CELL_ALPHA_TYPE = 2
30
- # INPUT_CELL_NUM_TYPE = 3
31
- # LITERAL_INPUT_CELL_TYPES = Literal[0,1,2,3]
32
-
33
- class Mouse:
34
- def __init__(self, parent) -> None:
35
- self.parent = parent
36
- self.__last_frame_position_count__ = 0
37
- self.__last_frame_position__ = Vector2D.new_zero()
38
- self.__last_frame_movement_count__ = 0
39
- self.__last_frame_movement__ = Vector2D.new_zero()
40
-
41
- self.__pressed__ : tuple[bool, bool, bool] = (False, False, False)
42
- self.update()
43
-
44
- @property
45
- def position(self) -> Vector2D:
46
- if self.__last_frame_position_count__ != self.parent.current_frame:
47
- self.__last_frame_position__ = Vector2D(*pg.mouse.get_pos())
48
- self.__last_frame_position_count__ = self.parent.current_frame
49
- return self.__last_frame_position__
50
- @position.setter
51
- def position(self, new_position:Vector2D) -> None:
52
- self.__last_frame_position_count__ = self.parent.current_frame
53
- self.__last_frame_position__ = new_position
54
- pg.mouse.set_pos(self.__last_frame_position__())
55
-
56
- @property
57
- def last_frame_movement(self) -> Vector2D:
58
- if self.__last_frame_movement_count__ != self.parent.current_frame:
59
- self.__last_frame_movement__ = Vector2D(*pg.mouse.get_rel())
60
- self.__last_frame_movement_count__ = self.parent.current_frame
61
- return self.__last_frame_movement__
62
-
63
- def update(self) -> None:
64
- self.__last_pressed__ = self.__pressed__
65
- self.__pressed__ = pg.mouse.get_pressed()
66
-
67
- def get_key(self, button_id:Literal[0,1,2]=0, mode:__LITERAL_KEY_MODE_TYPES__="pressed") -> bool:
68
- if mode == "pressed":
69
- return self.__pressed__[button_id]
70
- elif mode == "just_pressed":
71
- return self.__pressed__[button_id] and (not self.__last_pressed__[button_id])
72
- elif mode == "just_released":
73
- return (not self.__pressed__[button_id]) and self.__last_pressed__[button_id]
74
- else:
75
- raise Exception(f"Unknown mode type: {mode}")
76
-
77
- class Keyboard:
78
- def __init__(self) -> None:
79
- self.__pressed__ :pg.key.ScancodeWrapper= pg.key.get_pressed()
80
- self.update()
81
-
82
- def update(self) -> None:
83
- self.__last_pressed__ = self.__pressed__
84
- self.__pressed__ = pg.key.get_pressed()
85
-
86
- def get_key(self, scan_code:int, mode:__LITERAL_KEY_MODE_TYPES__="pressed") -> bool:
87
- if mode == "pressed":
88
- return self.__pressed__[scan_code]
89
- elif mode == "just_pressed":
90
- return self.__pressed__[scan_code] and (not self.__last_pressed__[scan_code])
91
- elif mode == "just_released":
92
- return (not self.__pressed__[scan_code]) and self.__last_pressed__[scan_code]
93
- else:
94
- raise Exception(f"Unknown mode type: {mode}")
95
-
96
- class Util:
97
- def __init__(self) -> None:
98
- self.rootEnv = None
99
- self.surface : pg.Surface
100
- self.id : int|str
101
- self.is_hovered :bool= False
102
- def draw(self) -> None: pass
103
- def update(self) -> None: pass
104
-
105
- class InputCell(Util):
106
- def __init__(self,
107
- id : int|str,
108
- initial_value : str,
109
- position : Vector2D,
110
- size : Vector2D,
111
- prefix : str|None = None,
112
- text_color : Color = Color.white(),
113
- bg_color : None|Color = None,
114
- border_color : Color = Color.white(),
115
- border_width : float = 0,
116
- border_radius : int|list[int]|tuple[int,int,int,int] = -1,
117
- margin : Vector2D = Vector2D.zero(),
118
- pivot_position : __LITERAL_PIVOT_POSITIONS__ = "center_center",
119
- font : pg.font.Font = FONT_ARIAL_32,
120
- personalized_surface : pg.Surface|None = None,
121
- on_enter_pressed : Callable[[str], Any] = lambda full_text: ...,
122
- check_when_adding : Callable[[str], str] = lambda new_text: new_text
123
- ) -> None:
124
- super().__init__()
125
-
126
- self.id = id
127
- self.on_enter_pressed = on_enter_pressed
128
- self.check_when_adding = check_when_adding
129
- self.prefix = prefix if prefix != None else ""
130
-
131
- self.text_color = text_color
132
- self.font = font
133
- self.surface = personalized_surface
134
- self.bg_color = bg_color
135
- # size = Vector2D(*self.text_box.get_size()) + self.margin * 2
136
- self.size = size
137
- self.position = (position - size * __PIVOT_POSITIONS_MULTIPLIER__[pivot_position] + margin)
138
- self.bg_rect = [0, 0] + size()
139
- self.margin_rect = (margin * -1)() + size()
140
- self.border_color = border_color
141
- self.border_radius = [border_radius]*4 if not any(isinstance(border_radius, cls) for cls in {tuple, list}) else border_radius
142
- self.border_width = border_width
143
-
144
- self.value = initial_value
145
- self.update_text()
146
-
147
- self.text_surface = pg.Surface(self.size(), pg.SRCALPHA, 32).convert_alpha()
148
-
149
- def draw(self) -> None:
150
- self.text_surface.fill((0,0,0,0))
151
- if self.bg_color != None:
152
- pg.draw.rect(self.text_surface, self.bg_color(), self.bg_rect, 0, -1, *self.border_radius)
153
-
154
- self.text_surface.blit(self.text_box, self.text_position())
155
-
156
- if self.rootEnv.selected_util != self:
157
- if self.border_width:
158
- pg.draw.rect(self.text_surface, self.border_color(), self.margin_rect, self.border_width, -1, *self.border_radius)
159
- else:
160
- pg.draw.rect(self.text_surface, [127 + 127 * _mt.sin(self.rootEnv.runtime_seconds * 10)]*3, self.margin_rect, self.border_width if self.border_width else 10, -1, *self.border_radius)
161
-
162
- self.surface.blit(self.text_surface, self.position())
163
-
164
- def update(self) -> None:
165
- self.is_hovered = self.position.x < self.rootEnv.mouse.position.x < self.position.x + self.size.x and\
166
- self.position.y < self.rootEnv.mouse.position.y < self.position.y + self.size.y
167
- if self.rootEnv.mouse.get_key(0, "just_pressed"):
168
- if self.is_hovered:
169
- self.rootEnv.selected_util = self if self.rootEnv.selected_util != self else None
170
- self.update_text()
171
- if self.rootEnv.selected_util == self:
172
- for event in self.rootEnv.events:
173
- if event.type == pg.TEXTINPUT:
174
- self.value += self.check_when_adding(event.text)
175
- elif event.type == pg.KEYDOWN and event.key == pg.K_BACKSPACE:
176
- self.value = self.value[:-1]
177
- if self.rootEnv.keyboard.get_key(pg.K_DELETE):
178
- self.value = self.value[:-1]
179
- if self.rootEnv.keyboard.get_key(pg.K_RETURN, "just_pressed"):
180
- self.on_enter_pressed(self.value)
181
- if self.rootEnv.keyboard.get_key(pg.K_ESCAPE, "just_pressed"):
182
- self.rootEnv.selected_util = self if self.rootEnv.selected_util != self else None
183
- self.update_text()
184
-
185
- def update_text(self) -> None:
186
- self.text_box = self.font.render(self.prefix + self.value, True, self.text_color())
187
- if self.rootEnv != None and self.rootEnv.selected_util == self:
188
- # self.text_position = self.position + self.size * Vector2D(.85, .5) - Vector2D(*self.text_box.get_size()) * Vector2D(1, .5) - self.position
189
- self.text_position = self.position + self.size * .5 - Vector2D(*self.text_box.get_size()) * Vector2D(.5, .5) - self.position
190
- else:
191
- self.text_position = self.position + self.size * .5 - Vector2D(*self.text_box.get_size()) * Vector2D(.5, .5) - self.position
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes