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.
Files changed (101) hide show
  1. assets/bullet_hell/enemy.py +130 -0
  2. assets/bullet_hell/enemy_bullets.py +230 -0
  3. assets/bullet_hell/main.py +11 -0
  4. assets/bullet_hell/old_verisons/bullet_hell.py +379 -0
  5. assets/bullet_hell/old_verisons/enemy.py +226 -0
  6. assets/bullet_hell/old_verisons/game_start.py +6 -0
  7. assets/bullet_hell/old_verisons/main.py +50 -0
  8. assets/bullet_hell/old_verisons/player.py +76 -0
  9. assets/bullet_hell/player.py +89 -0
  10. assets/bullet_hell/player_bullets.py +34 -0
  11. assets/bullet_hell/setting.py +33 -0
  12. examples/animated_sprite/main.py +7 -0
  13. examples/animated_sprite/my_sprite.py +79 -0
  14. examples/bullet_hell/enemy.py +152 -0
  15. examples/bullet_hell/enemy_bullet.py +88 -0
  16. examples/bullet_hell/main.py +17 -0
  17. examples/bullet_hell/player.py +39 -0
  18. examples/bullet_hell/player_bullet.py +31 -0
  19. examples/doodle_jump/main.py +9 -0
  20. examples/doodle_jump/platforms.py +51 -0
  21. examples/doodle_jump/player.py +52 -0
  22. examples/fish/assets/bullet_hell/enemy.py +130 -0
  23. examples/fish/assets/bullet_hell/enemy_bullets.py +230 -0
  24. examples/fish/assets/bullet_hell/main.py +11 -0
  25. examples/fish/assets/bullet_hell/old_verisons/bullet_hell.py +379 -0
  26. examples/fish/assets/bullet_hell/old_verisons/enemy.py +226 -0
  27. examples/fish/assets/bullet_hell/old_verisons/game_start.py +6 -0
  28. examples/fish/assets/bullet_hell/old_verisons/main.py +50 -0
  29. examples/fish/assets/bullet_hell/old_verisons/player.py +76 -0
  30. examples/fish/assets/bullet_hell/player.py +89 -0
  31. examples/fish/assets/bullet_hell/player_bullets.py +34 -0
  32. examples/fish/assets/bullet_hell/setting.py +33 -0
  33. examples/fish/fish.py +67 -0
  34. examples/fish/main.py +4 -0
  35. examples/getting-started/step 1 - create a sprite/main.py +11 -0
  36. examples/getting-started/step 1 - create a sprite/player.py +5 -0
  37. examples/getting-started/step 2 - control a sprite/main.py +11 -0
  38. examples/getting-started/step 2 - control a sprite/player.py +42 -0
  39. examples/getting-started/step 3 - backdrops/main.py +17 -0
  40. examples/getting-started/step 3 - backdrops/player.py +33 -0
  41. examples/getting-started/step 4 - clone a sprite/enemy.py +53 -0
  42. examples/getting-started/step 4 - clone a sprite/main.py +17 -0
  43. examples/getting-started/step 4 - clone a sprite/player.py +32 -0
  44. examples/getting-started/step 4 - clone a sprite (simple)/enemy.py +42 -0
  45. examples/getting-started/step 4 - clone a sprite (simple)/main.py +17 -0
  46. examples/getting-started/step 4 - clone a sprite (simple)/player.py +32 -0
  47. examples/getting-started/step 5 - local variables/enemy.py +52 -0
  48. examples/getting-started/step 5 - local variables/main.py +17 -0
  49. examples/getting-started/step 5 - local variables/player.py +49 -0
  50. examples/getting-started/step 6 - shared variables/enemy.py +64 -0
  51. examples/getting-started/step 6 - shared variables/main.py +17 -0
  52. examples/getting-started/step 6 - shared variables/player.py +80 -0
  53. examples/getting-started/step 7 - Referencing other sprites/enemy.py +83 -0
  54. examples/getting-started/step 7 - Referencing other sprites/hearts.py +39 -0
  55. examples/getting-started/step 7 - Referencing other sprites/main.py +23 -0
  56. examples/getting-started/step 7 - Referencing other sprites/player.py +59 -0
  57. examples/getting-started/step 8 - sprite variables/enemy.py +98 -0
  58. examples/getting-started/step 8 - sprite variables/hearts.py +39 -0
  59. examples/getting-started/step 8 - sprite variables/main.py +22 -0
  60. examples/getting-started/step 8 - sprite variables/player.py +63 -0
  61. examples/getting-started/step 9 - messages/enemy.py +98 -0
  62. examples/getting-started/step 9 - messages/hearts.py +39 -0
  63. examples/getting-started/step 9 - messages/main.py +23 -0
  64. examples/getting-started/step 9 - messages/player.py +78 -0
  65. examples/perspective_background/main.py +14 -0
  66. examples/perspective_background/player.py +52 -0
  67. examples/perspective_background/trees.py +39 -0
  68. examples/simple_pong/ball.py +72 -0
  69. examples/simple_pong/left_paddle.py +36 -0
  70. examples/simple_pong/main.py +21 -0
  71. examples/simple_pong/right_paddle.py +37 -0
  72. examples/simple_pong/score_display.py +54 -0
  73. pyscratch/__init__.py +48 -0
  74. pyscratch/event.py +263 -0
  75. pyscratch/game_module.py +1589 -0
  76. pyscratch/helper.py +561 -0
  77. pyscratch/sprite.py +1920 -0
  78. pyscratch/tools/sprite_preview/left_panel/frame_preview_card.py +238 -0
  79. pyscratch/tools/sprite_preview/left_panel/frame_preview_panel.py +42 -0
  80. pyscratch/tools/sprite_preview/main.py +18 -0
  81. pyscratch/tools/sprite_preview/main_panel/animation_display.py +77 -0
  82. pyscratch/tools/sprite_preview/main_panel/frame_bin.py +33 -0
  83. pyscratch/tools/sprite_preview/main_panel/play_edit_ui.py +64 -0
  84. pyscratch/tools/sprite_preview/main_panel/set_as_sprite_folder.py +22 -0
  85. pyscratch/tools/sprite_preview/main_panel/sprite_edit_ui.py +174 -0
  86. pyscratch/tools/sprite_preview/main_panel/warning_message.py +25 -0
  87. pyscratch/tools/sprite_preview/right_panel/back_button.py +35 -0
  88. pyscratch/tools/sprite_preview/right_panel/cut_button.py +32 -0
  89. pyscratch/tools/sprite_preview/right_panel/cut_parameter_fitting.py +152 -0
  90. pyscratch/tools/sprite_preview/right_panel/cut_parameters.py +42 -0
  91. pyscratch/tools/sprite_preview/right_panel/file_display.py +84 -0
  92. pyscratch/tools/sprite_preview/right_panel/file_display_area.py +57 -0
  93. pyscratch/tools/sprite_preview/right_panel/spritesheet_view.py +262 -0
  94. pyscratch/tools/sprite_preview/right_panel/ss_select_corner.py +208 -0
  95. pyscratch/tools/sprite_preview/settings.py +14 -0
  96. pyscratch/tools/sprite_preview/utils/input_box.py +235 -0
  97. pyscratch/tools/sprite_preview/utils/render_wrapped_file_name.py +86 -0
  98. pyscratch_pysc-1.0.3.dist-info/METADATA +37 -0
  99. pyscratch_pysc-1.0.3.dist-info/RECORD +101 -0
  100. pyscratch_pysc-1.0.3.dist-info/WHEEL +5 -0
  101. pyscratch_pysc-1.0.3.dist-info/top_level.txt +3 -0
