pyscratch-pysc 1.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- assets/bullet_hell/enemy.py +130 -0
- assets/bullet_hell/enemy_bullets.py +230 -0
- assets/bullet_hell/main.py +11 -0
- assets/bullet_hell/old_verisons/bullet_hell.py +379 -0
- assets/bullet_hell/old_verisons/enemy.py +226 -0
- assets/bullet_hell/old_verisons/game_start.py +6 -0
- assets/bullet_hell/old_verisons/main.py +50 -0
- assets/bullet_hell/old_verisons/player.py +76 -0
- assets/bullet_hell/player.py +89 -0
- assets/bullet_hell/player_bullets.py +34 -0
- assets/bullet_hell/setting.py +33 -0
- examples/animated_sprite/main.py +7 -0
- examples/animated_sprite/my_sprite.py +79 -0
- examples/bullet_hell/enemy.py +152 -0
- examples/bullet_hell/enemy_bullet.py +88 -0
- examples/bullet_hell/main.py +17 -0
- examples/bullet_hell/player.py +39 -0
- examples/bullet_hell/player_bullet.py +31 -0
- examples/doodle_jump/main.py +9 -0
- examples/doodle_jump/platforms.py +51 -0
- examples/doodle_jump/player.py +52 -0
- examples/fish/assets/bullet_hell/enemy.py +130 -0
- examples/fish/assets/bullet_hell/enemy_bullets.py +230 -0
- examples/fish/assets/bullet_hell/main.py +11 -0
- examples/fish/assets/bullet_hell/old_verisons/bullet_hell.py +379 -0
- examples/fish/assets/bullet_hell/old_verisons/enemy.py +226 -0
- examples/fish/assets/bullet_hell/old_verisons/game_start.py +6 -0
- examples/fish/assets/bullet_hell/old_verisons/main.py +50 -0
- examples/fish/assets/bullet_hell/old_verisons/player.py +76 -0
- examples/fish/assets/bullet_hell/player.py +89 -0
- examples/fish/assets/bullet_hell/player_bullets.py +34 -0
- examples/fish/assets/bullet_hell/setting.py +33 -0
- examples/fish/fish.py +67 -0
- examples/fish/main.py +4 -0
- examples/getting-started/step 1 - create a sprite/main.py +11 -0
- examples/getting-started/step 1 - create a sprite/player.py +5 -0
- examples/getting-started/step 2 - control a sprite/main.py +11 -0
- examples/getting-started/step 2 - control a sprite/player.py +42 -0
- examples/getting-started/step 3 - backdrops/main.py +17 -0
- examples/getting-started/step 3 - backdrops/player.py +33 -0
- examples/getting-started/step 4 - clone a sprite/enemy.py +53 -0
- examples/getting-started/step 4 - clone a sprite/main.py +17 -0
- examples/getting-started/step 4 - clone a sprite/player.py +32 -0
- examples/getting-started/step 4 - clone a sprite (simple)/enemy.py +42 -0
- examples/getting-started/step 4 - clone a sprite (simple)/main.py +17 -0
- examples/getting-started/step 4 - clone a sprite (simple)/player.py +32 -0
- examples/getting-started/step 5 - local variables/enemy.py +52 -0
- examples/getting-started/step 5 - local variables/main.py +17 -0
- examples/getting-started/step 5 - local variables/player.py +49 -0
- examples/getting-started/step 6 - shared variables/enemy.py +64 -0
- examples/getting-started/step 6 - shared variables/main.py +17 -0
- examples/getting-started/step 6 - shared variables/player.py +80 -0
- examples/getting-started/step 7 - Referencing other sprites/enemy.py +83 -0
- examples/getting-started/step 7 - Referencing other sprites/hearts.py +39 -0
- examples/getting-started/step 7 - Referencing other sprites/main.py +23 -0
- examples/getting-started/step 7 - Referencing other sprites/player.py +59 -0
- examples/getting-started/step 8 - sprite variables/enemy.py +98 -0
- examples/getting-started/step 8 - sprite variables/hearts.py +39 -0
- examples/getting-started/step 8 - sprite variables/main.py +22 -0
- examples/getting-started/step 8 - sprite variables/player.py +63 -0
- examples/getting-started/step 9 - messages/enemy.py +98 -0
- examples/getting-started/step 9 - messages/hearts.py +39 -0
- examples/getting-started/step 9 - messages/main.py +23 -0
- examples/getting-started/step 9 - messages/player.py +78 -0
- examples/perspective_background/main.py +14 -0
- examples/perspective_background/player.py +52 -0
- examples/perspective_background/trees.py +39 -0
- examples/simple_pong/ball.py +72 -0
- examples/simple_pong/left_paddle.py +36 -0
- examples/simple_pong/main.py +21 -0
- examples/simple_pong/right_paddle.py +37 -0
- examples/simple_pong/score_display.py +54 -0
- pyscratch/__init__.py +48 -0
- pyscratch/event.py +263 -0
- pyscratch/game_module.py +1589 -0
- pyscratch/helper.py +561 -0
- pyscratch/sprite.py +1920 -0
- pyscratch/tools/sprite_preview/left_panel/frame_preview_card.py +238 -0
- pyscratch/tools/sprite_preview/left_panel/frame_preview_panel.py +42 -0
- pyscratch/tools/sprite_preview/main.py +18 -0
- pyscratch/tools/sprite_preview/main_panel/animation_display.py +77 -0
- pyscratch/tools/sprite_preview/main_panel/frame_bin.py +33 -0
- pyscratch/tools/sprite_preview/main_panel/play_edit_ui.py +64 -0
- pyscratch/tools/sprite_preview/main_panel/set_as_sprite_folder.py +22 -0
- pyscratch/tools/sprite_preview/main_panel/sprite_edit_ui.py +174 -0
- pyscratch/tools/sprite_preview/main_panel/warning_message.py +25 -0
- pyscratch/tools/sprite_preview/right_panel/back_button.py +35 -0
- pyscratch/tools/sprite_preview/right_panel/cut_button.py +32 -0
- pyscratch/tools/sprite_preview/right_panel/cut_parameter_fitting.py +152 -0
- pyscratch/tools/sprite_preview/right_panel/cut_parameters.py +42 -0
- pyscratch/tools/sprite_preview/right_panel/file_display.py +84 -0
- pyscratch/tools/sprite_preview/right_panel/file_display_area.py +57 -0
- pyscratch/tools/sprite_preview/right_panel/spritesheet_view.py +262 -0
- pyscratch/tools/sprite_preview/right_panel/ss_select_corner.py +208 -0
- pyscratch/tools/sprite_preview/settings.py +14 -0
- pyscratch/tools/sprite_preview/utils/input_box.py +235 -0
- pyscratch/tools/sprite_preview/utils/render_wrapped_file_name.py +86 -0
- pyscratch_pysc-1.0.3.dist-info/METADATA +37 -0
- pyscratch_pysc-1.0.3.dist-info/RECORD +101 -0
- pyscratch_pysc-1.0.3.dist-info/WHEEL +5 -0
- pyscratch_pysc-1.0.3.dist-info/top_level.txt +3 -0
@@ -0,0 +1,208 @@
|
|
1
|
+
|
2
|
+
import numpy as np
|
3
|
+
import pyscratch as pysc
|
4
|
+
game = pysc.game
|
5
|
+
|
6
|
+
|
7
|
+
colour = 0, 0, 0, 50
|
8
|
+
|
9
|
+
cir0 = pysc.create_circle_sprite(colour, 30)
|
10
|
+
game['c0'] = cir0
|
11
|
+
|
12
|
+
cir1 = pysc.create_circle_sprite(colour, 30)
|
13
|
+
game['c1'] = cir1
|
14
|
+
|
15
|
+
# event game start: initial setting
|
16
|
+
def on_start():
|
17
|
+
|
18
|
+
cir0.set_draggable(True)
|
19
|
+
cir1.set_draggable(True)
|
20
|
+
|
21
|
+
# pysc.game.bring_to_front(cir)
|
22
|
+
# pysc.game.bring_to_front(cir2)
|
23
|
+
|
24
|
+
cir0.x = game['ss_view_topleft'][0] + 1
|
25
|
+
cir0.y = game['ss_view_topleft'][1] + 1
|
26
|
+
|
27
|
+
cir1.x = game['ss_view_buttom_right'][0]-1
|
28
|
+
cir1.y = game['ss_view_buttom_right'][1]-1
|
29
|
+
|
30
|
+
|
31
|
+
cir0.oob_limit=np.inf
|
32
|
+
cir1.oob_limit=np.inf
|
33
|
+
|
34
|
+
game.when_game_start([cir0, cir1]).add_handler(on_start)
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
# useful functions
|
39
|
+
def value_if_none(v, default):
|
40
|
+
if v is None:
|
41
|
+
return default
|
42
|
+
return v
|
43
|
+
|
44
|
+
def value_if_not(v, default):
|
45
|
+
if not v:
|
46
|
+
return default
|
47
|
+
return v
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
# event game start: set the cutting offset and the frame size if the sprite is dragged
|
53
|
+
def on_start2():
|
54
|
+
while True:
|
55
|
+
yield 1/30
|
56
|
+
ss_sprite: pysc.Sprite = game['ss_sprite']
|
57
|
+
if not ss_sprite: continue
|
58
|
+
game.bring_to_front(cir0)
|
59
|
+
game.bring_to_front(cir1)
|
60
|
+
|
61
|
+
mouse_down = pysc.get_mouse_presses()[0]
|
62
|
+
if not mouse_down:
|
63
|
+
try:
|
64
|
+
cir0.x = game['offset_x']*ss_sprite.scale_factor + ss_sprite.rect.left
|
65
|
+
cir1.x = game['limit_x']*ss_sprite.scale_factor + ss_sprite.rect.left
|
66
|
+
|
67
|
+
cir0.y = game['offset_y']*ss_sprite.scale_factor + ss_sprite.rect.top
|
68
|
+
cir1.y = game['limit_y']*ss_sprite.scale_factor + ss_sprite.rect.top
|
69
|
+
except:
|
70
|
+
pass
|
71
|
+
continue
|
72
|
+
if not (cir0.is_touching_mouse() or cir1.is_touching_mouse()): continue
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
# top left of the selected rect
|
77
|
+
cx0 = min(cir0.x, cir1.x)
|
78
|
+
cy0 = min(cir0.y, cir1.y)
|
79
|
+
|
80
|
+
# bottom right of the selected rect
|
81
|
+
cx1 = max(cir0.x, cir1.x)
|
82
|
+
cy1 = max(cir0.y, cir1.y)
|
83
|
+
|
84
|
+
# top left of the sprite sheet
|
85
|
+
x0, y0 = ss_sprite.rect.topleft
|
86
|
+
|
87
|
+
img_w, img_h = ss_sprite['original_width'], ss_sprite['original_height']
|
88
|
+
|
89
|
+
# scale factor
|
90
|
+
scale_factor = ss_sprite.scale_factor
|
91
|
+
|
92
|
+
# RC
|
93
|
+
n_col = value_if_not(game['n_col'], 1)
|
94
|
+
n_row = value_if_not(game['n_row'], 1)
|
95
|
+
|
96
|
+
# O
|
97
|
+
game['offset_x'] = Ox = max(np.floor((cx0-x0)/scale_factor), 0)
|
98
|
+
game['offset_y'] = Oy = max(np.floor((cy0-y0)/scale_factor), 0)
|
99
|
+
|
100
|
+
# L
|
101
|
+
game['limit_x'] = Lx = min(np.ceil((cx1-x0)/scale_factor), img_w-1)
|
102
|
+
game['limit_y'] = Ly = min(np.ceil((cy1-y0)/scale_factor), img_h-1)
|
103
|
+
|
104
|
+
# update the size
|
105
|
+
game['size_x'] = Lx - Ox + 1
|
106
|
+
game['size_y'] = Ly - Oy + 1
|
107
|
+
|
108
|
+
# pix
|
109
|
+
game['pixel_x'] = np.floor(game['size_x']/n_col)
|
110
|
+
game['pixel_y'] = np.floor(game['size_y']/n_row)
|
111
|
+
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
pysc.game.when_game_start([cir0, cir1]).add_handler(on_start2)
|
117
|
+
|
118
|
+
|
119
|
+
def on_offset_x_change(data):
|
120
|
+
|
121
|
+
if not (size_x := game['size_x']): return
|
122
|
+
if not (offset_x := game['offset_x']):
|
123
|
+
game['offset_x'] = 0
|
124
|
+
offset_x = 0
|
125
|
+
|
126
|
+
ss_sprite: pysc.Sprite = game['ss_sprite']
|
127
|
+
if not ss_sprite: return
|
128
|
+
|
129
|
+
game['limit_x'] = min(size_x+offset_x-1, ss_sprite['original_width']-1)
|
130
|
+
|
131
|
+
game['size_x'] = game['limit_x'] - offset_x + 1
|
132
|
+
|
133
|
+
cir0.x = offset_x*ss_sprite.scale_factor + ss_sprite.rect.left
|
134
|
+
cir1.x = game['limit_x']*ss_sprite.scale_factor + ss_sprite.rect.left
|
135
|
+
|
136
|
+
game['n_col'] = np.floor(game['size_x']/game['pixel_x'])
|
137
|
+
|
138
|
+
game.when_receive_message('offset_x_change').add_handler(on_offset_x_change)
|
139
|
+
|
140
|
+
def on_offset_y_change(data):
|
141
|
+
|
142
|
+
if not (size_y := game['size_y']): return
|
143
|
+
if (offset_y := game['offset_y']) is None:
|
144
|
+
game['offset_y'] = 0
|
145
|
+
offset_y = 0
|
146
|
+
|
147
|
+
ss_sprite: pysc.Sprite = game['ss_sprite']
|
148
|
+
if not ss_sprite: return
|
149
|
+
|
150
|
+
game['limit_y'] = min(size_y+offset_y-1, ss_sprite['original_height']-1)
|
151
|
+
|
152
|
+
game['size_y'] = game['limit_y'] - offset_y + 1
|
153
|
+
|
154
|
+
cir0.y = offset_y*ss_sprite.scale_factor + ss_sprite.rect.top
|
155
|
+
cir1.y = game['limit_y']*ss_sprite.scale_factor + ss_sprite.rect.top
|
156
|
+
|
157
|
+
game['n_row'] = np.floor(game['size_y']/game['pixel_y'])
|
158
|
+
|
159
|
+
game.when_receive_message('offset_y_change').add_handler(on_offset_y_change)
|
160
|
+
|
161
|
+
|
162
|
+
def on_n_row_change(data):
|
163
|
+
if not game['size_y']: return
|
164
|
+
game['pixel_y'] = np.floor(game['size_y']/value_if_not(game['n_row'], 1))
|
165
|
+
|
166
|
+
game.when_receive_message('n_row_change').add_handler(on_n_row_change)
|
167
|
+
|
168
|
+
|
169
|
+
def on_n_col_change(data):
|
170
|
+
if not game['size_x']: return
|
171
|
+
game['pixel_x'] = np.floor(game['size_x']/value_if_not(game['n_col'], 1))
|
172
|
+
|
173
|
+
game.when_receive_message('n_col_change').add_handler(on_n_col_change)
|
174
|
+
|
175
|
+
|
176
|
+
|
177
|
+
def on_pix_x_change(data):
|
178
|
+
if not game['size_x']: return
|
179
|
+
game['n_col'] = np.floor(game['size_x']/value_if_not(game['pixel_x'], 1))
|
180
|
+
|
181
|
+
|
182
|
+
game.when_receive_message('pixel_x_change').add_handler(on_pix_x_change)
|
183
|
+
|
184
|
+
def on_pix_y_change(data):
|
185
|
+
if not game['size_y']: return
|
186
|
+
game['n_row'] = np.floor(game['size_y']/value_if_not(game['pixel_y'], 1))
|
187
|
+
|
188
|
+
|
189
|
+
game.when_receive_message('pixel_y_change').add_handler(on_pix_y_change)
|
190
|
+
|
191
|
+
|
192
|
+
|
193
|
+
def on_scale_change(data):
|
194
|
+
ss_sprite: pysc.Sprite = game['ss_sprite']
|
195
|
+
if game['offset_x'] is None: return
|
196
|
+
if game['limit_x'] is None: return
|
197
|
+
if game['offset_y'] is None: return
|
198
|
+
if game['limit_y'] is None: return
|
199
|
+
|
200
|
+
|
201
|
+
cir0.x = game['offset_x']*ss_sprite.scale_factor + ss_sprite.rect.left
|
202
|
+
cir1.x = game['limit_x']*ss_sprite.scale_factor + ss_sprite.rect.left
|
203
|
+
|
204
|
+
cir0.y = game['offset_y']*ss_sprite.scale_factor + ss_sprite.rect.top
|
205
|
+
cir1.y = game['limit_y']*ss_sprite.scale_factor + ss_sprite.rect.top
|
206
|
+
|
207
|
+
|
208
|
+
game.when_receive_message('ss_sprite_scale_change').add_handler(on_pix_y_change)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import pygame
|
2
|
+
|
3
|
+
SCREEN_HEIGHT = 720
|
4
|
+
SCREEN_WIDTH = 1280
|
5
|
+
DEFAULT_FONT24 = pygame.font.SysFont(None, 24)
|
6
|
+
DEFAULT_FONT48 = pygame.font.SysFont(None, 24)
|
7
|
+
|
8
|
+
LEFT_PANEL_WIDTH = 120
|
9
|
+
RIGHT_PANEL_WIDTH = 600
|
10
|
+
|
11
|
+
BOTTOM_RIGHT_PANEL_HEIGHT = 200
|
12
|
+
PANEL_MARGIN = 10
|
13
|
+
|
14
|
+
|
@@ -0,0 +1,235 @@
|
|
1
|
+
from calendar import Day
|
2
|
+
import pyscratch as pysc
|
3
|
+
from settings import *
|
4
|
+
|
5
|
+
w, h = 120, 40
|
6
|
+
selected_colour = (255, 255, 255)
|
7
|
+
deselected_colour = (127, 127, 127)
|
8
|
+
|
9
|
+
|
10
|
+
def FloatInputBoxVerticallyLabel(data_key, message_on_change="", default_value=""):
|
11
|
+
label = pysc.create_rect_sprite(deselected_colour, w, h)
|
12
|
+
label.write_text(data_key, DEFAULT_FONT24, offset=(w/2, h/2))
|
13
|
+
|
14
|
+
selected_sur = pysc.create_rect(selected_colour, w, h)
|
15
|
+
deselected_sur = pysc.create_rect(deselected_colour, w, h)
|
16
|
+
pysc.game.shared_data[data_key] = None
|
17
|
+
text_box = pysc.Sprite({'selected':[selected_sur], 'deselected':[deselected_sur]}, 'deselected')
|
18
|
+
label.lock_to(text_box, (0,0), reset_xy=True)
|
19
|
+
label.y = -h
|
20
|
+
|
21
|
+
# def on_click():
|
22
|
+
# text_box.set_animation('selected')
|
23
|
+
# text_box.sprite_data['selected'] = True
|
24
|
+
|
25
|
+
# text_box.when_this_sprite_clicked().add_handler(on_click)
|
26
|
+
text_box['selected'] = False
|
27
|
+
text_box['text'] = default_value
|
28
|
+
try:
|
29
|
+
pysc.game.shared_data[data_key] = float(text_box.sprite_data['text'])
|
30
|
+
except:
|
31
|
+
pysc.game.shared_data[data_key] = None
|
32
|
+
|
33
|
+
text_box.write_text(text_box['text'], DEFAULT_FONT24, colour=(255,255,255), offset=(w/2, h/2))
|
34
|
+
def on_any_key_press(key:str, updown):
|
35
|
+
if updown == 'up': return
|
36
|
+
if not text_box.sprite_data['selected']: return
|
37
|
+
if text_box['just_selected']:
|
38
|
+
text_box['just_selected'] = False
|
39
|
+
text_box['text'] = ''
|
40
|
+
|
41
|
+
if key.isdigit() or key == '.':
|
42
|
+
text_box.sprite_data['text'] += key
|
43
|
+
|
44
|
+
if key == 'backspace' and len(text_box.sprite_data['text']):
|
45
|
+
text_box.sprite_data['text'] = text_box.sprite_data['text'][:-1]
|
46
|
+
|
47
|
+
try:
|
48
|
+
pysc.game.shared_data[data_key] = float(text_box.sprite_data['text'])
|
49
|
+
except:
|
50
|
+
pysc.game.shared_data[data_key] = None
|
51
|
+
|
52
|
+
text_box.write_text(text_box.sprite_data['text'], DEFAULT_FONT24, colour=(0,0,0), offset=(w/2, h/2))
|
53
|
+
|
54
|
+
if message_on_change:
|
55
|
+
pysc.game.broadcast_message(message_on_change, pysc.game.shared_data[data_key])
|
56
|
+
|
57
|
+
text_box.when_any_key_pressed().add_handler(on_any_key_press)
|
58
|
+
|
59
|
+
def on_any_mouse_click(pos, button, updown):
|
60
|
+
if not text_box.is_touching_mouse():
|
61
|
+
#print(button)
|
62
|
+
#print(pos)
|
63
|
+
text_box.sprite_data['selected'] = False
|
64
|
+
text_box['just_selected'] = False
|
65
|
+
text_box.set_animation('deselected')
|
66
|
+
text_box.write_text(text_box.sprite_data['text'], DEFAULT_FONT24, colour=(255,255,255), offset=(w/2, h/2))
|
67
|
+
|
68
|
+
else:
|
69
|
+
text_box.sprite_data['selected'] = True
|
70
|
+
text_box['just_selected'] = True
|
71
|
+
text_box.set_animation('selected')
|
72
|
+
text_box.write_text(text_box['text'], DEFAULT_FONT24, colour=(0,0,0), offset=(w/2, h/2))
|
73
|
+
pysc.game.when_mouse_click([text_box]).add_handler(on_any_mouse_click)
|
74
|
+
|
75
|
+
return text_box
|
76
|
+
|
77
|
+
|
78
|
+
def FloatInputBoxHoriLabel(data_key, message_on_change="", default_value="", label_width=80):
|
79
|
+
wl = label_width
|
80
|
+
label = pysc.create_rect_sprite(deselected_colour, wl, h)
|
81
|
+
label.write_text(data_key, DEFAULT_FONT24, offset=(wl/2, h/2))
|
82
|
+
|
83
|
+
selected_sur = pysc.create_rect(selected_colour, w, h)
|
84
|
+
deselected_sur = pysc.create_rect(deselected_colour, w, h)
|
85
|
+
pysc.game.shared_data[data_key] = None
|
86
|
+
text_box = pysc.Sprite({'selected':[selected_sur], 'deselected':[deselected_sur]}, 'deselected')
|
87
|
+
label.lock_to(text_box, (0,0), reset_xy=True)
|
88
|
+
label.x = -w/2-wl/2
|
89
|
+
|
90
|
+
|
91
|
+
# def on_click():
|
92
|
+
# text_box.set_animation('selected')
|
93
|
+
# text_box.sprite_data['selected'] = True
|
94
|
+
|
95
|
+
# text_box.when_this_sprite_clicked().add_handler(on_click)
|
96
|
+
text_box['selected'] = False
|
97
|
+
text_box['text'] = default_value
|
98
|
+
try:
|
99
|
+
pysc.game.shared_data[data_key] = float(text_box.sprite_data['text'])
|
100
|
+
except:
|
101
|
+
pysc.game.shared_data[data_key] = None
|
102
|
+
|
103
|
+
text_box.write_text(text_box['text'], DEFAULT_FONT24, colour=(255,255,255), offset=(w/2, h/2))
|
104
|
+
def on_any_key_press(key:str, updown):
|
105
|
+
if updown == 'up': return
|
106
|
+
if not text_box.sprite_data['selected']: return
|
107
|
+
if text_box['just_selected']:
|
108
|
+
text_box['just_selected'] = False
|
109
|
+
text_box['text'] = ''
|
110
|
+
|
111
|
+
if key.isdigit() or key == '.':
|
112
|
+
text_box.sprite_data['text'] += key
|
113
|
+
|
114
|
+
if key == 'backspace' and len(text_box.sprite_data['text']):
|
115
|
+
text_box.sprite_data['text'] = text_box.sprite_data['text'][:-1]
|
116
|
+
|
117
|
+
try:
|
118
|
+
pysc.game.shared_data[data_key] = float(text_box.sprite_data['text'])
|
119
|
+
except:
|
120
|
+
pysc.game.shared_data[data_key] = None
|
121
|
+
|
122
|
+
text_box.write_text(text_box.sprite_data['text'], DEFAULT_FONT24, colour=(0,0,0), offset=(w/2, h/2))
|
123
|
+
|
124
|
+
if message_on_change:
|
125
|
+
pysc.game.broadcast_message(message_on_change, pysc.game.shared_data[data_key])
|
126
|
+
|
127
|
+
text_box.when_any_key_pressed().add_handler(on_any_key_press)
|
128
|
+
|
129
|
+
def on_any_mouse_click(pos, button, updown):
|
130
|
+
if not text_box.is_touching_mouse():
|
131
|
+
#print(button)
|
132
|
+
#print(pos)
|
133
|
+
text_box.sprite_data['selected'] = False
|
134
|
+
text_box['just_selected'] = False
|
135
|
+
text_box.set_animation('deselected')
|
136
|
+
text_box.write_text(text_box.sprite_data['text'], DEFAULT_FONT24, colour=(255,255,255), offset=(w/2, h/2))
|
137
|
+
|
138
|
+
else:
|
139
|
+
text_box.sprite_data['selected'] = True
|
140
|
+
text_box['just_selected'] = True
|
141
|
+
text_box.set_animation('selected')
|
142
|
+
text_box.write_text(text_box['text'], DEFAULT_FONT24, colour=(0,0,0), offset=(w/2, h/2))
|
143
|
+
pysc.game.when_mouse_click([text_box]).add_handler(on_any_mouse_click)
|
144
|
+
|
145
|
+
return text_box
|
146
|
+
|
147
|
+
|
148
|
+
def IntegerInputBox(data_key, message_on_change="", default_value="", label_width=60):
|
149
|
+
wl = label_width
|
150
|
+
label = pysc.create_rect_sprite(deselected_colour, wl, h)
|
151
|
+
label.write_text(data_key, DEFAULT_FONT24, offset=(wl/2, h/2))
|
152
|
+
|
153
|
+
selected_sur = pysc.create_rect(selected_colour, w, h)
|
154
|
+
deselected_sur = pysc.create_rect(deselected_colour, w, h)
|
155
|
+
pysc.game.shared_data[data_key] = None
|
156
|
+
text_box = pysc.Sprite({'selected':[selected_sur], 'deselected':[deselected_sur]}, 'deselected')
|
157
|
+
label.lock_to(text_box, (0,0), reset_xy=True)
|
158
|
+
label.x = -w/2-wl/2
|
159
|
+
|
160
|
+
# def on_click():
|
161
|
+
# text_box.set_animation('selected')
|
162
|
+
# text_box.sprite_data['selected'] = True
|
163
|
+
|
164
|
+
# text_box.when_this_sprite_clicked().add_handler(on_click)
|
165
|
+
text_box.sprite_data['selected'] = False
|
166
|
+
text_box.sprite_data['text'] = default_value
|
167
|
+
text_box.write_text(text_box['text'], DEFAULT_FONT24, colour=(255,255,255), offset=(w/2, h/2))
|
168
|
+
def on_any_key_press(key:str, updown):
|
169
|
+
if updown == 'up': return
|
170
|
+
if not text_box.sprite_data['selected']: return
|
171
|
+
if text_box['just_selected']:
|
172
|
+
text_box['just_selected'] = False
|
173
|
+
text_box['text'] = ''
|
174
|
+
|
175
|
+
if key.isdigit():
|
176
|
+
text_box.sprite_data['text'] += key
|
177
|
+
|
178
|
+
if key == 'backspace' and len(text_box.sprite_data['text']):
|
179
|
+
text_box.sprite_data['text'] = text_box.sprite_data['text'][:-1]
|
180
|
+
|
181
|
+
# try:
|
182
|
+
# pysc.game.shared_data[data_key] = int(text_box.sprite_data['text'])
|
183
|
+
# except:
|
184
|
+
# pysc.game.shared_data[data_key] = None
|
185
|
+
|
186
|
+
text_box.write_text(text_box.sprite_data['text'], DEFAULT_FONT24, colour=(0,0,0), offset=(w/2, h/2))
|
187
|
+
|
188
|
+
|
189
|
+
|
190
|
+
text_box.when_any_key_pressed().add_handler(on_any_key_press)
|
191
|
+
|
192
|
+
def on_any_mouse_click(pos, button, updown):
|
193
|
+
if not text_box.is_touching_mouse():
|
194
|
+
#print(button)
|
195
|
+
#print(pos)
|
196
|
+
if text_box['selected']:
|
197
|
+
try:
|
198
|
+
pysc.game.shared_data[data_key] = int(text_box.sprite_data['text'])
|
199
|
+
except:
|
200
|
+
pysc.game.shared_data[data_key] = None
|
201
|
+
if message_on_change:
|
202
|
+
pysc.game.broadcast_message(message_on_change, pysc.game.shared_data[data_key])
|
203
|
+
text_box['selected'] = False
|
204
|
+
text_box['just_selected'] = False
|
205
|
+
text_box.set_animation('deselected')
|
206
|
+
text_box.write_text(text_box['text'], DEFAULT_FONT24, colour=(255,255,255), offset=(w/2, h/2))
|
207
|
+
|
208
|
+
else:
|
209
|
+
text_box['selected'] = True
|
210
|
+
text_box['just_selected'] = True
|
211
|
+
text_box.set_animation('selected')
|
212
|
+
text_box.write_text(text_box['text'], DEFAULT_FONT24, colour=(0,0,0), offset=(w/2, h/2))
|
213
|
+
pysc.game.when_mouse_click([text_box]).add_handler(on_any_mouse_click)
|
214
|
+
|
215
|
+
|
216
|
+
def update_value_on_change():
|
217
|
+
while True:
|
218
|
+
yield 1/30
|
219
|
+
|
220
|
+
|
221
|
+
|
222
|
+
if text_box.animation_name == "selected":
|
223
|
+
continue
|
224
|
+
|
225
|
+
try:
|
226
|
+
text_box['text'] = str(round(pysc.game[data_key]))
|
227
|
+
except:
|
228
|
+
text_box['text'] = ""
|
229
|
+
|
230
|
+
text_box.write_text(text_box['text'], DEFAULT_FONT24, colour=(255,255,255), offset=(w/2, h/2))
|
231
|
+
|
232
|
+
|
233
|
+
text_box.when_game_start().add_handler(update_value_on_change)
|
234
|
+
|
235
|
+
return text_box
|
@@ -0,0 +1,86 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
import pygame
|
4
|
+
|
5
|
+
|
6
|
+
def render_wrapped_file_name(text, max_chars, font, color=(255, 255, 255), bg_color=None, max_lines=None):
|
7
|
+
"""
|
8
|
+
THIS FUNCTION IS WRITTEN BY AN AI
|
9
|
+
|
10
|
+
Renders a file name like a file explorer: wrapping intelligently while preserving the extension.
|
11
|
+
|
12
|
+
:param text: The file name string to render.
|
13
|
+
:param max_chars: Maximum number of characters per line (approximate width).
|
14
|
+
:param font: Pygame font object to render with.
|
15
|
+
:param color: Text color (default white).
|
16
|
+
:param bg_color: Background color (default None = transparent).
|
17
|
+
:param max_lines: Optional maximum number of lines to render. Extra text will be truncated with '...'.
|
18
|
+
:return: A Pygame surface with the rendered multiline text.
|
19
|
+
"""
|
20
|
+
def split_file_name(text):
|
21
|
+
if '.' in text and not text.startswith('.') and text.rfind('.') > 0:
|
22
|
+
idx = text.rfind('.')
|
23
|
+
return text[:idx], text[idx+1:]
|
24
|
+
else:
|
25
|
+
return text, ''
|
26
|
+
|
27
|
+
def wrap_lines(base, ext, max_chars, max_lines=None):
|
28
|
+
words = base.split(' ')
|
29
|
+
lines = []
|
30
|
+
current_line = ''
|
31
|
+
|
32
|
+
for word in words:
|
33
|
+
test_line = (current_line + ' ' + word).strip()
|
34
|
+
if len(test_line) <= max_chars:
|
35
|
+
current_line = test_line
|
36
|
+
else:
|
37
|
+
if current_line:
|
38
|
+
lines.append(current_line)
|
39
|
+
if max_lines and len(lines) == max_lines:
|
40
|
+
return lines[:-1] + [truncate_with_ellipsis(current_line, max_chars)]
|
41
|
+
# Break long word
|
42
|
+
while len(word) > max_chars:
|
43
|
+
lines.append(word[:max_chars])
|
44
|
+
word = word[max_chars:]
|
45
|
+
if max_lines and len(lines) == max_lines:
|
46
|
+
return lines[:-1] + [truncate_with_ellipsis(lines[-1], max_chars)]
|
47
|
+
current_line = word
|
48
|
+
|
49
|
+
if current_line:
|
50
|
+
lines.append(current_line)
|
51
|
+
if max_lines and len(lines) > max_lines:
|
52
|
+
lines = lines[:max_lines]
|
53
|
+
lines[-1] = truncate_with_ellipsis(lines[-1], max_chars)
|
54
|
+
|
55
|
+
# Add extension
|
56
|
+
if ext:
|
57
|
+
if len(lines[-1] + '.' + ext) <= max_chars:
|
58
|
+
lines[-1] += '.' + ext
|
59
|
+
elif not max_lines or len(lines) < max_lines:
|
60
|
+
lines.append('.' + ext)
|
61
|
+
else:
|
62
|
+
lines[-1] = truncate_with_ellipsis(lines[-1], max_chars)
|
63
|
+
|
64
|
+
return lines
|
65
|
+
|
66
|
+
def truncate_with_ellipsis(line, max_chars):
|
67
|
+
return line[:max(0, max_chars - 3)] + '...'
|
68
|
+
|
69
|
+
# Prepare
|
70
|
+
base, ext = split_file_name(text)
|
71
|
+
lines = wrap_lines(base, ext, max_chars, max_lines)
|
72
|
+
|
73
|
+
# Render
|
74
|
+
line_height = font.get_linesize()
|
75
|
+
surface_height = line_height * len(lines)
|
76
|
+
surface_width = max(font.size(line)[0] for line in lines)
|
77
|
+
|
78
|
+
rendered_surface = pygame.Surface((surface_width, surface_height), pygame.SRCALPHA)
|
79
|
+
if bg_color:
|
80
|
+
rendered_surface.fill(bg_color)
|
81
|
+
|
82
|
+
for i, line in enumerate(lines):
|
83
|
+
text_surface = font.render(line, True, color)
|
84
|
+
rendered_surface.blit(text_surface, (0, i * line_height))
|
85
|
+
|
86
|
+
return rendered_surface
|
@@ -0,0 +1,37 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: pyscratch-pysc
|
3
|
+
Version: 1.0.3
|
4
|
+
Summary: A Python game development framework designed to provide an easy transitioning from Scratch to Python
|
5
|
+
Author-email: Daniel Ka-Wa Chan <kwdaniel525@protonmail.com>
|
6
|
+
License: MIT
|
7
|
+
Project-URL: Homepage, https://kwdchan.github.io/pyscratch/
|
8
|
+
Project-URL: Repository, https://github.com/kwdChan/pyscratch
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
11
|
+
Classifier: Operating System :: OS Independent
|
12
|
+
Requires-Python: >=3.10
|
13
|
+
Description-Content-Type: text/markdown
|
14
|
+
Requires-Dist: pymunk<7
|
15
|
+
Requires-Dist: pygame<3
|
16
|
+
Requires-Dist: numpy<3
|
17
|
+
Requires-Dist: typing_extensions
|
18
|
+
Requires-Dist: pillow<12
|
19
|
+
|
20
|
+
# PyScratch
|
21
|
+
For more information, see: https://kwdchan.github.io/pyscratch/
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
## Change History
|
29
|
+
|
30
|
+
### 07 Sep 2025
|
31
|
+
**v1.0.3**
|
32
|
+
Added undeclared dependency: Pillow
|
33
|
+
Specified the versions of the dependencies
|
34
|
+
|
35
|
+
### Jul 2025
|
36
|
+
**v1.0.0**
|
37
|
+
The first version
|