easycode-infinite 1.0.0__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.
- easycode_infinite-1.0.0/LICENSE +24 -0
- easycode_infinite-1.0.0/PKG-INFO +10 -0
- easycode_infinite-1.0.0/README.md +17 -0
- easycode_infinite-1.0.0/easycode-infinite/__init__.py +97 -0
- easycode_infinite-1.0.0/easycode-infinite/easycode_addons.py +780 -0
- easycode_infinite-1.0.0/easycode_infinite.egg-info/PKG-INFO +10 -0
- easycode_infinite-1.0.0/easycode_infinite.egg-info/SOURCES.txt +10 -0
- easycode_infinite-1.0.0/easycode_infinite.egg-info/dependency_links.txt +1 -0
- easycode_infinite-1.0.0/easycode_infinite.egg-info/requires.txt +4 -0
- easycode_infinite-1.0.0/easycode_infinite.egg-info/top_level.txt +1 -0
- easycode_infinite-1.0.0/pyproject.toml +19 -0
- easycode_infinite-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
EasyCode License Agreement (2026)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 [Your Nickname/Team Name]
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted to any person obtaining a copy of this software
|
|
6
|
+
("EasyCode") to use it for personal, educational, and non-commercial game
|
|
7
|
+
development purposes, subject to the following conditions:
|
|
8
|
+
|
|
9
|
+
1. ATTRIBUTION (CREDIT): Any game or project created using EasyCode must
|
|
10
|
+
provide visible credit to the author in the game's "About" section,
|
|
11
|
+
credits, or documentation.
|
|
12
|
+
|
|
13
|
+
2. NON-COMMERCIAL USE: You may not use this library in a game that is
|
|
14
|
+
sold for money or contains microtransactions unless you have
|
|
15
|
+
obtained written permission from the author.
|
|
16
|
+
|
|
17
|
+
3. NO DERIVATIVES: You may not take the code from EasyCode to create,
|
|
18
|
+
distribute, or sell a competing library or "addon" package.
|
|
19
|
+
|
|
20
|
+
4. NO STEALING: You may not claim this code as your own.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
24
|
+
OTHER LIABILITY.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: easycode-infinite
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A simple GUI addon for Pygame, Pyglet, and Arcade
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Dist: pygame-ce
|
|
7
|
+
Requires-Dist: pyglet>=2.0
|
|
8
|
+
Requires-Dist: arcade>=3.0
|
|
9
|
+
Requires-Dist: roman
|
|
10
|
+
Dynamic: license-file
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
##EasyCode
|
|
2
|
+
**EasyCode is a python library made specifically so there would be easier and better coding with a lot of simplification added**
|
|
3
|
+
|
|
4
|
+
EasyCode simplifies game development in Python by providing high-precision math variables and powerful, easy-to-use base classes for the industry's most popular 2D frameworks.
|
|
5
|
+
|
|
6
|
+
##Key Features
|
|
7
|
+
*it includes of 3 special variables BigDecimal, BigString, and BigVector
|
|
8
|
+
*includes of optimizations
|
|
9
|
+
*is very fast and can save memory potentially
|
|
10
|
+
*has a couple new sprites you can use
|
|
11
|
+
*supports arcade, pyglet, and pygame
|
|
12
|
+
|
|
13
|
+
##Installation
|
|
14
|
+
Install EasyCode via `pip` or `uv`:
|
|
15
|
+
```bash
|
|
16
|
+
pip install easycode
|
|
17
|
+
uv pip install easycode --system
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
from .easycode_addons import (
|
|
2
|
+
PygameVisibleList,
|
|
3
|
+
PygameVisibleVariable,
|
|
4
|
+
PygameClickedCalculator,
|
|
5
|
+
PygameHealthBar,
|
|
6
|
+
PygameDraggableSlider,
|
|
7
|
+
PygameScreenShake,
|
|
8
|
+
PygameTextBox,
|
|
9
|
+
PygameDialogueText,
|
|
10
|
+
EasyDraw,
|
|
11
|
+
PygameSoundManager,
|
|
12
|
+
get_font,
|
|
13
|
+
change_axis,
|
|
14
|
+
BigString,
|
|
15
|
+
BigDecimal,
|
|
16
|
+
BigVector2,
|
|
17
|
+
BigVector3,
|
|
18
|
+
BigVector4,
|
|
19
|
+
PygameSprite,
|
|
20
|
+
PygameGroup,
|
|
21
|
+
PygameLayeredGroup,
|
|
22
|
+
ArcadeSprite,
|
|
23
|
+
ArcadeGroup,
|
|
24
|
+
PygletHealthBar,
|
|
25
|
+
PygletVisibleList,
|
|
26
|
+
PygletTextBox,
|
|
27
|
+
PygletDialogueText,
|
|
28
|
+
PygletScreenShake,
|
|
29
|
+
PygletDraggableSlider,
|
|
30
|
+
PygletSprite,
|
|
31
|
+
PygletGroup
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
sound = PygameSoundManager()
|
|
35
|
+
draw = EasyDraw()
|
|
36
|
+
|
|
37
|
+
bigstr = BigString
|
|
38
|
+
bigdec = BigDecimal
|
|
39
|
+
bigvector = BigVector2
|
|
40
|
+
bigvector2 = BigVector2
|
|
41
|
+
bigvector3 = BigVector3
|
|
42
|
+
bigvector4 = BigVector4
|
|
43
|
+
|
|
44
|
+
pg_sprite = PygameSprite
|
|
45
|
+
pg_group = PygameGroup
|
|
46
|
+
arc_sprite = ArcadeSprite
|
|
47
|
+
arc_group = ArcadeGroup
|
|
48
|
+
pgl_sprite = PygletSprite
|
|
49
|
+
|
|
50
|
+
__all__ = [
|
|
51
|
+
'PygameVisibleList',
|
|
52
|
+
'PygameVisibleVariable',
|
|
53
|
+
'PygameClickedCalculator',
|
|
54
|
+
'PygameHealthBar',
|
|
55
|
+
'PygameDraggableSlider',
|
|
56
|
+
'PygameScreenShake',
|
|
57
|
+
'PygameTextBox',
|
|
58
|
+
'PygameDialogueText',
|
|
59
|
+
'PygameEasyDraw',
|
|
60
|
+
'PygameSoundManager',
|
|
61
|
+
'sound',
|
|
62
|
+
'get_font',
|
|
63
|
+
'change_axis',
|
|
64
|
+
'bigstr',
|
|
65
|
+
'bigdec',
|
|
66
|
+
'bigvector',
|
|
67
|
+
'bigvector2',
|
|
68
|
+
'bigvector3',
|
|
69
|
+
'bigvector4',
|
|
70
|
+
'BigString',
|
|
71
|
+
'BigDecimal',
|
|
72
|
+
'BigVector2',
|
|
73
|
+
'BigVector3',
|
|
74
|
+
'BigVector4',
|
|
75
|
+
'PygameSprite',
|
|
76
|
+
'PygameGroup',
|
|
77
|
+
'PygameLayeredGroup',
|
|
78
|
+
'pg_sprite',
|
|
79
|
+
'pg_group',
|
|
80
|
+
'ArcadeSprite',
|
|
81
|
+
'ArcadeGroup',
|
|
82
|
+
'arc_sprite',
|
|
83
|
+
'arc_group',
|
|
84
|
+
'PygletHealthBar',
|
|
85
|
+
'PygletVisibleList',
|
|
86
|
+
'PygletTextBox',
|
|
87
|
+
'PygletDialogueText',
|
|
88
|
+
'PygletScreenShake',
|
|
89
|
+
'PygletDraggableSlider',
|
|
90
|
+
'PygletSprite',
|
|
91
|
+
'PygletGroup',
|
|
92
|
+
'pgl_sprite'
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
# PACKAGE METADATA
|
|
96
|
+
__version__ = "0.5.0"
|
|
97
|
+
__author__ = "Kent"
|
|
@@ -0,0 +1,780 @@
|
|
|
1
|
+
import pygame, pyglet, arcade
|
|
2
|
+
import time, os, math
|
|
3
|
+
|
|
4
|
+
_FONT_CACHE = {}
|
|
5
|
+
|
|
6
|
+
# this function you can use to get cached fonts but it was created for internal use mainly
|
|
7
|
+
def get_font(name, size):
|
|
8
|
+
key = (name, size)
|
|
9
|
+
if key not in _FONT_CACHE:
|
|
10
|
+
try:
|
|
11
|
+
_FONT_CACHE[key] = pygame.font.SysFont(name, size)
|
|
12
|
+
except:
|
|
13
|
+
_FONT_CACHE[key] = pygame.font.SysFont("Arial", size)
|
|
14
|
+
return _FONT_CACHE[key]
|
|
15
|
+
|
|
16
|
+
# simply were I will add my drawing functions
|
|
17
|
+
class EasyDraw:
|
|
18
|
+
@staticmethod
|
|
19
|
+
def star(surface, color, center, size, points=5, corner_rounding=0):
|
|
20
|
+
inner_radius = size / 2.5
|
|
21
|
+
outer_radius = size
|
|
22
|
+
point_list = []
|
|
23
|
+
|
|
24
|
+
for i in range(points * 2):
|
|
25
|
+
radius = float(outer_radius) if i % 2 == 0 else float(inner_radius)
|
|
26
|
+
angle = math.radians(i * (360 / (points * 2)))
|
|
27
|
+
|
|
28
|
+
x = center[0] + radius * math.cos(angle)
|
|
29
|
+
y = center[1] + radius * math.sin(angle)
|
|
30
|
+
point_list.append((x, y))
|
|
31
|
+
|
|
32
|
+
if corner_rounding <= 0:
|
|
33
|
+
return pygame.draw.polygon(surface, color, point_list)
|
|
34
|
+
else:
|
|
35
|
+
# For 2026, we use a thicker line join to simulate rounding
|
|
36
|
+
return pygame.draw.polygon(surface, color, point_list, width=0)
|
|
37
|
+
|
|
38
|
+
# will change the way you sprite or sprite group spins
|
|
39
|
+
def change_axis(sprite, angle, pivot_offset):
|
|
40
|
+
rotated_image = pygame.transform.rotate(sprite.image, angle)
|
|
41
|
+
|
|
42
|
+
offset_rotated = pygame.math.Vector2(pivot_offset).rotate(-angle)
|
|
43
|
+
|
|
44
|
+
sprite.image = rotated_image
|
|
45
|
+
sprite.rect = rotated_image.get_rect(center=sprite.pos.to_pygame() + offset_rotated)
|
|
46
|
+
|
|
47
|
+
class PygameClickedCalculator(pygame.sprite.Sprite):
|
|
48
|
+
def __init__(self):
|
|
49
|
+
super().__init__()
|
|
50
|
+
|
|
51
|
+
"""this function calculates if the sprite was clicked or not"""
|
|
52
|
+
def clicked(self, event):
|
|
53
|
+
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
|
|
54
|
+
if hasattr(self, 'rect') and self.rect.collidepoint(event.pos):
|
|
55
|
+
return True
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
"""this function changes the cursor to a hand when hovering over the sprite"""
|
|
59
|
+
def handle_cursor(self):
|
|
60
|
+
mouse_pos = pygame.mouse.get_pos()
|
|
61
|
+
if hasattr(self, 'rect') and self.rect.collidepoint(mouse_pos):
|
|
62
|
+
pygame.mouse.set_cursor(pygame.SYSTEM_CURSOR_HAND)
|
|
63
|
+
return True
|
|
64
|
+
return False
|
|
65
|
+
|
|
66
|
+
#a tool you can use to have the camera follow something
|
|
67
|
+
class PygameSmartCamera:
|
|
68
|
+
def __init__(self, screen_width, screen_height, lerp_speed=0.1):
|
|
69
|
+
self.offset = pygame.Vector2(0, 0)
|
|
70
|
+
self.width = screen_width
|
|
71
|
+
self.height = screen_height
|
|
72
|
+
self.lerp_speed = lerp_speed
|
|
73
|
+
|
|
74
|
+
def update(self, target_rect):
|
|
75
|
+
target_center_x = target_rect.centerx - self.width // 2
|
|
76
|
+
target_center_y = target_rect.centery - self.height // 2
|
|
77
|
+
|
|
78
|
+
self.offset.x += (target_center_x - self.offset.x) * self.lerp_speed
|
|
79
|
+
self.offset.y += (target_center_y - self.offset.y) * self.lerp_speed
|
|
80
|
+
|
|
81
|
+
def apply(self, entity_rect):
|
|
82
|
+
return entity_rect.move(-self.offset.x, -self.offset.y)
|
|
83
|
+
|
|
84
|
+
# this will create a visible variable that can contain any type of data ints floats strings etc
|
|
85
|
+
class PygameVisibleVariable(PygameClickedCalculator):
|
|
86
|
+
def __init__(self, font, fontsize, fontcolor, x, y, string, background_t_f, backgroundcolor=None):
|
|
87
|
+
if not isinstance(font, str):
|
|
88
|
+
raise TypeError(f"Font name must be a string, not {type(font).__name__}")
|
|
89
|
+
|
|
90
|
+
if not isinstance(fontsize, (int, float)) or fontsize <= 0:
|
|
91
|
+
raise ValueError(f"Font size must be a positive number, you provided: {fontsize}")
|
|
92
|
+
|
|
93
|
+
if not isinstance(fontcolor, (tuple, list)) or len(fontcolor) < 3:
|
|
94
|
+
raise TypeError("fontcolor must be an RGB tuple or list (e.g., (255, 255, 255))")
|
|
95
|
+
|
|
96
|
+
if not isinstance(background_t_f, bool):
|
|
97
|
+
raise TypeError(f"background_t_f must be True or False, not {type(background_t_f).__name__}")
|
|
98
|
+
|
|
99
|
+
if background_t_f and backgroundcolor is None:
|
|
100
|
+
raise ValueError("When background_t_f is True, you must provide a backgroundcolor (e.g., (0,0,255))")
|
|
101
|
+
|
|
102
|
+
if not background_t_f and backgroundcolor is not None:
|
|
103
|
+
raise ValueError("backgroundcolor should not be provided when background_t_f is False")
|
|
104
|
+
|
|
105
|
+
super().__init__()
|
|
106
|
+
self.font_name = font
|
|
107
|
+
self.font_size = int(fontsize)
|
|
108
|
+
self.font_color = fontcolor
|
|
109
|
+
self.background_t_f = background_t_f
|
|
110
|
+
self.background_color = backgroundcolor
|
|
111
|
+
self.x, self.y = x, y
|
|
112
|
+
self.refresh_image(string)
|
|
113
|
+
|
|
114
|
+
# this function will update the visiblevariable you dont need to use it but its an optimized way of allowing the variable to change
|
|
115
|
+
def refresh_image(self, new_val):
|
|
116
|
+
font_obj = get_font(self.font_name, self.font_size)
|
|
117
|
+
string_val = str(new_val)
|
|
118
|
+
|
|
119
|
+
text_surface = font_obj.render(string_val, True, self.font_color)
|
|
120
|
+
w, h = text_surface.get_size()
|
|
121
|
+
|
|
122
|
+
if not self.background_t_f:
|
|
123
|
+
self.image = pygame.Surface((w, h), pygame.SRCALPHA).convert_alpha()
|
|
124
|
+
self.image.blit(text_surface, (0, 0))
|
|
125
|
+
else:
|
|
126
|
+
self.image = pygame.Surface((w + 4, h + 4)).convert()
|
|
127
|
+
self.image.fill(self.background_color)
|
|
128
|
+
self.image.blit(text_surface, (2, 2))
|
|
129
|
+
|
|
130
|
+
self.rect = self.image.get_rect(topleft=(self.x, self.y))
|
|
131
|
+
|
|
132
|
+
# this is bassically a group of variables but visible and it will layout them out either vertically or horizontally you dont need to make multiple visible variables for this
|
|
133
|
+
class PygameVisibleList(pygame.sprite.Group):
|
|
134
|
+
def __init__(self, font, fontsize, fontcolor, x, y, variablegroup,
|
|
135
|
+
vh, v_bg_t_f, v_bg_color=None,
|
|
136
|
+
l_bg_t_f=False, l_bg_color=None):
|
|
137
|
+
|
|
138
|
+
if vh.lower() not in ["vertical", "horizontal"]:
|
|
139
|
+
raise ValueError(f"Layout 'vh' must be 'vertical' or 'horizontal', not '{vh}'")
|
|
140
|
+
|
|
141
|
+
if not isinstance(variablegroup, (list, tuple)):
|
|
142
|
+
raise TypeError(f"variablegroup must be a list or tuple of data, not {type(variablegroup).__name__}")
|
|
143
|
+
|
|
144
|
+
if l_bg_t_f and l_bg_color is None:
|
|
145
|
+
raise ValueError("When l_bg_t_f is True, you must provide a list_background_color")
|
|
146
|
+
|
|
147
|
+
super().__init__()
|
|
148
|
+
self.font, self.fontsize, self.fontcolor = font, fontsize, fontcolor
|
|
149
|
+
self.x, self.y = x, y
|
|
150
|
+
self.vh = vh.lower()
|
|
151
|
+
self.v_bg_t_f, self.v_bg_color = v_bg_t_f, v_bg_color
|
|
152
|
+
self.l_bg_t_f, self.l_bg_color = l_bg_t_f, l_bg_color
|
|
153
|
+
self.refresh_list(variablegroup)
|
|
154
|
+
|
|
155
|
+
# this function will do the same as the visible variable but for the whole list
|
|
156
|
+
def refresh_list(self, variablegroup):
|
|
157
|
+
self.empty()
|
|
158
|
+
curr_x, curr_y = self.x, self.y
|
|
159
|
+
spacing = 10
|
|
160
|
+
for item in variablegroup:
|
|
161
|
+
node = PygameVisibleVariable(self.font, self.fontsize, self.fontcolor,
|
|
162
|
+
curr_x, curr_y, item, self.v_bg_t_f, self.v_bg_color)
|
|
163
|
+
self.add(node)
|
|
164
|
+
if self.vh == "vertical":
|
|
165
|
+
curr_y += node.rect.height + spacing
|
|
166
|
+
else:
|
|
167
|
+
curr_x += node.rect.width + spacing
|
|
168
|
+
|
|
169
|
+
# this function lets you just draw the list
|
|
170
|
+
def draw(self, surface):
|
|
171
|
+
if self.l_bg_t_f and self.l_bg_color and self.sprites():
|
|
172
|
+
all_rects = [s.rect for s in self.sprites()]
|
|
173
|
+
combined_rect = all_rects[0].unionall(all_rects[1:])
|
|
174
|
+
bg_rect = combined_rect.inflate(15, 15)
|
|
175
|
+
pygame.draw.rect(surface, self.l_bg_color, bg_rect)
|
|
176
|
+
super().draw(surface)
|
|
177
|
+
|
|
178
|
+
# creates a simple health bar for pygame you can use to show health
|
|
179
|
+
class PygameHealthBar(pygame.sprite.Sprite):
|
|
180
|
+
def __init__(self, x, y, width_per_1hp, max_health, current_health, bar_height, border_color, health_color):
|
|
181
|
+
super().__init__()
|
|
182
|
+
if width_per_1hp <= 0:
|
|
183
|
+
raise ValueError("width_per_1hp must be a positive number.")
|
|
184
|
+
if max_health <= 0:
|
|
185
|
+
raise ValueError("max_health must be greater than 0.")
|
|
186
|
+
|
|
187
|
+
self.x, self.y = x, y
|
|
188
|
+
self.w_p_1 = width_per_1hp
|
|
189
|
+
self.max_h = max_health
|
|
190
|
+
self.height = bar_height
|
|
191
|
+
self.b_color = border_color
|
|
192
|
+
self.h_color = health_color
|
|
193
|
+
|
|
194
|
+
self.image = pygame.Surface((max_health * width_per_1hp + 4, bar_height)).convert()
|
|
195
|
+
self.rect = self.image.get_rect(topleft=(x, y))
|
|
196
|
+
|
|
197
|
+
self.refresh_bar(current_health)
|
|
198
|
+
|
|
199
|
+
"""Redraws the bar. Only need to pass the new health value!"""
|
|
200
|
+
def refresh_bar(self, current_health):
|
|
201
|
+
self.image.fill(self.b_color)
|
|
202
|
+
|
|
203
|
+
draw_health = current_health
|
|
204
|
+
if draw_health > self.max_h:
|
|
205
|
+
draw_health = self.max_h
|
|
206
|
+
if draw_health < 0:
|
|
207
|
+
draw_health = 0
|
|
208
|
+
|
|
209
|
+
pygame.draw.rect(self.image, self.h_color, (2, 2, draw_health * self.w_p_1, self.height - 4))
|
|
210
|
+
|
|
211
|
+
def update_hp(self, current_health):
|
|
212
|
+
"""The 'Easy' way to change health in your loop."""
|
|
213
|
+
self.refresh_bar(current_health)
|
|
214
|
+
|
|
215
|
+
# this is a slider that can be dragged left and right to get to get a value you want that will customize something in your game
|
|
216
|
+
class PygameDraggableSlider(PygameClickedCalculator):
|
|
217
|
+
def __init__(self, color, startingX, y, min_x, max_x):
|
|
218
|
+
super().__init__()
|
|
219
|
+
self.image = pygame.Surface((20, 20), pygame.SRCALPHA).convert_alpha()
|
|
220
|
+
pygame.draw.circle(self.image, color, (10, 10), 10)
|
|
221
|
+
|
|
222
|
+
self.rect = self.image.get_rect(center=(startingX, y))
|
|
223
|
+
self.color = color
|
|
224
|
+
self.dragging = False
|
|
225
|
+
|
|
226
|
+
self.min_x = min_x
|
|
227
|
+
self.max_x = max_x
|
|
228
|
+
|
|
229
|
+
def handle_input(self, event):
|
|
230
|
+
if event.type == pygame.MOUSEBUTTONDOWN:
|
|
231
|
+
if self.rect.collidepoint(event.pos):
|
|
232
|
+
self.dragging = True
|
|
233
|
+
|
|
234
|
+
elif event.type == pygame.MOUSEBUTTONUP:
|
|
235
|
+
self.dragging = False
|
|
236
|
+
|
|
237
|
+
elif event.type == pygame.MOUSEMOTION:
|
|
238
|
+
if self.dragging:
|
|
239
|
+
new_x = event.pos[0]
|
|
240
|
+
self.rect.centerx = max(self.min_x, min(new_x, self.max_x))
|
|
241
|
+
|
|
242
|
+
def get_value(self):
|
|
243
|
+
total_range = self.max_x - self.min_x
|
|
244
|
+
current_pos = self.rect.centerx - self.min_x
|
|
245
|
+
return current_pos / total_range
|
|
246
|
+
|
|
247
|
+
class PygameScreenShake:
|
|
248
|
+
def __init__(self, seed=None):
|
|
249
|
+
self.s0 = seed or int(time.time() * 1000) & 0xFFFFFFFFFFFFFFFF
|
|
250
|
+
self.s1 = 0xBEA123456789ABCD ^ self.s0
|
|
251
|
+
self.offset = pygame.Vector2(0, 0)
|
|
252
|
+
self.duration = 0
|
|
253
|
+
self.intensity = 0
|
|
254
|
+
self.impact_vec = pygame.Vector2(0, 0)
|
|
255
|
+
|
|
256
|
+
def _next_xorshift(self):
|
|
257
|
+
x, y = self.s0, self.s1
|
|
258
|
+
self.s0 = y
|
|
259
|
+
x ^= (x << 23) & 0xFFFFFFFFFFFFFFFF
|
|
260
|
+
self.s1 = (x ^ y ^ (x >> 17) ^ (y >> 26)) & 0xFFFFFFFFFFFFFFFF
|
|
261
|
+
return (self.s1 + y) & 0xFFFFFFFFFFFFFFFF
|
|
262
|
+
|
|
263
|
+
def _get_rand_float(self):
|
|
264
|
+
return (self._next_xorshift() / 0xFFFFFFFFFFFFFFFF) * 2 - 1
|
|
265
|
+
|
|
266
|
+
# this really is the only neccessary thing if you would like you can figure out how to use the rest but just this command is all you need
|
|
267
|
+
def shake(self, intensity=None, duration=None, impact_pos=None, center_pos=None):
|
|
268
|
+
if intensity is not None:
|
|
269
|
+
self.intensity = intensity
|
|
270
|
+
self.duration = duration
|
|
271
|
+
if impact_pos and center_pos:
|
|
272
|
+
self.impact_vec = (pygame.Vector2(center_pos) - pygame.Vector2(impact_pos))
|
|
273
|
+
if self.impact_vec.length() > 0:
|
|
274
|
+
self.impact_vec = self.impact_vec.normalize()
|
|
275
|
+
else:
|
|
276
|
+
self.impact_vec = pygame.Vector2(0, 0)
|
|
277
|
+
|
|
278
|
+
if self.duration > 0:
|
|
279
|
+
self.duration -= 1
|
|
280
|
+
rand_vec = pygame.Vector2(self._get_rand_float(), self._get_rand_float())
|
|
281
|
+
if self.impact_vec.length() > 0:
|
|
282
|
+
alignment = rand_vec.dot(self.impact_vec)
|
|
283
|
+
self.offset = self.impact_vec * alignment * self.intensity
|
|
284
|
+
else:
|
|
285
|
+
self.offset = rand_vec * self.intensity
|
|
286
|
+
else:
|
|
287
|
+
self.offset = pygame.Vector2(0, 0)
|
|
288
|
+
|
|
289
|
+
return self.offset
|
|
290
|
+
|
|
291
|
+
# a simple text box that only allows strings but will wrap text and gives you a max length for whatever you want it to be
|
|
292
|
+
class PygameTextBox(pygame.sprite.Sprite):
|
|
293
|
+
def __init__(self, x, y, width, string, font_name, fontsize, fontcolor,
|
|
294
|
+
background_t_f=False, backgroundcolor=None,
|
|
295
|
+
typewrite_t_f=False, time_per_char=50):
|
|
296
|
+
super().__init__()
|
|
297
|
+
|
|
298
|
+
if isinstance(x, (list, tuple)):
|
|
299
|
+
raise TypeError(f"EasyCode Error: 'x' must be a number, but you passed a {type(x).__name__}. Check the order of your arguments in PygameDialogueText!")
|
|
300
|
+
|
|
301
|
+
self.x = int(x)
|
|
302
|
+
self.y = int(y)
|
|
303
|
+
self.width = int(width)
|
|
304
|
+
self.full_string = str(string)
|
|
305
|
+
self.font = get_font(font_name, int(fontsize))
|
|
306
|
+
self.color = fontcolor
|
|
307
|
+
self.bg_enabled = background_t_f
|
|
308
|
+
self.bg_color = backgroundcolor
|
|
309
|
+
|
|
310
|
+
self.typewrite_enabled = typewrite_t_f
|
|
311
|
+
self.ms_per_char = time_per_char
|
|
312
|
+
self.char_index = 0
|
|
313
|
+
self.last_type_time = pygame.time.get_ticks()
|
|
314
|
+
|
|
315
|
+
if not self.typewrite_enabled:
|
|
316
|
+
self.char_index = len(self.full_string)
|
|
317
|
+
|
|
318
|
+
self.refresh_text()
|
|
319
|
+
|
|
320
|
+
def update(self):
|
|
321
|
+
"""Standard Pygame update to handle typewriter timing."""
|
|
322
|
+
if self.typewrite_enabled and self.char_index < len(self.full_string):
|
|
323
|
+
now = pygame.time.get_ticks()
|
|
324
|
+
if now - self.last_type_time >= self.ms_per_char:
|
|
325
|
+
self.char_index += 1
|
|
326
|
+
self.last_type_time = now
|
|
327
|
+
self.refresh_text()
|
|
328
|
+
|
|
329
|
+
def wrap_text(self, text):
|
|
330
|
+
"""Splits text into lines that fit within self.width."""
|
|
331
|
+
words = str(text).split(' ')
|
|
332
|
+
lines, current_line = [], []
|
|
333
|
+
for word in words:
|
|
334
|
+
if self.font.size(' '.join(current_line + [word]))[0] <= self.width:
|
|
335
|
+
current_line.append(word)
|
|
336
|
+
else:
|
|
337
|
+
lines.append(' '.join(current_line))
|
|
338
|
+
current_line = [word]
|
|
339
|
+
lines.append(' '.join(current_line))
|
|
340
|
+
return lines
|
|
341
|
+
|
|
342
|
+
def refresh_text(self):
|
|
343
|
+
"""Redraws the surface based on how many characters are revealed."""
|
|
344
|
+
visible_text = self.full_string[:self.char_index]
|
|
345
|
+
lines = self.wrap_text(visible_text)
|
|
346
|
+
|
|
347
|
+
line_height = self.font.get_linesize()
|
|
348
|
+
total_height = len(lines) * line_height
|
|
349
|
+
|
|
350
|
+
if self.bg_enabled:
|
|
351
|
+
self.image = pygame.Surface((self.width + 10, total_height + 10)).convert()
|
|
352
|
+
self.image.fill(self.bg_color)
|
|
353
|
+
padding = 5
|
|
354
|
+
else:
|
|
355
|
+
self.image = pygame.Surface((self.width, total_height), pygame.SRCALPHA).convert_alpha()
|
|
356
|
+
padding = 0
|
|
357
|
+
|
|
358
|
+
for i, line in enumerate(lines):
|
|
359
|
+
text_surf = self.font.render(line, True, self.color)
|
|
360
|
+
self.image.blit(text_surf, (padding, padding + (i * line_height)))
|
|
361
|
+
|
|
362
|
+
# Update the physics box
|
|
363
|
+
self.rect = self.image.get_rect(topleft=(self.x, self.y))
|
|
364
|
+
|
|
365
|
+
# a dialogue tool that when used will take a list of strings turn them into PygameTextBox(s) and has a next string which can be triggered by whatever you want
|
|
366
|
+
class PygameDialogueText(pygame.sprite.Group):
|
|
367
|
+
def __init__(self, text_list, x, y, width, font_name, fontsize, fontcolor,
|
|
368
|
+
background_t_f=False, backgroundcolor=None,
|
|
369
|
+
typewrite_t_f=False, time_per_char=50):
|
|
370
|
+
super().__init__()
|
|
371
|
+
|
|
372
|
+
self.text_list = text_list
|
|
373
|
+
self.index = 0
|
|
374
|
+
self.x, self.y, self.width = x, y, width
|
|
375
|
+
self.font_name, self.font_size = font_name, fontsize
|
|
376
|
+
self.font_color = fontcolor
|
|
377
|
+
self.bg_t_f, self.bg_color = background_t_f, backgroundcolor
|
|
378
|
+
self.typewrite_t_f, self.time_per_char = typewrite_t_f, time_per_char
|
|
379
|
+
|
|
380
|
+
self._update_display()
|
|
381
|
+
|
|
382
|
+
def _update_display(self):
|
|
383
|
+
self.empty()
|
|
384
|
+
new_box = PygameTextBox(
|
|
385
|
+
self.x, self.y, self.width,
|
|
386
|
+
self.text_list[self.index],
|
|
387
|
+
self.font_name, self.font_size, self.font_color,
|
|
388
|
+
self.bg_t_f, self.bg_color,
|
|
389
|
+
self.typewrite_t_f, self.time_per_char
|
|
390
|
+
)
|
|
391
|
+
self.add(new_box)
|
|
392
|
+
|
|
393
|
+
def next_string(self):
|
|
394
|
+
self.index += 1
|
|
395
|
+
if self.index >= len(self.text_list):
|
|
396
|
+
self.index = 0
|
|
397
|
+
self._update_display()
|
|
398
|
+
|
|
399
|
+
def update(self):
|
|
400
|
+
"""Passes the update command to the internal TextBox."""
|
|
401
|
+
for sprite in self.sprites():
|
|
402
|
+
sprite.update()
|
|
403
|
+
|
|
404
|
+
# these are some built in sounds
|
|
405
|
+
class PygameSoundManager:
|
|
406
|
+
def __init__(self):
|
|
407
|
+
if not pygame.mixer.get_init():
|
|
408
|
+
pygame.mixer.pre_init(44100, -16, 2, 512)
|
|
409
|
+
pygame.mixer.init()
|
|
410
|
+
self.sounds = {}
|
|
411
|
+
self.base_dir = os.path.dirname(os.path.abspath(__file__))
|
|
412
|
+
|
|
413
|
+
def load(self, name: str, filename: str):
|
|
414
|
+
if filename.startswith("sounds/"):
|
|
415
|
+
clean_name = filename.replace("sounds/", "")
|
|
416
|
+
else:
|
|
417
|
+
clean_name = filename
|
|
418
|
+
|
|
419
|
+
full_path = os.path.join(self.base_dir, "sounds", clean_name)
|
|
420
|
+
|
|
421
|
+
def play(self, name: str):
|
|
422
|
+
if name in self.sounds:
|
|
423
|
+
self.sounds[name].play()
|
|
424
|
+
|
|
425
|
+
def is_playing(self):
|
|
426
|
+
return pygame.mixer.get_busy()
|
|
427
|
+
|
|
428
|
+
def play_until_done(self, name: str):
|
|
429
|
+
if name in self.sounds:
|
|
430
|
+
if not self.is_playing():
|
|
431
|
+
self.sounds[name].play()
|
|
432
|
+
|
|
433
|
+
# this is a bigstring dont worry about what this thing does or actually is just use it as a string except has no limit in characters plus when it comes to short string it saves memory
|
|
434
|
+
class BigString:
|
|
435
|
+
def __init__(self, initial_text=""):
|
|
436
|
+
self.data = 0
|
|
437
|
+
self.set(str(initial_text))
|
|
438
|
+
|
|
439
|
+
def set(self, text):
|
|
440
|
+
byte_data = text.encode('utf-8')
|
|
441
|
+
self.data = int.from_bytes(byte_data, 'big')
|
|
442
|
+
|
|
443
|
+
def get(self):
|
|
444
|
+
if self.data == 0: return ""
|
|
445
|
+
byte_length = (self.data.bit_length() + 7) // 8
|
|
446
|
+
return self.data.to_bytes(byte_length, 'big').decode('utf-8')
|
|
447
|
+
|
|
448
|
+
def __add__(self, other):
|
|
449
|
+
"""Allows: bigstr("hi") + " there" """
|
|
450
|
+
return bigstr(self.get() + str(other))
|
|
451
|
+
|
|
452
|
+
def __radd__(self, other):
|
|
453
|
+
"""Allows: "hello " + bigstr("world") """
|
|
454
|
+
return bigstr(str(other) + self.get())
|
|
455
|
+
|
|
456
|
+
def __eq__(self, other):
|
|
457
|
+
"""Allows: if my_bigstr == "test": """
|
|
458
|
+
return self.get() == str(other)
|
|
459
|
+
|
|
460
|
+
def __len__(self):
|
|
461
|
+
"""Allows: len(my_bigstr) """
|
|
462
|
+
return len(self.get())
|
|
463
|
+
|
|
464
|
+
def __str__(self):
|
|
465
|
+
"""Allows: print(my_bigstr) """
|
|
466
|
+
return self.get()
|
|
467
|
+
|
|
468
|
+
def __repr__(self):
|
|
469
|
+
"""Shows up as bigstr('text') in the console"""
|
|
470
|
+
return f"bigstr('{self.get()}')"
|
|
471
|
+
|
|
472
|
+
# similiar to the bigstring it can hold more number but because it uses bigints and not floats it actually is faster calculations and no limit and perfect accuracy just dont destroy your PC by not adding a limit to accuracy
|
|
473
|
+
class BigDecimal:
|
|
474
|
+
def __init__(self, value, scale=0):
|
|
475
|
+
if isinstance(value, str):
|
|
476
|
+
if "." in value:
|
|
477
|
+
parts = value.split(".")
|
|
478
|
+
self.scale = len(parts[1])
|
|
479
|
+
self.value = int(parts[0] + parts[1])
|
|
480
|
+
else:
|
|
481
|
+
self.value = int(value)
|
|
482
|
+
self.scale = 0
|
|
483
|
+
else:
|
|
484
|
+
self.value = int(value)
|
|
485
|
+
self.scale = scale
|
|
486
|
+
|
|
487
|
+
def to_float(self):
|
|
488
|
+
return self.value / (10 ** self.scale)
|
|
489
|
+
|
|
490
|
+
def _align(self, other):
|
|
491
|
+
if not isinstance(other, BigDecimal):
|
|
492
|
+
other = BigDecimal(str(other))
|
|
493
|
+
|
|
494
|
+
new_scale = max(self.scale, other.scale)
|
|
495
|
+
v1 = self.value * (10 ** (new_scale - self.scale))
|
|
496
|
+
v2 = other.value * (10 ** (new_scale - other.scale))
|
|
497
|
+
return v1, v2, new_scale
|
|
498
|
+
|
|
499
|
+
def __add__(self, other):
|
|
500
|
+
v1, v2, s = self._align(other)
|
|
501
|
+
return BigDecimal(v1 + v2, s)
|
|
502
|
+
|
|
503
|
+
def __sub__(self, other):
|
|
504
|
+
v1, v2, s = self._align(other)
|
|
505
|
+
return BigDecimal(v1 - v2, s)
|
|
506
|
+
|
|
507
|
+
def __mul__(self, other):
|
|
508
|
+
if not isinstance(other, BigDecimal):
|
|
509
|
+
other = BigDecimal(str(other))
|
|
510
|
+
return BigDecimal(self.value * other.value, self.scale + other.scale)
|
|
511
|
+
|
|
512
|
+
def __str__(self):
|
|
513
|
+
s = str(abs(self.value)).zfill(self.scale + 1)
|
|
514
|
+
res = s[:-self.scale] + "." + s[-self.scale:]
|
|
515
|
+
return f"-{res}" if self.value < 0 else res
|
|
516
|
+
|
|
517
|
+
# like the bigdecimal instead of floats and decimals in this vector its bigints and bigdecimals and its for the same reason bigints are better then floats mostly
|
|
518
|
+
class BigVectorBase:
|
|
519
|
+
def __init__(self, *args):
|
|
520
|
+
self.components = [
|
|
521
|
+
arg if isinstance(arg, BigDecimal) else bigdec(str(arg))
|
|
522
|
+
for arg in args
|
|
523
|
+
]
|
|
524
|
+
|
|
525
|
+
def __add__(self, other):
|
|
526
|
+
if len(self.components) == len(other.components):
|
|
527
|
+
new_comps = [a + b for a, b in zip(self.components, other.components)]
|
|
528
|
+
return self.__class__(*new_comps)
|
|
529
|
+
raise ValueError(f"Cannot add {len(self.components)}D and {len(other.components)}D vectors!")
|
|
530
|
+
|
|
531
|
+
def __sub__(self, other):
|
|
532
|
+
if len(self.components) == len(other.components):
|
|
533
|
+
new_comps = [a - b for a, b in zip(self.components, other.components)]
|
|
534
|
+
return self.__class__(*new_comps)
|
|
535
|
+
raise ValueError("Dimension mismatch during subtraction!")
|
|
536
|
+
|
|
537
|
+
def __mul__(self, scalar):
|
|
538
|
+
new_comps = [a * scalar for a in self.components]
|
|
539
|
+
return self.__class__(*new_comps)
|
|
540
|
+
|
|
541
|
+
def __str__(self):
|
|
542
|
+
coords = ", ".join(str(c) for c in self.components)
|
|
543
|
+
return f"({coords})"
|
|
544
|
+
|
|
545
|
+
def __repr__(self):
|
|
546
|
+
return self.__str__()
|
|
547
|
+
|
|
548
|
+
def to_pygame(self):
|
|
549
|
+
if len(self.components) == 2:
|
|
550
|
+
return pygame.Vector2(self.components[0].to_float(), self.components[1].to_float())
|
|
551
|
+
elif len(self.components) == 3:
|
|
552
|
+
return pygame.Vector3(self.components[0].to_float(), self.components[1].to_float(), self.components[2].to_float())
|
|
553
|
+
return tuple(c.to_float() for c in self.components)
|
|
554
|
+
|
|
555
|
+
def to_tuple(self):
|
|
556
|
+
return tuple(c.to_float() for c in self.components)
|
|
557
|
+
|
|
558
|
+
def magnitude(self):
|
|
559
|
+
return (self.x * self.x + self.y * self.y)
|
|
560
|
+
|
|
561
|
+
class BigVector2(BigVectorBase):
|
|
562
|
+
def __init__(self, x, y):
|
|
563
|
+
super().__init__(x, y)
|
|
564
|
+
self.x, self.y = self.components[0], self.components[1]
|
|
565
|
+
|
|
566
|
+
class BigVector3(BigVectorBase):
|
|
567
|
+
def __init__(self, x, y, z):
|
|
568
|
+
super().__init__(x, y, z)
|
|
569
|
+
self.x, self.y, self.z = self.components[0], self.components[1], self.components[2]
|
|
570
|
+
|
|
571
|
+
class BigVector4(BigVectorBase):
|
|
572
|
+
def __init__(self, x, y, z, w):
|
|
573
|
+
super().__init__(x, y, z, w)
|
|
574
|
+
self.x, self.y, self.z, self.w = self.components[0], self.components[1], self.components[2], self.components[3]
|
|
575
|
+
|
|
576
|
+
class PygletVisibleVariable(pyglet.text.Label):
|
|
577
|
+
def __init__(self, font, fontsize, fontcolor, x, y, string, background_t_f, backgroundcolor=None):
|
|
578
|
+
rgba_font = (*fontcolor, 255) if len(fontcolor) == 3 else fontcolor
|
|
579
|
+
|
|
580
|
+
bg_color = None
|
|
581
|
+
if background_t_f and backgroundcolor:
|
|
582
|
+
bg_color = (*backgroundcolor, 255) if len(backgroundcolor) == 3 else backgroundcolor
|
|
583
|
+
|
|
584
|
+
super().__init__(str(string), font_name=font, font_size=fontsize,
|
|
585
|
+
color=rgba_font, x=x, y=y, background_color=bg_color)
|
|
586
|
+
|
|
587
|
+
class PygletHealthBar:
|
|
588
|
+
def __init__(self, x, y, width_per_hp, max_hp, current_hp, height, border_color, health_color, batch=None):
|
|
589
|
+
self.max_hp = max_hp
|
|
590
|
+
self.w_p_hp = width_per_hp
|
|
591
|
+
|
|
592
|
+
self.bg = pyglet.shapes.Rectangle(x, y, max_hp * width_per_hp, height, color=border_color, batch=batch)
|
|
593
|
+
self.bar = pyglet.shapes.Rectangle(x + 2, y + 2, current_hp * width_per_hp - 4, height - 4, color=health_color, batch=batch)
|
|
594
|
+
|
|
595
|
+
def refresh_bar(self, current_hp):
|
|
596
|
+
safe_hp = max(0, min(current_hp, self.max_hp))
|
|
597
|
+
self.bar.width = max(0, (safe_hp * self.w_p_hp) - 4)
|
|
598
|
+
|
|
599
|
+
class PygletVisibleList:
|
|
600
|
+
def __init__(self, font, fontsize, fontcolor, x, y, items, vh="vertical", batch=None):
|
|
601
|
+
self.items = []
|
|
602
|
+
self.batch = batch
|
|
603
|
+
self.x, self.y = x, y
|
|
604
|
+
self.font, self.size, self.color = font, fontsize, fontcolor
|
|
605
|
+
self.vh = vh.lower()
|
|
606
|
+
self.refresh_list(items)
|
|
607
|
+
|
|
608
|
+
def refresh_list(self, items):
|
|
609
|
+
self.items = []
|
|
610
|
+
curr_x, curr_y = self.x, self.y
|
|
611
|
+
spacing = 10
|
|
612
|
+
|
|
613
|
+
for text in items:
|
|
614
|
+
label = pyglet.text.Label(str(text), font_name=self.font, font_size=self.size,
|
|
615
|
+
color=(*self.color, 255), x=curr_x, y=curr_y, batch=self.batch)
|
|
616
|
+
self.items.append(label)
|
|
617
|
+
if self.vh == "vertical":
|
|
618
|
+
curr_y -= (self.size + spacing)
|
|
619
|
+
else:
|
|
620
|
+
curr_x += (len(str(text)) * self.size * 0.6) + spacing
|
|
621
|
+
|
|
622
|
+
class PygletTextBox:
|
|
623
|
+
def __init__(self, x, y, width, initial_text="", batch=None, window=None):
|
|
624
|
+
self.doc = pyglet.text.document.UnformattedDocument(initial_text)
|
|
625
|
+
self.layout = pyglet.text.layout.IncrementalTextLayout(self.doc, width, 30, multiline=False, batch=batch)
|
|
626
|
+
self.layout.x, self.layout.y = x, y
|
|
627
|
+
|
|
628
|
+
self.caret = pyglet.text.caret.Caret(self.layout)
|
|
629
|
+
|
|
630
|
+
if window:
|
|
631
|
+
window.push_handlers(self.caret)
|
|
632
|
+
|
|
633
|
+
@property
|
|
634
|
+
def text(self):
|
|
635
|
+
return self.doc.text
|
|
636
|
+
|
|
637
|
+
class PygletDialogueText:
|
|
638
|
+
def __init__(self, text_list, x, y, width, font_name, fontsize, fontcolor,
|
|
639
|
+
background_t_f=False, backgroundcolor=None,
|
|
640
|
+
typewrite_t_f=True, time_per_char=0.05, batch=None):
|
|
641
|
+
self.text_list = text_list
|
|
642
|
+
self.index = 0
|
|
643
|
+
self.batch = batch
|
|
644
|
+
self.x, self.y, self.width = x, y, width
|
|
645
|
+
self.font, self.size, self.color = font_name, fontsize, fontcolor
|
|
646
|
+
|
|
647
|
+
self.bg = None
|
|
648
|
+
if background_t_f and backgroundcolor:
|
|
649
|
+
self.bg = pyglet.shapes.Rectangle(x-5, y-5, width+10, (fontsize*len(text_list[0])//10)+10,
|
|
650
|
+
color=backgroundcolor, batch=batch)
|
|
651
|
+
self.bg.opacity = 200
|
|
652
|
+
|
|
653
|
+
self.full_text = text_list[self.index]
|
|
654
|
+
self.display_text = ""
|
|
655
|
+
self.char_index = 0
|
|
656
|
+
self.typewrite_enabled = typewrite_t_f
|
|
657
|
+
|
|
658
|
+
self.label = pyglet.text.Label("", font_name=font_name, font_size=fontsize,
|
|
659
|
+
color=(*fontcolor, 255), x=x, y=y, width=width,
|
|
660
|
+
multiline=True, batch=batch)
|
|
661
|
+
|
|
662
|
+
if self.typewrite_enabled:
|
|
663
|
+
pyglet.clock.schedule_interval(self._update_typewriter, time_per_char)
|
|
664
|
+
else:
|
|
665
|
+
self.label.text = self.full_text
|
|
666
|
+
|
|
667
|
+
def _update_typewriter(self, dt):
|
|
668
|
+
if self.char_index < len(self.full_text):
|
|
669
|
+
self.char_index += 1
|
|
670
|
+
self.label.text = self.full_text[:self.char_index]
|
|
671
|
+
|
|
672
|
+
def next_string(self):
|
|
673
|
+
self.index = (self.index + 1) % len(self.text_list)
|
|
674
|
+
self.full_text = self.text_list[self.index]
|
|
675
|
+
self.char_index = 0
|
|
676
|
+
if not self.typewrite_enabled:
|
|
677
|
+
self.label.text = self.full_text
|
|
678
|
+
|
|
679
|
+
class PygletScreenShake(PygameScreenShake):
|
|
680
|
+
def apply_to_window(self, window):
|
|
681
|
+
offset = self.shake()
|
|
682
|
+
window.view = window.view.from_translation((offset.x, offset.y, 0))
|
|
683
|
+
|
|
684
|
+
class PygletDraggableSlider:
|
|
685
|
+
def __init__(self, color, starting_x, y, min_x, max_x, batch=None, window=None):
|
|
686
|
+
self.min_x = min_x
|
|
687
|
+
self.max_x = max_x
|
|
688
|
+
self.y = y
|
|
689
|
+
self.dragging = False
|
|
690
|
+
|
|
691
|
+
self.track = pyglet.shapes.Line(min_x, y, max_x, y, width=2,
|
|
692
|
+
color=(100, 100, 100, 255), batch=batch)
|
|
693
|
+
|
|
694
|
+
self.handle = pyglet.shapes.Circle(starting_x, y, 10, color=color, batch=batch)
|
|
695
|
+
|
|
696
|
+
if window:
|
|
697
|
+
window.push_handlers(on_mouse_press=self.on_mouse_press,
|
|
698
|
+
on_mouse_release=self.on_mouse_release,
|
|
699
|
+
on_mouse_drag=self.on_mouse_drag)
|
|
700
|
+
|
|
701
|
+
def on_mouse_press(self, x, y, button, modifiers):
|
|
702
|
+
dist = ((x - self.handle.x)**2 + (y - self.handle.y)**2)**0.5
|
|
703
|
+
if dist < 15:
|
|
704
|
+
self.dragging = True
|
|
705
|
+
|
|
706
|
+
def on_mouse_release(self, x, y, button, modifiers):
|
|
707
|
+
self.dragging = False
|
|
708
|
+
|
|
709
|
+
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
|
|
710
|
+
if self.dragging:
|
|
711
|
+
# Constrain movement to the min/max X boundaries
|
|
712
|
+
self.handle.x = max(self.min_x, min(x, self.max_x))
|
|
713
|
+
|
|
714
|
+
def get_value(self):
|
|
715
|
+
total_range = self.max_x - self.min_x
|
|
716
|
+
current_pos = self.handle.x - self.min_x
|
|
717
|
+
return current_pos / total_range
|
|
718
|
+
|
|
719
|
+
class ArcadeVisibleVariable(arcade.Text):
|
|
720
|
+
def __init__(self, font, fontsize, fontcolor, x, y, string, background_t_f, backgroundcolor=None):
|
|
721
|
+
super().__init__(str(string), x, y, color=fontcolor, font_size=fontsize, font_name=font)
|
|
722
|
+
self.bg_enabled = background_t_f
|
|
723
|
+
self.bg_color = backgroundcolor
|
|
724
|
+
|
|
725
|
+
def draw(self):
|
|
726
|
+
if self.bg_enabled and self.bg_color:
|
|
727
|
+
arcade.draw_lrtb_rectangle_filled(
|
|
728
|
+
self.left - 5, self.right + 5,
|
|
729
|
+
self.top + 5, self.bottom - 5,
|
|
730
|
+
self.bg_color
|
|
731
|
+
)
|
|
732
|
+
super().draw()
|
|
733
|
+
|
|
734
|
+
def bigstr(initial_text=""):
|
|
735
|
+
return BigString(initial_text)
|
|
736
|
+
|
|
737
|
+
def bigdec(value, scale=0):
|
|
738
|
+
return BigDecimal(value, scale)
|
|
739
|
+
|
|
740
|
+
bigvector2 = BigVector2
|
|
741
|
+
# --- PYGAME WRAPPERS ---
|
|
742
|
+
class PygameSprite(pygame.sprite.Sprite):
|
|
743
|
+
def __init__(self, x="0.0", y="0.0", width=50, height=50, color=(255, 255, 255)):
|
|
744
|
+
super().__init__()
|
|
745
|
+
self.pos = bigvector2(str(x), str(y))
|
|
746
|
+
self.image = pygame.Surface((width, height))
|
|
747
|
+
self.image.fill(color)
|
|
748
|
+
self.rect = self.image.get_rect()
|
|
749
|
+
self.sync()
|
|
750
|
+
|
|
751
|
+
def sync(self):
|
|
752
|
+
p = self.pos.to_pygame()
|
|
753
|
+
self.rect.topleft = (int(p.x), int(p.y))
|
|
754
|
+
|
|
755
|
+
class PygameGroup(pygame.sprite.Group):
|
|
756
|
+
def draw_all(self, surface):
|
|
757
|
+
self.draw(surface)
|
|
758
|
+
|
|
759
|
+
class PygameLayeredGroup(pygame.sprite.LayeredUpdates):
|
|
760
|
+
pass
|
|
761
|
+
|
|
762
|
+
# --- ARCADE WRAPPERS ---
|
|
763
|
+
class ArcadeSprite(arcade.Sprite):
|
|
764
|
+
def __init__(self, x="0.0", y="0.0", scale=1.0):
|
|
765
|
+
super().__init__(scale=scale)
|
|
766
|
+
self.pos = bigvector2(str(x), str(y))
|
|
767
|
+
self.center_x = self.pos.x.to_float()
|
|
768
|
+
self.center_y = self.pos.y.to_float()
|
|
769
|
+
|
|
770
|
+
class ArcadeGroup(arcade.SpriteList):
|
|
771
|
+
pass
|
|
772
|
+
|
|
773
|
+
# --- PYGLET WRAPPERS ---
|
|
774
|
+
class PygletSprite(pyglet.sprite.Sprite):
|
|
775
|
+
def __init__(self, img, x="0.0", y="0.0", batch=None):
|
|
776
|
+
self.pos = bigvector2(str(x), str(y))
|
|
777
|
+
super().__init__(img, x=self.pos.x.to_float(), y=self.pos.y.to_float(), batch=batch)
|
|
778
|
+
|
|
779
|
+
class PygletGroup(pyglet.graphics.Group):
|
|
780
|
+
pass
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: easycode-infinite
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A simple GUI addon for Pygame, Pyglet, and Arcade
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
Requires-Dist: pygame-ce
|
|
7
|
+
Requires-Dist: pyglet>=2.0
|
|
8
|
+
Requires-Dist: arcade>=3.0
|
|
9
|
+
Requires-Dist: roman
|
|
10
|
+
Dynamic: license-file
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
easycode-infinite/__init__.py
|
|
5
|
+
easycode-infinite/easycode_addons.py
|
|
6
|
+
easycode_infinite.egg-info/PKG-INFO
|
|
7
|
+
easycode_infinite.egg-info/SOURCES.txt
|
|
8
|
+
easycode_infinite.egg-info/dependency_links.txt
|
|
9
|
+
easycode_infinite.egg-info/requires.txt
|
|
10
|
+
easycode_infinite.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
easycode-infinite
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "easycode-infinite"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "A simple GUI addon for Pygame, Pyglet, and Arcade"
|
|
5
|
+
dependencies = [
|
|
6
|
+
"pygame-ce",
|
|
7
|
+
"pyglet>=2.0",
|
|
8
|
+
"arcade>=3.0",
|
|
9
|
+
"roman"
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
[build-system]
|
|
13
|
+
requires = ["setuptools>=64", "wheel"]
|
|
14
|
+
build-backend = "setuptools.build_meta"
|
|
15
|
+
|
|
16
|
+
[tool.setuptools]
|
|
17
|
+
packages = ["easycode-infinite"]
|
|
18
|
+
[tool.setuptools.package-data]
|
|
19
|
+
easycode = ["sounds/*.wav"]
|