pyscratch/helper.py ADDED
@@ -0,0 +1,561 @@
1
+ """
2
+ Everything in this module is directly under the pyscratch namespace.
3
+ For example, instead of doing `pysc.helper.random_number`,
4
+ you can also directly do `pysc.random_number`
5
+ """
6
+
7
+
8
+ from functools import cache
9
+ from itertools import product
10
+ from pathlib import Path
11
+ from typing import Dict, List, Tuple, Union
12
+ import random
13
+
14
+ import pygame
15
+ import numpy as np
16
+
17
+
18
+ def cap(v:float, min_v:float, max_v:float)->float:
19
+ """
20
+ Cap a value to a range between `min_v` and `max_v`.
21
+
22
+ Example
23
+ ```python
24
+ cap(5, 1, 10) # returns 5
25
+ cap(15, 1, 10) # returns 10
26
+ cap(-10, 1, 10) # returns 1
27
+
28
+ # a more realistic example usage: keep the sprite within the screen.
29
+ my_sprite.x = cap(my_sprite.x, 0, SCREEN_WIDTH)
30
+ my_sprite.y = cap(my_sprite.y, 0, SCREEN_HEIGHT)
31
+ ```
32
+ """
33
+ return max(min(max_v, v), min_v)
34
+
35
+ def random_number(min_v:float, max_v:float) -> float:
36
+ """
37
+ Returns a random number between `min_v` and `max_v`
38
+ """
39
+ return random.random()*(max_v-min_v)+min_v
40
+
41
+ @cache
42
+ def load_image(path: str) -> pygame.Surface:
43
+ """
44
+ Return the `pygame.Surface` given the path to an image.
45
+ """
46
+ return pygame.image.load(path).convert_alpha()
47
+
48
+
49
+ def get_frame_from_sprite_sheet(
50
+ sheet: pygame.Surface,
51
+ columns:int, rows:int, index:int,
52
+ spacing:int=0, margin:int=0, inset:int=0):
53
+ """
54
+ Extract a specific frame from a sprite sheet.
55
+
56
+ *You will not need to use this function directly.*
57
+
58
+ THIS FUNCTION IS WRITTEN BY AN AI.
59
+
60
+
61
+ The index starts from the top-left as 0,
62
+ and increments left-to-right before up-to-down.
63
+ For example, for a 3x3 sheet, the index would be
64
+ ```
65
+ 0 1 2
66
+ 3 4 5
67
+ 6 7 8
68
+ ```
69
+ """
70
+ sheet_rect = sheet.get_rect()
71
+
72
+ total_spacing_x = spacing * (columns - 1)
73
+ total_spacing_y = spacing * (rows - 1)
74
+
75
+ total_margin_x = margin * 2
76
+ total_margin_y = margin * 2
77
+
78
+ frame_width = (sheet_rect.width - total_spacing_x - total_margin_x) // columns
79
+ frame_height = (sheet_rect.height - total_spacing_y - total_margin_y) // rows
80
+
81
+ col = index % columns
82
+ row = index // columns
83
+
84
+ x = margin + col * (frame_width + spacing)
85
+ y = margin + row * (frame_height + spacing)
86
+
87
+ # Apply internal cropping (inset) from all sides
88
+ cropped_rect = pygame.Rect(
89
+ x + inset,
90
+ y + inset,
91
+ frame_width - 2 * inset,
92
+ frame_height - 2 * inset
93
+ )
94
+
95
+ return sheet.subsurface(cropped_rect)
96
+
97
+ def get_frame_from_sprite_sheet_by_frame_size(
98
+ sheet: pygame.Surface,
99
+ size_x: int, size_y: int,
100
+ c:int, r: int):
101
+ """
102
+ Extract a specific frame from a sprite sheet.
103
+
104
+ *You will not need to use this function directly.*
105
+
106
+
107
+ Parameters
108
+ ---
109
+ sheet: pygame.Surface
110
+ The sprite sheet you want to cut
111
+
112
+ size_x: int
113
+ The x pixel size of the frame
114
+
115
+ size_y: int
116
+ The y pixel size of the frame
117
+
118
+ c: int
119
+ The column position of the frame
120
+
121
+ r: int
122
+ The row position of the frame
123
+ """
124
+ crop_rect = pygame.Rect(
125
+ c*size_x,
126
+ r*size_y,
127
+ size_x,
128
+ size_y
129
+ )
130
+
131
+ return sheet.subsurface(crop_rect)
132
+
133
+ from PIL import Image, ImageSequence
134
+ import pygame
135
+
136
+ @cache
137
+ def load_gif_frames(path) -> List[pygame.Surface]:
138
+ """
139
+ Load a gif file as a list of images (as `pygame.Surface`)
140
+
141
+ *You will not need to use this function directly.*
142
+
143
+ THIS FUNCTION IS WRITTEN BY AN AI.
144
+
145
+ """
146
+ pil = Image.open(path)
147
+ frames = []
148
+ for frame in ImageSequence.Iterator(pil):
149
+ mode = frame.convert("RGBA")
150
+ data = mode.tobytes()
151
+ size = mode.size
152
+ surf = pygame.image.frombuffer(data, size, "RGBA").convert_alpha()
153
+ frames.append(surf)
154
+ return frames
155
+
156
+
157
+ @cache
158
+ def load_frames_from_gif_folder(folder_path: Path):
159
+ """
160
+ Creates a `frame_dict` that the Sprite constructor takes using
161
+ the gif files inside a folder.
162
+
163
+ The folder should be organised in the following way:
164
+ ```
165
+ ├─ player/
166
+ ├─ walking.gif
167
+ ├─ idling.gif
168
+ ├─ jumping.gif
169
+ ...
170
+ ```
171
+
172
+ *You will not need to use this function directly.*
173
+
174
+
175
+ """
176
+ frame_dict = {}
177
+ for f in folder_path.iterdir():
178
+ if f.suffix != '.gif':
179
+ print(f"ignoring {f.name} (not a gif)")
180
+ continue
181
+
182
+ frame_dict[f.stem] = load_gif_frames(f)
183
+
184
+ return frame_dict
185
+
186
+
187
+
188
+
189
+ def cut_sprite_sheet(
190
+ sheet: pygame.Surface,
191
+ columns, rows,
192
+ spacing=0, margin=0, inset=0,
193
+ folder_path='.',
194
+ suffix='png'):
195
+ """
196
+ Split a sprite sheet so each frame is its own image file.
197
+
198
+ *You probably won't need to use this function directly.*
199
+
200
+ Parameters
201
+ ---
202
+ sheet: pygame.Surface
203
+ The sprite sheet image
204
+ columns: int
205
+ The total number of columns of the sheet
206
+ rows: int
207
+ The total number of rows of the sheet
208
+ spacing: int
209
+ Keep it as zero.
210
+ margin: int
211
+ Keep it as zero.
212
+ inset: int
213
+ Keep it as zero.
214
+ folder_path: str
215
+ The path of the destination folder to put the splitted images.
216
+ suffix: str
217
+ The file extension
218
+ """
219
+
220
+ folder_path = Path(folder_path)
221
+ if not folder_path.exists():
222
+ folder_path.mkdir()
223
+ for i in range(columns*rows):
224
+ f = get_frame_from_sprite_sheet(sheet, columns, rows, i, spacing, margin, inset)
225
+ pygame.image.save(f, folder_path/f"{i}.{suffix}")
226
+
227
+ def _get_frame_sequence(sheet:pygame.Surface, columns:int, rows:int, indices:List[int], spacing:int, margin:int, inset:int):
228
+ """
229
+ **You will not need to use this function directly.**
230
+ """
231
+ return [get_frame_from_sprite_sheet(sheet, columns, rows, i, spacing, margin, inset) for i in indices]
232
+
233
+ def _get_frame_dict(
234
+ sheet:pygame.Surface, columns:int, rows:int,
235
+ indices_dict: Dict[str, List[int]],
236
+ spacing:int=0, margin:int=0, inset:int=0):
237
+ """
238
+ **You will not need to use this function directly.**
239
+ """
240
+ frame_dict = {}
241
+ for k, v in indices_dict.items():
242
+ assert isinstance(v, list) or isinstance(v, tuple)
243
+
244
+ frame_dict[k] = _get_frame_sequence(sheet, columns, rows, v, spacing, margin, inset)
245
+
246
+ return frame_dict
247
+
248
+ @cache
249
+ def load_frames_from_folder(folder_path: Union[Path, str]):
250
+ """
251
+ Creates a `frame_dict` that the Sprite constructor takes using
252
+ the images inside a folder.
253
+ You can use `sprite.create_animated_sprite` instead for convenience.
254
+
255
+ The folder should be organised in one of these two ways:
256
+
257
+ **Option 1**: Only one frame mode. *Note that the images must be numbered.*
258
+ ```
259
+ ├─ player/
260
+ ├─ 0.png
261
+ ├─ 1.png
262
+ ├─ 2.png
263
+ ...
264
+ ```
265
+
266
+ **Option 2**: Multiple frame modes. *Note that the images must be numbered.*
267
+ ```
268
+ ├─ player/
269
+ ├─ walking/
270
+ ├─ 0.png
271
+ ├─ 1.png
272
+ ...
273
+ ├─ idling/
274
+ ├─ 0.png
275
+ ├─ 1.png
276
+ ...
277
+ ...
278
+ ```
279
+ Example
280
+ ```python
281
+ frame_dict = load_frames_from_folder("assets/player")
282
+ my_sprite1 = Sprite(frame_dict)
283
+ ```
284
+ """
285
+ return _load_frames_from_folder_uncached(folder_path)
286
+
287
+
288
+
289
+ def _load_frames_from_folder_uncached(folder_path: Union[Path, str]):
290
+
291
+ def extract_images(path: Path):
292
+ index2image: Dict[int, pygame.Surface] = {}
293
+
294
+ for f in path.iterdir():
295
+ if f.is_dir():
296
+ continue
297
+
298
+ if not f.stem.isdigit():
299
+ print(f'skipping: {f.name}')
300
+ continue
301
+ index2image[int(f.stem)] = pygame.image.load(f).convert_alpha()
302
+
303
+ return [index2image[i] for i in sorted(index2image.keys())]
304
+
305
+
306
+ path = Path(folder_path)
307
+
308
+ folder_seen = False
309
+ file_seen = False
310
+
311
+ frame_dict = {}
312
+ for f in path.iterdir():
313
+ if f.is_dir():
314
+ folder_seen = True
315
+ assert not file_seen
316
+ frame_dict[f.stem] = extract_images(f)
317
+ else:
318
+ file_seen = True
319
+ assert not folder_seen
320
+
321
+ if not folder_seen:
322
+ frame_dict[path.stem] = extract_images(path)
323
+
324
+ return frame_dict
325
+
326
+ #RGBType = Tuple[int, int, int]
327
+ #RGBAType = Tuple[int, int, int, int]
328
+ #ColourType = Union[RGBAType, RGBType]
329
+
330
+ def create_circle(colour, radius: float) -> pygame.Surface:
331
+ """
332
+ Create a circle image (pygame.Surface) given the colour and radius.
333
+
334
+ Parameters
335
+ ---
336
+ colour: Tuple[int, int, int] or Tuple[int, int, int, int]
337
+ The colour of the rectangle in RGB or RGBA. Value range: [0-255].
338
+ radius: float
339
+ the radius of the cirlce.
340
+ """
341
+ surface = pygame.Surface((radius*2, radius*2), pygame.SRCALPHA)
342
+ pygame.draw.circle(surface, colour, (radius, radius), radius)
343
+ return surface
344
+
345
+
346
+ def create_rect(colour, width: float, height: float) -> pygame.Surface:
347
+ """
348
+ Create a rectangle image (pygame.Surface) given the colour, width and height
349
+
350
+ Parameters
351
+ ---
352
+ colour: Tuple[int, int, int] or Tuple[int, int, int, int]
353
+ The colour of the rectangle in RGB or RGBA. Value range: [0-255].
354
+ width: float
355
+ the width (x length) of the rectangle.
356
+ height: float
357
+ the height (y length) of the rectangle.
358
+ """
359
+
360
+ surface = pygame.Surface((width, height), pygame.SRCALPHA)
361
+ pygame.draw.rect(surface, colour, surface.get_rect())
362
+ return surface
363
+
364
+ def scale_and_tile(image, screen_size, scale_factor):
365
+ """
366
+ Scale an image by a factor and tile it to fill the screen.
367
+
368
+ THIS FUNCTION IS WRITTEN BY AN AI.
369
+
370
+ Parameters
371
+ ----------
372
+ image : pygame.Surface
373
+ The image to scale and tile.
374
+ screen_size : tuple of int
375
+ The width and height of the target surface.
376
+ scale_factor : float
377
+ Factor by which to scale the image.
378
+ """
379
+
380
+ img_w, img_h = image.get_size()
381
+ new_img = pygame.transform.smoothscale(image, (int(img_w * scale_factor), int(img_h * scale_factor)))
382
+ new_img_w, new_img_h = new_img.get_size()
383
+
384
+ tiled_surface = pygame.Surface(screen_size)
385
+
386
+ for y in range(0, screen_size[1], new_img_h):
387
+ for x in range(0, screen_size[0], new_img_w):
388
+ tiled_surface.blit(new_img, (x, y))
389
+
390
+ return tiled_surface
391
+
392
+
393
+ def scale_to_fill(image:pygame.Surface, new_size:Tuple[int, int]):
394
+ """
395
+ Scale an image to a new size without preserving aspect ratio.
396
+
397
+ Parameters
398
+ ----------
399
+ image : pygame.Surface
400
+ The image to scale.
401
+ new_size : tuple of int
402
+ Target width and height of the image.
403
+ """
404
+ return pygame.transform.smoothscale(image, new_size)
405
+
406
+
407
+ def scale_to_fit_aspect(image:pygame.Surface, new_size:Tuple[int, int], fit='horizontal'):
408
+ """
409
+ Scale an image to fit a rect while preserving aspect ratio.
410
+
411
+ THIS FUNCTION IS WRITTEN BY AN AI.
412
+
413
+ Parameters
414
+ ----------
415
+ image : pygame.Surface
416
+ The image to scale.
417
+ new_size : tuple of int
418
+ The width and height of the target rect.
419
+ fit : 'horizontal' or 'vertical'
420
+ Axis to fit the image against. Default is 'horizontal'.
421
+ """
422
+ img_rect = image.get_rect()
423
+ screen_w, screen_h = new_size
424
+ img_w, img_h = img_rect.size
425
+
426
+ if fit == 'horizontal':
427
+ scale_factor = screen_w / img_w
428
+ elif fit == 'vertical':
429
+ scale_factor = screen_h / img_h
430
+ else:
431
+ raise ValueError("fit must be either 'horizontal' or 'vertical'")
432
+
433
+ new_size = (int(img_w * scale_factor), int(img_h * scale_factor))
434
+ return pygame.transform.smoothscale(image, new_size)
435
+
436
+
437
+ def _set_transparency(image, factor):
438
+ """
439
+ Set the transparency of an image.
440
+
441
+ THIS FUNCTION IS WRITTEN BY AN AI.
442
+
443
+ ***IMCOMPLETE IMPLEMENTATION***:
444
+ The transparency of the transparent background of the image is also changed
445
+
446
+
447
+ Parameters
448
+ ----------
449
+ image : pygame.Surface
450
+ The image to adjust.
451
+ factor : float
452
+ Transparency level from 0.0 (fully transparent) to 1.0 (fully opaque).
453
+ """
454
+ new_image = image.copy()
455
+ new_image.set_alpha(int(factor*255))
456
+ return new_image
457
+
458
+ def set_transparency(image: pygame.Surface, factor):
459
+ """
460
+ Get a new copy of the image with the transparency applied.
461
+
462
+ Parameters
463
+ ----------
464
+ image : pygame.Surface
465
+ The image to adjust.
466
+ factor : float
467
+ Transparency level from 0.0 (fully transparent) to 1.0 (fully opaque).
468
+ """
469
+ w = image.get_width()
470
+ h = image.get_height()
471
+
472
+ sur = pygame.Surface((w, h)).convert_alpha()
473
+
474
+ sur.fill((255,255,255,int(factor*255) ))
475
+ #sur.set_alpha(int(factor*255))
476
+
477
+ new_image = image.copy()
478
+ new_image.blit(sur, (0,0), special_flags=pygame.BLEND_RGBA_MULT)
479
+ return new_image
480
+
481
+
482
+ def adjust_brightness(image, factor):
483
+ """
484
+ Get a new copy of the image with the brightness changes applied.
485
+
486
+ THIS FUNCTION IS WRITTEN BY AN AI.
487
+
488
+ Parameters
489
+ ----------
490
+ image : pygame.Surface
491
+ The image to adjust.
492
+ factor : float
493
+ Brightness multiplier. Values < 1.0 darken, values > 1.0 brighten.
494
+
495
+ """
496
+ new_image = image.copy()
497
+ brightness_surface = pygame.Surface(image.get_size()).convert_alpha()
498
+ brightness_surface.fill((255, 255, 255, 0)) # Start with no change
499
+
500
+ # Per-pixel operation is slow. Instead, we use special_flags to modulate brightness.
501
+ if factor < 1:
502
+ # Darken using multiply blend mode
503
+ darken_surface = pygame.Surface(image.get_size()).convert_alpha()
504
+ value = int(255 * factor)
505
+ darken_surface.fill((value, value, value))
506
+ new_image.blit(darken_surface, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)
507
+ elif factor > 1:
508
+ # Brighten by blending in white
509
+ value = int(255 * (factor - 1))
510
+ brighten_surface = pygame.Surface(image.get_size()).convert_alpha()
511
+ brighten_surface.fill((value, value, value))
512
+ new_image.blit(brighten_surface, (0, 0), special_flags=pygame.BLEND_RGBA_ADD)
513
+
514
+ return new_image
515
+
516
+
517
+ def _draw_guide_lines(screen: pygame.Surface, font: pygame.font.Font, minor_grid, major_grid):
518
+ w, h = screen.get_width(), screen.get_height()
519
+
520
+
521
+ pygame.draw.lines(screen, (0,0,0), True, [(0,0), (0, h), (w, h), (w, 0)])
522
+ screen.blit(font.render(f"({0},{0})", True, (0,0,0)), (5,5))
523
+ for i in range(0, w, minor_grid):
524
+ lw = 1
525
+ v = 200
526
+ if i and (not i % major_grid):
527
+ lw = 1
528
+ v = 0
529
+ screen.blit(font.render(f"{i}", True, (0,0,0)), (i+5,5))
530
+
531
+ pygame.draw.line(screen, (v,v,v,255-v), (i, 0), (i, h), width=lw)
532
+
533
+
534
+
535
+
536
+ for i in range(0, h, minor_grid):
537
+ lw = 1
538
+ v = 200
539
+ if i and (not i % major_grid):
540
+ lw = 1
541
+ v = 0
542
+ screen.blit(font.render(f"{i}", True, (0,0,0)), (5,i+5))
543
+ pygame.draw.line(screen, (v,v,v,255-v), (0, i), (w, i), width=lw)
544
+
545
+ #text = font.render(f"({w},{h})", True, (0,0,0))
546
+ #screen.blit(text, (w-5-text.get_width(), h-5-text.get_height()))
547
+
548
+
549
+ for x, y in product(range(major_grid, w, major_grid), range(major_grid, h, major_grid)):
550
+ text = font.render(f"({x},{y})", True, (0,0,0))
551
+ screen.blit(text, (x+5, y+5))
552
+
553
+
554
+
555
+ def _show_mouse_position(screen, font):
556
+ w, h = screen.get_width(), screen.get_height()
557
+
558
+ mx, my = pygame.mouse.get_pos()
559
+
560
+ text = font.render(f"({mx},{my})", True, (0,0,0))
561
+ screen.blit(text, (w-5-text.get_width(), h-5-text.get_height()))