crystalwindow 3.7.1b1__tar.gz → 3.8.1__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.
- {crystalwindow-3.7.1b1/crystalwindow.egg-info → crystalwindow-3.8.1}/PKG-INFO +1 -1
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/__init__.py +21 -5
- crystalwindow-3.8.1/crystalwindow/assets.py +150 -0
- crystalwindow-3.8.1/crystalwindow/sprites.py +115 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1/crystalwindow.egg-info}/PKG-INFO +1 -1
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/setup.py +1 -1
- crystalwindow-3.7.1b1/crystalwindow/assets.py +0 -72
- crystalwindow-3.7.1b1/crystalwindow/sprites.py +0 -78
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/LICENSE +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/MANIFEST.in +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/README.md +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/FileHelper.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/Icons/default_icon.png +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/animation.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/camera.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/clock.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/collision.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/crystal3d.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/docs/getting_started.md +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/docs/index.md +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/draw_helpers.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/draw_rects.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/draw_text_helper.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/draw_tool.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/fun_helpers.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/gametests/3dsquare.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/gametests/__init__.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/gametests/__main__.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/gametests/gravitytest.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/gametests/guitesting.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/gametests/sandbox.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/gametests/squaremove.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/gametests/windowtesting.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/gravity.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/gui.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/gui_ext.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/math.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/player.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/tilemap.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/ver_warner.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow/window.py +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow.egg-info/SOURCES.txt +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow.egg-info/dependency_links.txt +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/crystalwindow.egg-info/top_level.txt +0 -0
- {crystalwindow-3.7.1b1 → crystalwindow-3.8.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crystalwindow
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.8.1
|
|
4
4
|
Summary: A Tkinter powered window + GUI toolkit made by Crystal (MEEEEEE)! Easier apps, smoother UI and all-in-one helpers!
|
|
5
5
|
Home-page: https://pypi.org/project/crystalwindow/
|
|
6
6
|
Author: CrystalBallyHereXD
|
|
@@ -12,7 +12,15 @@ from .FileHelper import FileHelper
|
|
|
12
12
|
from .math import Mathematics
|
|
13
13
|
|
|
14
14
|
# === Assets & Animation ===
|
|
15
|
-
from .assets import
|
|
15
|
+
from .assets import (
|
|
16
|
+
load_image,
|
|
17
|
+
load_folder_images,
|
|
18
|
+
load_music,
|
|
19
|
+
play_music,
|
|
20
|
+
flip_image,
|
|
21
|
+
flip_horizontal,
|
|
22
|
+
flip_vertical,
|
|
23
|
+
)
|
|
16
24
|
from .animation import Animation
|
|
17
25
|
|
|
18
26
|
# === Collision ===
|
|
@@ -23,7 +31,7 @@ from .gui import Button, Label, GUIManager, random_color, hex_to_rgb, Fade
|
|
|
23
31
|
from .gui_ext import Toggle, Slider
|
|
24
32
|
|
|
25
33
|
# === Time ===
|
|
26
|
-
from .clock import Clock
|
|
34
|
+
from .clock import Clock
|
|
27
35
|
|
|
28
36
|
# === Drawing Helpers ===
|
|
29
37
|
from .draw_helpers import gradient_rect, CameraShake
|
|
@@ -36,14 +44,22 @@ from .fun_helpers import random_name, DebugOverlay
|
|
|
36
44
|
from .camera import Camera
|
|
37
45
|
|
|
38
46
|
# === 3D Engine ===
|
|
39
|
-
from .crystal3d import CW3D
|
|
47
|
+
from .crystal3d import CW3D
|
|
48
|
+
|
|
40
49
|
|
|
41
50
|
__all__ = [
|
|
42
51
|
# --- Core ---
|
|
43
52
|
"Window", "Sprite", "TileMap", "Player", "Gravity", "FileHelper", "Mathematics",
|
|
44
53
|
|
|
45
54
|
# --- Assets & Animation ---
|
|
46
|
-
"load_image",
|
|
55
|
+
"load_image",
|
|
56
|
+
"load_folder_images",
|
|
57
|
+
"load_music",
|
|
58
|
+
"play_music",
|
|
59
|
+
"flip_image",
|
|
60
|
+
"flip_horizontal",
|
|
61
|
+
"flip_vertical",
|
|
62
|
+
"Animation",
|
|
47
63
|
|
|
48
64
|
# --- Collision ---
|
|
49
65
|
"check_collision", "resolve_collision",
|
|
@@ -64,5 +80,5 @@ __all__ = [
|
|
|
64
80
|
"random_name", "DebugOverlay", "Camera",
|
|
65
81
|
|
|
66
82
|
# --- 3D ---
|
|
67
|
-
"CW3D"
|
|
83
|
+
"CW3D",
|
|
68
84
|
]
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# assets.py
|
|
2
|
+
import os
|
|
3
|
+
import random
|
|
4
|
+
from tkinter import PhotoImage
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
from PIL import Image, ImageTk
|
|
8
|
+
except ImportError:
|
|
9
|
+
Image = None
|
|
10
|
+
ImageTk = None
|
|
11
|
+
|
|
12
|
+
ASSETS = {} # cache for all loaded images
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# --------------------------------------------------------
|
|
16
|
+
# MAIN IMAGE LOADER
|
|
17
|
+
# --------------------------------------------------------
|
|
18
|
+
def load_image(path, flip_h=False, flip_v=False):
|
|
19
|
+
"""
|
|
20
|
+
Loads an image and returns a Tk PhotoImage.
|
|
21
|
+
Supports flipping using Pillow.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
key = f"{path}|h={flip_h}|v={flip_v}"
|
|
25
|
+
if key in ASSETS:
|
|
26
|
+
return ASSETS[key]
|
|
27
|
+
|
|
28
|
+
if not os.path.exists(path):
|
|
29
|
+
print(f"⚠️ Missing file: {path}")
|
|
30
|
+
img = generate_fallback(path)
|
|
31
|
+
ASSETS[key] = img
|
|
32
|
+
return img
|
|
33
|
+
|
|
34
|
+
# If Pillow is missing → load normal image
|
|
35
|
+
if Image is None or ImageTk is None:
|
|
36
|
+
try:
|
|
37
|
+
img = PhotoImage(file=path)
|
|
38
|
+
ASSETS[key] = img
|
|
39
|
+
return img
|
|
40
|
+
except:
|
|
41
|
+
fb = generate_fallback(path)
|
|
42
|
+
ASSETS[key] = fb
|
|
43
|
+
return fb
|
|
44
|
+
|
|
45
|
+
# Load with PIL to allow flipping
|
|
46
|
+
try:
|
|
47
|
+
pil_img = Image.open(path)
|
|
48
|
+
|
|
49
|
+
if flip_h:
|
|
50
|
+
pil_img = pil_img.transpose(Image.FLIP_LEFT_RIGHT)
|
|
51
|
+
if flip_v:
|
|
52
|
+
pil_img = pil_img.transpose(Image.FLIP_TOP_BOTTOM)
|
|
53
|
+
|
|
54
|
+
tk_img = ImageTk.PhotoImage(pil_img)
|
|
55
|
+
ASSETS[key] = tk_img
|
|
56
|
+
return tk_img
|
|
57
|
+
|
|
58
|
+
except Exception as e:
|
|
59
|
+
print(f"⚠️ Error loading {path}: {e}")
|
|
60
|
+
fb = generate_fallback(path)
|
|
61
|
+
ASSETS[key] = fb
|
|
62
|
+
return fb
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# --------------------------------------------------------
|
|
66
|
+
# FALLBACK NODE
|
|
67
|
+
# --------------------------------------------------------
|
|
68
|
+
def generate_fallback(path):
|
|
69
|
+
"""Fallback colored block used when an image is missing."""
|
|
70
|
+
rand_color = (
|
|
71
|
+
random.randint(50, 255),
|
|
72
|
+
random.randint(50, 255),
|
|
73
|
+
random.randint(50, 255),
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
if Image:
|
|
77
|
+
try:
|
|
78
|
+
pil_img = Image.open(path)
|
|
79
|
+
w, h = pil_img.size
|
|
80
|
+
except:
|
|
81
|
+
w, h = 64, 64
|
|
82
|
+
else:
|
|
83
|
+
w, h = 64, 64
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
"fallback": True,
|
|
87
|
+
"size": (w, h),
|
|
88
|
+
"color": rand_color
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# --------------------------------------------------------
|
|
93
|
+
# PYGAME-STYLE FLIP HELPERS
|
|
94
|
+
# --------------------------------------------------------
|
|
95
|
+
def flip_image(img, flip_h=False, flip_v=False):
|
|
96
|
+
"""
|
|
97
|
+
Returns a NEW flipped PhotoImage.
|
|
98
|
+
Like pygame.transform.flip().
|
|
99
|
+
"""
|
|
100
|
+
if Image is None or ImageTk is None:
|
|
101
|
+
print("⚠️ Pillow not installed; cannot flip images.")
|
|
102
|
+
return img
|
|
103
|
+
|
|
104
|
+
pil_img = ImageTk.getimage(img)
|
|
105
|
+
|
|
106
|
+
if flip_h:
|
|
107
|
+
pil_img = pil_img.transpose(Image.FLIP_LEFT_RIGHT)
|
|
108
|
+
if flip_v:
|
|
109
|
+
pil_img = pil_img.transpose(Image.FLIP_TOP_BOTTOM)
|
|
110
|
+
|
|
111
|
+
return ImageTk.PhotoImage(pil_img)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def flip_horizontal(img):
|
|
115
|
+
return flip_image(img, flip_h=True)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def flip_vertical(img):
|
|
119
|
+
return flip_image(img, flip_v=True)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# --------------------------------------------------------
|
|
123
|
+
# FOLDER LOADING
|
|
124
|
+
# --------------------------------------------------------
|
|
125
|
+
def load_folder_images(folder, nested=True):
|
|
126
|
+
if not os.path.exists(folder):
|
|
127
|
+
print(f"⚠️ Folder not found: {folder}")
|
|
128
|
+
return {}
|
|
129
|
+
|
|
130
|
+
result = {}
|
|
131
|
+
for item in os.listdir(folder):
|
|
132
|
+
full = os.path.join(folder, item)
|
|
133
|
+
|
|
134
|
+
if os.path.isdir(full) and nested:
|
|
135
|
+
result[item] = load_folder_images(full)
|
|
136
|
+
|
|
137
|
+
elif item.lower().endswith((".png", ".gif")):
|
|
138
|
+
result[item] = load_image(full)
|
|
139
|
+
|
|
140
|
+
return result
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# --------------------------------------------------------
|
|
144
|
+
# MUSIC PLACEHOLDER
|
|
145
|
+
# --------------------------------------------------------
|
|
146
|
+
def load_music(path):
|
|
147
|
+
print(f"[assets] Music load not supported: {path}")
|
|
148
|
+
|
|
149
|
+
def play_music(loop=-1):
|
|
150
|
+
print("[assets] Music playback not supported.")
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# sprites.py
|
|
2
|
+
from tkinter import PhotoImage
|
|
3
|
+
from PIL import Image, ImageTk
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Sprite:
|
|
7
|
+
def __init__(self, pos, size=None, image=None, color=(255, 0, 0)):
|
|
8
|
+
self.x, self.y = pos
|
|
9
|
+
self.pos = pos
|
|
10
|
+
|
|
11
|
+
self.image = None
|
|
12
|
+
self.color = color
|
|
13
|
+
|
|
14
|
+
# If fallback dict provided from assets
|
|
15
|
+
if isinstance(image, dict) and image.get("fallback"):
|
|
16
|
+
self.width, self.height = image["size"]
|
|
17
|
+
self.color = image["color"]
|
|
18
|
+
|
|
19
|
+
# Normal image
|
|
20
|
+
elif isinstance(image, PhotoImage):
|
|
21
|
+
self.set_image(image)
|
|
22
|
+
|
|
23
|
+
# Rectangle sprite
|
|
24
|
+
elif size is not None:
|
|
25
|
+
self.width, self.height = size
|
|
26
|
+
|
|
27
|
+
else:
|
|
28
|
+
raise ValueError("Sprite needs 'size' or 'image'")
|
|
29
|
+
|
|
30
|
+
# Movement physics
|
|
31
|
+
self.vel_x = 0
|
|
32
|
+
self.vel_y = 0
|
|
33
|
+
|
|
34
|
+
# Optional direction flag
|
|
35
|
+
self.facing_left = False
|
|
36
|
+
|
|
37
|
+
# --------------------------------------
|
|
38
|
+
# Constructors
|
|
39
|
+
# --------------------------------------
|
|
40
|
+
@classmethod
|
|
41
|
+
def image(cls, img, pos):
|
|
42
|
+
if isinstance(img, dict) and img.get("fallback"):
|
|
43
|
+
w, h = img["size"]
|
|
44
|
+
color = img["color"]
|
|
45
|
+
return cls(pos, size=(w, h), color=color)
|
|
46
|
+
return cls(pos, image=img)
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def rect(cls, pos, w, h, color=(255, 0, 0)):
|
|
50
|
+
return cls(pos, size=(w, h), color=color)
|
|
51
|
+
|
|
52
|
+
# --------------------------------------
|
|
53
|
+
# Draw
|
|
54
|
+
# --------------------------------------
|
|
55
|
+
def draw(self, win, cam=None):
|
|
56
|
+
if cam:
|
|
57
|
+
draw_x, draw_y = cam.apply(self)
|
|
58
|
+
else:
|
|
59
|
+
draw_x, draw_y = self.x, self.y
|
|
60
|
+
|
|
61
|
+
if self.image:
|
|
62
|
+
win.canvas.create_image(draw_x, draw_y, anchor="nw", image=self.image)
|
|
63
|
+
else:
|
|
64
|
+
win.draw_rect(self.color, (draw_x, draw_y, self.width, self.height))
|
|
65
|
+
|
|
66
|
+
# --------------------------------------
|
|
67
|
+
# Movement
|
|
68
|
+
# --------------------------------------
|
|
69
|
+
def move(self, dx, dy):
|
|
70
|
+
self.x += dx
|
|
71
|
+
self.y += dy
|
|
72
|
+
self.pos = (self.x, self.y)
|
|
73
|
+
|
|
74
|
+
def apply_velocity(self, dt=1):
|
|
75
|
+
self.x += self.vel_x * dt
|
|
76
|
+
self.y += self.vel_y * dt
|
|
77
|
+
self.pos = (self.x, self.y)
|
|
78
|
+
|
|
79
|
+
# --------------------------------------
|
|
80
|
+
# Image setter
|
|
81
|
+
# --------------------------------------
|
|
82
|
+
def set_image(self, new_image):
|
|
83
|
+
"""Set sprite image and update size."""
|
|
84
|
+
self.image = new_image
|
|
85
|
+
self.width = new_image.width()
|
|
86
|
+
self.height = new_image.height()
|
|
87
|
+
|
|
88
|
+
# --------------------------------------
|
|
89
|
+
# In-place flipping (optional)
|
|
90
|
+
# --------------------------------------
|
|
91
|
+
def flip_horizontal(self):
|
|
92
|
+
if not self.image:
|
|
93
|
+
return
|
|
94
|
+
pil = ImageTk.getimage(self.image)
|
|
95
|
+
flipped = pil.transpose(Image.FLIP_LEFT_RIGHT)
|
|
96
|
+
self.set_image(ImageTk.PhotoImage(flipped))
|
|
97
|
+
self.facing_left = not self.facing_left
|
|
98
|
+
|
|
99
|
+
def flip_vertical(self):
|
|
100
|
+
if not self.image:
|
|
101
|
+
return
|
|
102
|
+
pil = ImageTk.getimage(self.image)
|
|
103
|
+
flipped = pil.transpose(Image.FLIP_TOP_BOTTOM)
|
|
104
|
+
self.set_image(ImageTk.PhotoImage(flipped))
|
|
105
|
+
|
|
106
|
+
# --------------------------------------
|
|
107
|
+
# Collision
|
|
108
|
+
# --------------------------------------
|
|
109
|
+
def colliderect(self, other):
|
|
110
|
+
return (
|
|
111
|
+
self.x < other.x + other.width and
|
|
112
|
+
self.x + self.width > other.x and
|
|
113
|
+
self.y < other.y + other.height and
|
|
114
|
+
self.y + self.height > other.y
|
|
115
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: crystalwindow
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.8.1
|
|
4
4
|
Summary: A Tkinter powered window + GUI toolkit made by Crystal (MEEEEEE)! Easier apps, smoother UI and all-in-one helpers!
|
|
5
5
|
Home-page: https://pypi.org/project/crystalwindow/
|
|
6
6
|
Author: CrystalBallyHereXD
|
|
@@ -7,7 +7,7 @@ with open("README.md", encoding="utf-8") as f:
|
|
|
7
7
|
|
|
8
8
|
setup(
|
|
9
9
|
name="crystalwindow",
|
|
10
|
-
version="3.
|
|
10
|
+
version="3.8.1", # Force metadata refresh
|
|
11
11
|
packages=find_packages(include=["crystalwindow", "crystalwindow.*"]),
|
|
12
12
|
|
|
13
13
|
include_package_data=True, # include package_data files
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import random
|
|
3
|
-
from tkinter import PhotoImage
|
|
4
|
-
|
|
5
|
-
try:
|
|
6
|
-
from PIL import Image
|
|
7
|
-
except:
|
|
8
|
-
Image = None
|
|
9
|
-
|
|
10
|
-
ASSETS = {}
|
|
11
|
-
|
|
12
|
-
def load_image(path):
|
|
13
|
-
# try normal load
|
|
14
|
-
if os.path.exists(path):
|
|
15
|
-
try:
|
|
16
|
-
img = PhotoImage(file=path)
|
|
17
|
-
ASSETS[path] = img
|
|
18
|
-
return img
|
|
19
|
-
except:
|
|
20
|
-
print(f"⚠️ Ops!, could not load img: {path}")
|
|
21
|
-
else:
|
|
22
|
-
print(f"⚠️ Ops!, file not found: {path}")
|
|
23
|
-
|
|
24
|
-
# fallback: get natural size using PIL if possible
|
|
25
|
-
if Image is not None:
|
|
26
|
-
try:
|
|
27
|
-
pil_img = Image.open(path)
|
|
28
|
-
w, h = pil_img.size
|
|
29
|
-
except:
|
|
30
|
-
w, h = 64, 64
|
|
31
|
-
else:
|
|
32
|
-
w, h = 64, 64
|
|
33
|
-
|
|
34
|
-
# RANDOM COLOR FALLBACK (chaos energy)
|
|
35
|
-
rand_color = (
|
|
36
|
-
random.randint(0, 255),
|
|
37
|
-
random.randint(0, 255),
|
|
38
|
-
random.randint(0, 255)
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
"fallback": True,
|
|
43
|
-
"size": (w, h),
|
|
44
|
-
"color": rand_color
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def load_folder_images(folder, nested=True):
|
|
49
|
-
if not os.path.exists(folder):
|
|
50
|
-
print(f"⚠️ Ops!, folder not found: {folder}")
|
|
51
|
-
return {}
|
|
52
|
-
|
|
53
|
-
result = {}
|
|
54
|
-
for item in os.listdir(folder):
|
|
55
|
-
full_path = os.path.join(folder, item)
|
|
56
|
-
|
|
57
|
-
if os.path.isdir(full_path) and nested:
|
|
58
|
-
result[item] = load_folder_images(full_path, nested=True)
|
|
59
|
-
|
|
60
|
-
elif item.lower().endswith((".png", ".gif")):
|
|
61
|
-
result[item] = load_image(full_path)
|
|
62
|
-
|
|
63
|
-
return result
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def load_music(path):
|
|
67
|
-
print(f"[assets] Music loading not supported in this crystalwindow ver, sorry! ~Crystal: {path}")
|
|
68
|
-
return None
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def play_music(loop=-1):
|
|
72
|
-
print("[assets] Music playback not supported in this ver sorry! ~Crystal")
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import random
|
|
2
|
-
from tkinter import PhotoImage
|
|
3
|
-
|
|
4
|
-
class Sprite:
|
|
5
|
-
def __init__(self, pos, size=None, image=None, color=(255, 0, 0)):
|
|
6
|
-
"""
|
|
7
|
-
pos: (x, y)
|
|
8
|
-
size: (w, h) optional
|
|
9
|
-
image: PhotoImage (Tkinter)
|
|
10
|
-
color: fill color if no image
|
|
11
|
-
"""
|
|
12
|
-
self.pos = pos
|
|
13
|
-
self.x, self.y = pos
|
|
14
|
-
self.image = image
|
|
15
|
-
self.color = color
|
|
16
|
-
|
|
17
|
-
if image is not None:
|
|
18
|
-
self.width = image.width()
|
|
19
|
-
self.height = image.height()
|
|
20
|
-
elif size is not None:
|
|
21
|
-
self.width, self.height = size
|
|
22
|
-
else:
|
|
23
|
-
raise ValueError("Sprite needs either 'size' or 'image'")
|
|
24
|
-
|
|
25
|
-
# optional velocity fields for physics
|
|
26
|
-
self.vel_x = 0
|
|
27
|
-
self.vel_y = 0
|
|
28
|
-
|
|
29
|
-
# === CLASS METHODS ===
|
|
30
|
-
@classmethod
|
|
31
|
-
def image(cls, img, pos):
|
|
32
|
-
# fallback if img is missing
|
|
33
|
-
if isinstance(img, dict) and img.get("fallback"):
|
|
34
|
-
print("⚠️ Missing image, making RANDOM rect fallback.")
|
|
35
|
-
w, h = img["size"]
|
|
36
|
-
color = img["color"]
|
|
37
|
-
return cls.rect(pos, w, h, color=color)
|
|
38
|
-
return cls(pos, image=img)
|
|
39
|
-
|
|
40
|
-
@classmethod
|
|
41
|
-
def rect(cls, pos, w, h, color=(255, 0, 0)):
|
|
42
|
-
"""Create sprite using a plain colored rectangle"""
|
|
43
|
-
return cls(pos, size=(w, h), color=color)
|
|
44
|
-
|
|
45
|
-
# === METHODS ===
|
|
46
|
-
def draw(self, win, cam=None):
|
|
47
|
-
"""Draw sprite on a CrystalWindow or Tkinter canvas"""
|
|
48
|
-
if cam:
|
|
49
|
-
draw_x, draw_y = cam.apply(self)
|
|
50
|
-
else:
|
|
51
|
-
draw_x, draw_y = self.x, self.y
|
|
52
|
-
|
|
53
|
-
if self.image:
|
|
54
|
-
win.canvas.create_image(draw_x, draw_y, anchor="nw", image=self.image)
|
|
55
|
-
else:
|
|
56
|
-
win.draw_rect(self.color, (draw_x, draw_y, self.width, self.height))
|
|
57
|
-
|
|
58
|
-
def move(self, dx, dy):
|
|
59
|
-
"""Move sprite manually by dx/dy"""
|
|
60
|
-
self.x += dx
|
|
61
|
-
self.y += dy
|
|
62
|
-
self.pos = (self.x, self.y)
|
|
63
|
-
|
|
64
|
-
def apply_velocity(self, dt=1):
|
|
65
|
-
"""Apply vel_x/vel_y to x/y for physics"""
|
|
66
|
-
self.x += self.vel_x * dt
|
|
67
|
-
self.y += self.vel_y * dt
|
|
68
|
-
self.pos = (self.x, self.y)
|
|
69
|
-
|
|
70
|
-
# === COLLISION ===
|
|
71
|
-
def colliderect(self, other):
|
|
72
|
-
"""Check if self collides with another sprite"""
|
|
73
|
-
return (
|
|
74
|
-
self.x < other.x + getattr(other, "width", 0) and
|
|
75
|
-
self.x + getattr(self, "width", 0) > other.x and
|
|
76
|
-
self.y < other.y + getattr(other, "height", 0) and
|
|
77
|
-
self.y + getattr(self, "height", 0) > other.y
|
|
78
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|