pg-extended 0.0.1b1__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.
Files changed (53) hide show
  1. pg_extended-0.0.1b1/LICENSE +21 -0
  2. pg_extended-0.0.1b1/PKG-INFO +65 -0
  3. pg_extended-0.0.1b1/README.md +50 -0
  4. pg_extended-0.0.1b1/pyproject.toml +29 -0
  5. pg_extended-0.0.1b1/setup.cfg +4 -0
  6. pg_extended-0.0.1b1/src/pg_extended/Core/Base/AnimatedValue.py +246 -0
  7. pg_extended-0.0.1b1/src/pg_extended/Core/Base/Callback.py +57 -0
  8. pg_extended-0.0.1b1/src/pg_extended/Core/Base/DynamicValue.py +100 -0
  9. pg_extended-0.0.1b1/src/pg_extended/Core/Base/__init__.py +3 -0
  10. pg_extended-0.0.1b1/src/pg_extended/Core/Composites/CircleArea.py +33 -0
  11. pg_extended-0.0.1b1/src/pg_extended/Core/Composites/RectArea.py +40 -0
  12. pg_extended-0.0.1b1/src/pg_extended/Core/Composites/__init__.py +2 -0
  13. pg_extended-0.0.1b1/src/pg_extended/Core/__init__.py +5 -0
  14. pg_extended-0.0.1b1/src/pg_extended/Game/Elements/Entity.py +77 -0
  15. pg_extended-0.0.1b1/src/pg_extended/Game/Elements/Level.py +110 -0
  16. pg_extended-0.0.1b1/src/pg_extended/Game/Elements/Player.py +3 -0
  17. pg_extended-0.0.1b1/src/pg_extended/Game/Elements/SpriteAnimation.py +21 -0
  18. pg_extended-0.0.1b1/src/pg_extended/Game/Elements/TextureAtlas.py +101 -0
  19. pg_extended-0.0.1b1/src/pg_extended/Game/Elements/__init__.py +9 -0
  20. pg_extended-0.0.1b1/src/pg_extended/Game/Scene.py +69 -0
  21. pg_extended-0.0.1b1/src/pg_extended/Game/ViewPort.py +61 -0
  22. pg_extended-0.0.1b1/src/pg_extended/Game/__init__.py +15 -0
  23. pg_extended-0.0.1b1/src/pg_extended/Types.py +8 -0
  24. pg_extended-0.0.1b1/src/pg_extended/UI/Compounds/List.py +50 -0
  25. pg_extended-0.0.1b1/src/pg_extended/UI/Compounds/__init__.py +3 -0
  26. pg_extended-0.0.1b1/src/pg_extended/UI/CopyElement.py +123 -0
  27. pg_extended-0.0.1b1/src/pg_extended/UI/Elements/Button.py +114 -0
  28. pg_extended-0.0.1b1/src/pg_extended/UI/Elements/Circle.py +65 -0
  29. pg_extended-0.0.1b1/src/pg_extended/UI/Elements/Section.py +163 -0
  30. pg_extended-0.0.1b1/src/pg_extended/UI/Elements/Slider.py +267 -0
  31. pg_extended-0.0.1b1/src/pg_extended/UI/Elements/TextBox.py +89 -0
  32. pg_extended-0.0.1b1/src/pg_extended/UI/Elements/TextInput.py +261 -0
  33. pg_extended-0.0.1b1/src/pg_extended/UI/Elements/Toggle.py +109 -0
  34. pg_extended-0.0.1b1/src/pg_extended/UI/Elements/__init__.py +20 -0
  35. pg_extended-0.0.1b1/src/pg_extended/UI/System.py +170 -0
  36. pg_extended-0.0.1b1/src/pg_extended/UI/__init__.py +23 -0
  37. pg_extended-0.0.1b1/src/pg_extended/Util/ImgManipulation.py +97 -0
  38. pg_extended-0.0.1b1/src/pg_extended/Util/Misc.py +17 -0
  39. pg_extended-0.0.1b1/src/pg_extended/Util/__init__.py +2 -0
  40. pg_extended-0.0.1b1/src/pg_extended/Window/Core.py +34 -0
  41. pg_extended-0.0.1b1/src/pg_extended/Window/EventManager.py +38 -0
  42. pg_extended-0.0.1b1/src/pg_extended/Window/Lifecycle.py +42 -0
  43. pg_extended-0.0.1b1/src/pg_extended/Window/MainLoop.py +48 -0
  44. pg_extended-0.0.1b1/src/pg_extended/Window/SceneManager.py +52 -0
  45. pg_extended-0.0.1b1/src/pg_extended/Window/SystemManager.py +95 -0
  46. pg_extended-0.0.1b1/src/pg_extended/Window/Utility.py +50 -0
  47. pg_extended-0.0.1b1/src/pg_extended/Window/__init__.py +1 -0
  48. pg_extended-0.0.1b1/src/pg_extended/__init__.py +16 -0
  49. pg_extended-0.0.1b1/src/pg_extended.egg-info/PKG-INFO +65 -0
  50. pg_extended-0.0.1b1/src/pg_extended.egg-info/SOURCES.txt +51 -0
  51. pg_extended-0.0.1b1/src/pg_extended.egg-info/dependency_links.txt +1 -0
  52. pg_extended-0.0.1b1/src/pg_extended.egg-info/requires.txt +3 -0
  53. pg_extended-0.0.1b1/src/pg_extended.egg-info/top_level.txt +1 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Saurabh
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.
@@ -0,0 +1,65 @@
1
+ Metadata-Version: 2.4
2
+ Name: pg-extended
3
+ Version: 0.0.1b1
4
+ Summary: A lightweight 2d game engine built on top of pygame.
5
+ Author-email: Saurabh Jadhav <pgextended.2025@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/Saurabh262004/pg-extended
8
+ Requires-Python: >=3.9
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: pygame-ce
12
+ Requires-Dist: pyperclip
13
+ Requires-Dist: easygui
14
+ Dynamic: license-file
15
+
16
+ # pg-extended
17
+ *A lightweight UI wrapper and window manager for pygame.*
18
+
19
+ > [!WARNING]
20
+ > - This library is in the early stages of development and may have many breaking changes in the future.
21
+ > - Some of the features are still to be refined and added.
22
+
23
+ ## Goal
24
+ - Provide a dynamic, customizable, and intuitive system for building UI and game elements in pygame.
25
+ - Handle repetitive UI / window management tasks for the user.
26
+ - Eventually evolve into a small, modular game engine.
27
+
28
+ ---
29
+
30
+ ## Installation
31
+ > [!IMPORTANT]
32
+ > pip install support will be added later on.
33
+
34
+ ```
35
+ git clone https://github.com/Saurabh262004/pg-extended.git
36
+ ```
37
+
38
+ Copy the `pg_extended/` folder into the root directory of your project.
39
+ Make sure that the folder name remains exactly `pg_extended/`.
40
+
41
+ ---
42
+
43
+ # Example
44
+
45
+ A simple example of how to initialize an empty window with pg_extended.
46
+
47
+ ```python
48
+ from pg_extended import Window
49
+
50
+ # create a window with "Demo pgx window" as the title with 1280x720 resolution
51
+ app = Window("Demo pgx window", (1280, 720))
52
+
53
+ # all the UI / Game setup can be done here
54
+
55
+ # open the window
56
+ app.openWindow()
57
+ ```
58
+
59
+ > For more details, please checkout the [wiki page](../../wiki).
60
+
61
+ ---
62
+
63
+ ## [HVision](https://github.com/Saurabh262004/HVision)
64
+
65
+ ### A large project by me that uses pg_extended in a real environment.
@@ -0,0 +1,50 @@
1
+ # pg-extended
2
+ *A lightweight UI wrapper and window manager for pygame.*
3
+
4
+ > [!WARNING]
5
+ > - This library is in the early stages of development and may have many breaking changes in the future.
6
+ > - Some of the features are still to be refined and added.
7
+
8
+ ## Goal
9
+ - Provide a dynamic, customizable, and intuitive system for building UI and game elements in pygame.
10
+ - Handle repetitive UI / window management tasks for the user.
11
+ - Eventually evolve into a small, modular game engine.
12
+
13
+ ---
14
+
15
+ ## Installation
16
+ > [!IMPORTANT]
17
+ > pip install support will be added later on.
18
+
19
+ ```
20
+ git clone https://github.com/Saurabh262004/pg-extended.git
21
+ ```
22
+
23
+ Copy the `pg_extended/` folder into the root directory of your project.
24
+ Make sure that the folder name remains exactly `pg_extended/`.
25
+
26
+ ---
27
+
28
+ # Example
29
+
30
+ A simple example of how to initialize an empty window with pg_extended.
31
+
32
+ ```python
33
+ from pg_extended import Window
34
+
35
+ # create a window with "Demo pgx window" as the title with 1280x720 resolution
36
+ app = Window("Demo pgx window", (1280, 720))
37
+
38
+ # all the UI / Game setup can be done here
39
+
40
+ # open the window
41
+ app.openWindow()
42
+ ```
43
+
44
+ > For more details, please checkout the [wiki page](../../wiki).
45
+
46
+ ---
47
+
48
+ ## [HVision](https://github.com/Saurabh262004/HVision)
49
+
50
+ ### A large project by me that uses pg_extended in a real environment.
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pg-extended"
7
+ version = "0.0.1b1"
8
+ description = "A lightweight 2d game engine built on top of pygame."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Saurabh Jadhav", email = "pgextended.2025@gmail.com" }
14
+ ]
15
+
16
+ dependencies = [
17
+ "pygame-ce",
18
+ "pyperclip",
19
+ "easygui"
20
+ ]
21
+
22
+ [tool.setuptools]
23
+ package-dir = {"" = "src"}
24
+
25
+ [tool.setuptools.packages.find]
26
+ where = ["src"]
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/Saurabh262004/pg-extended"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,246 @@
1
+ import time
2
+ from copy import copy
3
+ from pg_extended.Core.Base.DynamicValue import DynamicValue
4
+
5
+ INTERPOLATION_TYPES = ['linear', 'easeIn', 'easeOut', 'easeInOut', 'custom']
6
+ DEFAULT_POS_VALS = ['start', 'end']
7
+
8
+ type valuesType = list[DynamicValue | AnimatedValue | int | float] | list[DynamicValue | AnimatedValue | int | float]
9
+
10
+ class AnimatedValue:
11
+ def __init__(self, values: valuesType, duration: float, defaultPos: str = 'start', interpolation: str = 'linear', callback: callable = None, customInterpolation: callable = None):
12
+ if len(values) < 2:
13
+ raise ValueError("Animator requires a minimum of two values to animate between.")
14
+
15
+ if not interpolation in INTERPOLATION_TYPES:
16
+ raise ValueError(f'Invalid interpolation type: {interpolation}. Must be one of: {INTERPOLATION_TYPES}')
17
+
18
+ if interpolation == 'custom' and customInterpolation is None:
19
+ raise ValueError('Custom interpolation function must be provided when using "custom" interpolation type.')
20
+
21
+ if not defaultPos in DEFAULT_POS_VALS:
22
+ raise ValueError(f'Invalid defaultPos: {defaultPos}. Must be one of: {DEFAULT_POS_VALS}')
23
+
24
+ self.values = values
25
+ self.rawValues: list[int | float] = []
26
+ self.duration = duration
27
+ self.interpolation = interpolation
28
+ self.callback = callback
29
+ self.defaultPos = defaultPos
30
+
31
+ self.updateValues()
32
+
33
+ if self.defaultPos == 'start':
34
+ self.value = self.rawValues[0]
35
+ else:
36
+ self.value = self.rawValues[-1]
37
+
38
+ self.animStart: float = None
39
+ self.reverse: bool = False
40
+ self.repeats: int = 0
41
+ self.alternate: bool = False
42
+ self.hasPlayedOnce: bool = False
43
+ self.delay: int = 0
44
+
45
+ if self.interpolation == 'linear':
46
+ self.interpolationStep = self.linear
47
+ elif self.interpolation == 'easeIn':
48
+ self.interpolationStep = self.easeIn
49
+ elif self.interpolation == 'easeOut':
50
+ self.interpolationStep = self.easeOut
51
+ elif self.interpolation == 'easeInOut':
52
+ self.interpolationStep = self.easeInOut
53
+ elif self.interpolation == 'custom':
54
+ self.interpolationStep = customInterpolation
55
+
56
+ @staticmethod
57
+ def linear(start: float, end: float, t: float) -> float:
58
+ if t <= 0:
59
+ return start
60
+ elif t >= 1:
61
+ return end
62
+
63
+ return start + (end - start) * t
64
+
65
+ @staticmethod
66
+ def easeIn(start: float, end: float, t: float) -> float:
67
+ if t <= 0:
68
+ return start
69
+ elif t >= 1:
70
+ return end
71
+
72
+ t = t ** 2
73
+
74
+ return start + (end - start) * t
75
+
76
+ @staticmethod
77
+ def easeOut(start: float, end: float, t: float) -> float:
78
+ if t <= 0:
79
+ return start
80
+ elif t >= 1:
81
+ return end
82
+
83
+ t = 1 - (1 - t) ** 2
84
+
85
+ return start + (end - start) * t
86
+
87
+ @staticmethod
88
+ def easeInOut(start: float, end: float, t: float) -> float:
89
+ if t <= 0:
90
+ return start
91
+ elif t >= 1:
92
+ return end
93
+
94
+ t = t**3 * (t * (t * 6 - 15) + 10)
95
+
96
+ return start + (end - start) * t
97
+
98
+ # get raw values from animated / dynamic values
99
+ def updateValues(self):
100
+ self.rawValues = []
101
+
102
+ for value in self.values:
103
+ if isinstance(value, (DynamicValue, AnimatedValue)):
104
+ value.resolveValue()
105
+ self.rawValues.append(value.value)
106
+ else:
107
+ self.rawValues.append(value)
108
+
109
+ # get an interpolated value from normalized t
110
+ def interpolate(self, t: float):
111
+ if t <= 0:
112
+ return self.rawValues[0]
113
+ elif t >= 1:
114
+ return self.rawValues[-1]
115
+
116
+ processingVals = copy(self.rawValues)
117
+
118
+ while len(processingVals) > 1:
119
+ tmp = []
120
+
121
+ for i in range(len(processingVals) - 1):
122
+ tmp.append(
123
+ self.interpolationStep(processingVals[i], processingVals[i + 1], t)
124
+ )
125
+
126
+ processingVals = tmp
127
+
128
+ self.value = processingVals[0]
129
+
130
+ # calculate current animation time, get normalized t, call .interpolate() etc..
131
+ # most importantly this is the function you need to call to update the animated value
132
+ def resolveValue(self):
133
+ if self.animStart is None:
134
+ self.updateRestingPos()
135
+ return
136
+
137
+ elapsedTime = ((time.perf_counter() * 1000) - self.animStart) - self.delay
138
+
139
+ self.updateValues()
140
+
141
+ if elapsedTime >= self.duration:
142
+ self.finishAnim()
143
+ else:
144
+ if self.reverse:
145
+ t = 1 - (elapsedTime / self.duration)
146
+ else:
147
+ t = elapsedTime / self.duration
148
+
149
+ self.interpolate(t)
150
+
151
+ # handle animation ends, repeats, callbacks used by .resolveValue()
152
+ def finishAnim(self):
153
+ if self.reverse:
154
+ self.value = self.rawValues[0]
155
+ else:
156
+ self.value = self.rawValues[-1]
157
+
158
+ self.animStart = None
159
+
160
+ self.hasPlayedOnce = True
161
+
162
+ if self.repeats > 0:
163
+ self.repeats -= 1
164
+ self.trigger(self.reverse, self.repeats, self.alternate)
165
+ return None
166
+
167
+ if self.repeats == -1:
168
+ self.trigger(self.reverse, self.repeats, self.alternate)
169
+ return None
170
+
171
+ if self.callback is not None:
172
+ self.callback()
173
+
174
+ # updates the value to a default idle position when no animation is playing
175
+ def updateRestingPos(self):
176
+ self.updateValues()
177
+
178
+ A = self.hasPlayedOnce
179
+ B = self.defaultPos == 'start'
180
+ C = self.reverse
181
+
182
+ '''
183
+ this let's the system decide the resting position with only the default position when it hasn't ran yet
184
+ once it has ran, the reverse value also has an effect on the resting value
185
+
186
+ if self.hasPlayedOnce:
187
+ if self.defaultPos == 'start':
188
+ if self.reverse:
189
+ self.value = self.values[0].value
190
+ else:
191
+ self.value = self.values[-1].value
192
+ else:
193
+ if self.reverse:
194
+ self.value = self.values[-1].value
195
+ else:
196
+ self.value = self.values[0].value
197
+ else:
198
+ if self.defaultPos == 'start':
199
+ self.value = self.values[0].value
200
+ else:
201
+ self.value = self.values[-1].value
202
+
203
+ condition for choosing first value:
204
+ (A and B and C) or (A and not B and not C) or (not A and B)
205
+ condition for choosing last value:
206
+ (A and B and not C) or (A and not B and C) or (not A and not B)
207
+
208
+ compacted:
209
+ (A and (B == C)) or (not A and B)
210
+
211
+ maximum performance version:
212
+ (B and not A) or (A and (B == C))
213
+ '''
214
+
215
+ pickStart = (B and not A) or (A and (B == C))
216
+
217
+ self.value = self.rawValues[0] if pickStart else self.rawValues[-1]
218
+
219
+ # triggers animation
220
+ def trigger(self, reverse: bool = False, repeats: int = 0, alternate: bool = False, delay: int = 0):
221
+ self.animStart = time.perf_counter() * 1000
222
+
223
+ self.repeats = repeats
224
+ self.alternate = alternate
225
+ self.delay = delay
226
+
227
+ if self.hasPlayedOnce:
228
+ if self.alternate:
229
+ self.reverse = not self.reverse
230
+ else:
231
+ self.reverse = reverse
232
+ else:
233
+ self.reverse = reverse
234
+
235
+ # stops all animations, resets repeats and instantly snaps the value to a resting position
236
+ def terminate(self):
237
+ if self.animStart is None:
238
+ return None
239
+
240
+ self.animStart = None
241
+ self.repeats = 0
242
+
243
+ if self.reverse:
244
+ self.value = self.rawValues[0]
245
+ else:
246
+ self.value = self.rawValues[-1]
@@ -0,0 +1,57 @@
1
+ from typing import Any
2
+ from pg_extended.Core.Base import DynamicValue, AnimatedValue
3
+ from pg_extended.Types import CallableLike
4
+
5
+ class Callback:
6
+ def __init__(self, triggers: list[str] | tuple[str], func: CallableLike, staticArgs: dict[str, Any] = None, extraArgKeys: dict[str, str] = None):
7
+ self.triggers = triggers
8
+ self.func = func
9
+ self.staticArgs = staticArgs or {}
10
+ self.resolvedArgs = {}
11
+ self.extraArgKeys = extraArgKeys or {}
12
+ self.totalArgs = {}
13
+
14
+ def _setExtraArgs(self, args: dict[str, Any] = None):
15
+ args = args or {}
16
+
17
+ self.totalArgs = self.staticArgs.copy()
18
+
19
+ for key, value in args.items():
20
+ if key in self.extraArgKeys:
21
+ self.totalArgs[self.extraArgKeys[key]] = value
22
+
23
+ def resolveArgs(self):
24
+ self.resolvedArgs = {}
25
+
26
+ for key in self.totalArgs:
27
+ val = self.totalArgs[key]
28
+
29
+ if isinstance(val, (DynamicValue, AnimatedValue)):
30
+ val.resolveValue()
31
+ self.resolvedArgs[key] = val.value
32
+ else:
33
+ self.resolvedArgs[key] = val
34
+
35
+ def call(self, extraArgs: dict[str, Any] = None):
36
+ extraArgs = extraArgs or {}
37
+
38
+ self._setExtraArgs(extraArgs)
39
+
40
+ self.resolveArgs()
41
+
42
+ self.func(**self.resolvedArgs)
43
+
44
+ class CallbackSet:
45
+ def __init__(self, callbacks: list[Callback] | tuple[Callback]):
46
+ self.callbacks = callbacks
47
+ self.callbacksDict = {}
48
+
49
+ for callback in self.callbacks:
50
+ for tgr in callback.triggers:
51
+ self.callbacksDict.setdefault(tgr, []).append(callback)
52
+
53
+ def call(self, trigger: str, extraArgs: dict[str, Any] = None):
54
+ if trigger not in self.callbacksDict: return None
55
+
56
+ for callback in self.callbacksDict[trigger]:
57
+ callback.call(extraArgs)
@@ -0,0 +1,100 @@
1
+ from __future__ import annotations
2
+ from typing import Any
3
+ from pg_extended.Types import CallableLike
4
+ import types
5
+
6
+ class DynamicValue:
7
+ def __init__(self, ref: Any, lookup: str | None = None, args: dict[str, Any] | None = None, percent: int | float | None = None):
8
+ self.reference = ref
9
+ self.lookup = lookup
10
+ self.args = args
11
+ self.percent = percent
12
+ self.value: Any = None
13
+ self.resolveValue: CallableLike = None
14
+
15
+ self.assignResolveMethod()
16
+
17
+ self.resolveValue()
18
+
19
+ def _IFPer(self):
20
+ self.value = self.reference / 100 * self.percent
21
+
22
+ def _dictLookup(self):
23
+ self.value = self.reference[self.lookup]
24
+
25
+ def _dictLookupPer(self):
26
+ self.value = self.reference[self.lookup] / 100 * self.percent
27
+
28
+ def _CV(self):
29
+ self.reference.resolveValue()
30
+ self.value = self.reference.value
31
+
32
+ def _CVPer(self):
33
+ self.reference.resolveValue()
34
+ self.value = self.reference.value / 100 * self.percent
35
+
36
+ def _call(self):
37
+ self.value = self.reference()
38
+
39
+ def _callPer(self):
40
+ self.value = self.reference() / 100 * self.percent
41
+
42
+ def _callArgs(self):
43
+ self.value = self.reference(**self.args)
44
+
45
+ def _callArgsPer(self):
46
+ self.value = self.reference(**self.args) / 100 * self.percent
47
+
48
+ def _objLookup(self):
49
+ self.value = getattr(self.reference, self.lookup)
50
+
51
+ def _objLookupPer(self):
52
+ self.value = getattr(self.reference, self.lookup) / 100 * self.percent
53
+
54
+ def _direct(self):
55
+ self.value = self.reference
56
+
57
+ def assignResolveMethod(self):
58
+ from pg_extended.Core.Base.AnimatedValue import AnimatedValue
59
+
60
+ # numbers with a percent value given
61
+ if isinstance(self.reference, (int, float)) and self.percent is not None:
62
+ self.resolveValue = self._IFPer
63
+
64
+ # dicts
65
+ elif isinstance(self.reference, dict) and self.lookup is not None:
66
+ if self.percent is None:
67
+ self.resolveValue = self._dictLookup
68
+ else:
69
+ self.resolveValue = self._dictLookupPer
70
+
71
+ # DV or AV
72
+ elif isinstance(self.reference, DynamicValue) or isinstance(self.reference, AnimatedValue):
73
+ if self.percent is None:
74
+ self.resolveValue = self._CV
75
+ else:
76
+ self.resolveValue = self._CVPer
77
+
78
+ # callable
79
+ elif isinstance(self.reference, (types.FunctionType | types.BuiltinFunctionType | types.MethodType)):
80
+ if self.args is None:
81
+ if self.percent is None:
82
+ self.resolveValue = self._call
83
+ else:
84
+ self.resolveValue = self._callPer
85
+ else:
86
+ if self.percent is None:
87
+ self.resolveValue = self._callArgs
88
+ else:
89
+ self.resolveValue = self._callArgsPer
90
+
91
+ # none of the above and lookup is provided, assume it's a class + attribute
92
+ elif isinstance(self.lookup, str):
93
+ if self.percent is None:
94
+ self.resolveValue = self._objLookup
95
+ else:
96
+ self.resolveValue = self._objLookupPer
97
+
98
+ # dump everything else into direct
99
+ else:
100
+ self.resolveValue = self._direct
@@ -0,0 +1,3 @@
1
+ from pg_extended.Core.Base.DynamicValue import DynamicValue
2
+ from pg_extended.Core.Base.AnimatedValue import AnimatedValue
3
+ from pg_extended.Core.Base.Callback import Callback, CallbackSet
@@ -0,0 +1,33 @@
1
+ from pg_extended.Core.Base.DynamicValue import DynamicValue
2
+ from pg_extended.Core.Base.AnimatedValue import AnimatedValue
3
+
4
+ type NumValue = DynamicValue | AnimatedValue | int | float
5
+
6
+ class CircleArea:
7
+ def __init__(self, dimensions: dict[str, NumValue]):
8
+ self.dimensions = dimensions
9
+
10
+ if not len(self.dimensions) == 3:
11
+ raise ValueError(f'dimensions must contain 3 Dimension objects, received: {len(self.dimensions)}')
12
+
13
+ for key in ('x', 'y', 'radius'):
14
+ if not key in self.dimensions:
15
+ raise ValueError('dimensions must contain all of the following keys: \'x\', \'y\', \'radius\'')
16
+
17
+ self.x: int | float
18
+ self.y: int | float
19
+ self.radius: int | float
20
+
21
+ self.update()
22
+
23
+ def getDimValue(self, key: str) -> int | float:
24
+ return self.dimensions[key].value if isinstance(self.dimensions[key], (DynamicValue, AnimatedValue)) else self.dimensions[key]
25
+
26
+ def update(self):
27
+ for key in self.dimensions:
28
+ if isinstance(self.dimensions[key], (DynamicValue, AnimatedValue)):
29
+ self.dimensions[key].resolveValue()
30
+
31
+ self.x = self.getDimValue("x")
32
+ self.y = self.getDimValue("y")
33
+ self.radius = self.getDimValue("radius")
@@ -0,0 +1,40 @@
1
+ import pygame as pg
2
+ from pg_extended.Core.Base.DynamicValue import DynamicValue
3
+ from pg_extended.Core.Base.AnimatedValue import AnimatedValue
4
+
5
+ type NumValue = DynamicValue | AnimatedValue | int | float
6
+
7
+ class RectArea:
8
+ def __init__(self, dimensions: dict[str, NumValue]):
9
+ self.dimensions: dict[str, NumValue] = dimensions
10
+
11
+ if not len(self.dimensions) == 4:
12
+ raise ValueError(f'dimensions must contain 4 Dimension objects, received: {len(self.dimensions)}')
13
+
14
+ for key in ('x', 'y', 'width', 'height'):
15
+ if not key in self.dimensions:
16
+ raise ValueError('dimensions must contain all of the following keys: \'x\', \'y\', \'width\' \'height\'')
17
+
18
+ self.x: int | float
19
+ self.y: int | float
20
+ self.width: int | float
21
+ self.height: int | float
22
+
23
+ self.rect: pg.Rect = pg.Rect(0, 0, 0, 0)
24
+
25
+ self.update()
26
+
27
+ def getDimValue(self, key: str) -> int | float:
28
+ return self.dimensions[key].value if isinstance(self.dimensions[key], (DynamicValue, AnimatedValue)) else self.dimensions[key]
29
+
30
+ def update(self):
31
+ for key in self.dimensions:
32
+ if isinstance(self.dimensions[key], (DynamicValue, AnimatedValue)):
33
+ self.dimensions[key].resolveValue()
34
+
35
+ self.x = self.getDimValue("x")
36
+ self.y = self.getDimValue("y")
37
+ self.width = self.getDimValue("width")
38
+ self.height = self.getDimValue("height")
39
+
40
+ self.rect.update(self.x, self.y, self.width, self.height)
@@ -0,0 +1,2 @@
1
+ from pg_extended.Core.Composites.RectArea import RectArea
2
+ from pg_extended.Core.Composites.CircleArea import CircleArea
@@ -0,0 +1,5 @@
1
+ from pg_extended.Core import Composites
2
+ from pg_extended.Core import Base
3
+
4
+ from pg_extended.Core.Composites import *
5
+ from pg_extended.Core.Base import *