skyport-engine 0.1.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. skyport_engine-0.1.5/PKG-INFO +6 -0
  2. skyport_engine-0.1.5/setup.cfg +4 -0
  3. skyport_engine-0.1.5/setup.py +20 -0
  4. skyport_engine-0.1.5/skyport/__init__.py +127 -0
  5. skyport_engine-0.1.5/skyport/assets/images/None.png +0 -0
  6. skyport_engine-0.1.5/skyport/assets/images/buttons/how_to_play.png +0 -0
  7. skyport_engine-0.1.5/skyport/assets/images/buttons/menue.png +0 -0
  8. skyport_engine-0.1.5/skyport/assets/images/buttons/play.png +0 -0
  9. skyport_engine-0.1.5/skyport/assets/images/buttons/quit.png +0 -0
  10. skyport_engine-0.1.5/skyport/assets/images/error.png +0 -0
  11. skyport_engine-0.1.5/skyport/assets/images/pt-17.png +0 -0
  12. skyport_engine-0.1.5/skyport/assets/layar_manager.py +249 -0
  13. skyport_engine-0.1.5/skyport/assets/loader/game_file_maps/engine_assets.json +10 -0
  14. skyport_engine-0.1.5/skyport/assets/loader/sound_maps/engine_sounds.json +6 -0
  15. skyport_engine-0.1.5/skyport/assets/loader/texture_maps/engine_textures.json +30 -0
  16. skyport_engine-0.1.5/skyport/assets/sounds/error.mp3 +0 -0
  17. skyport_engine-0.1.5/skyport/assets/sprites/test1.sprite/settings.json +5 -0
  18. skyport_engine-0.1.5/skyport/core/paths.py +57 -0
  19. skyport_engine-0.1.5/skyport/engine_setup.py +4 -0
  20. skyport_engine-0.1.5/skyport/gf_map_cunstructor.py +51 -0
  21. skyport_engine-0.1.5/skyport/global_utils.py +415 -0
  22. skyport_engine-0.1.5/skyport/logs/engine_logs.json +31 -0
  23. skyport_engine-0.1.5/skyport/rendering_eng.py +129 -0
  24. skyport_engine-0.1.5/skyport/skyport.py +9 -0
  25. skyport_engine-0.1.5/skyport_engine.egg-info/PKG-INFO +6 -0
  26. skyport_engine-0.1.5/skyport_engine.egg-info/SOURCES.txt +27 -0
  27. skyport_engine-0.1.5/skyport_engine.egg-info/dependency_links.txt +1 -0
  28. skyport_engine-0.1.5/skyport_engine.egg-info/requires.txt +2 -0
  29. skyport_engine-0.1.5/skyport_engine.egg-info/top_level.txt +1 -0
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: skyport_engine
3
+ Version: 0.1.5
4
+ Requires-Dist: pygame-ce>=2.5.5
5
+ Requires-Dist: numpy>=2.3.2
6
+ Dynamic: requires-dist
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,20 @@
1
+
2
+ from setuptools import setup, find_packages
3
+
4
+ setup(
5
+ name="skyport_engine",
6
+ # version format: major version . minor version . patch version
7
+ version="0.1.5",
8
+ include_package_data=True,
9
+ package_data={"skyport": ["*.json", "**/*.json", "*.png", "**/*.png", "*.mp3", "**/*.mp3"]},
10
+ install_requires=[
11
+ 'pygame-ce>=2.5.5',
12
+ 'numpy>=2.3.2'
13
+ ]
14
+ )
15
+ #C:\Users\matth\OneDrive\Desktop\skyport
16
+ #C:\Users\matth\OneDrive\Desktop\skyport\dist\skyport-0.1.0-py3-none-any.whl
17
+
18
+ #compile with:
19
+ # cd "C:\Users\matth\OneDrive\Desktop\skyport" && python setup.py sdist bdist_wheel
20
+ #pip install dist\skyport_engine-0.1.5-py3-none-any.whl
@@ -0,0 +1,127 @@
1
+ """
2
+ made by : Matthew R and William L
3
+
4
+ ////////////////////////////
5
+ -----welcome to skyport-----
6
+ ////////////////////////////
7
+
8
+ the purpos of skyport is to:
9
+ provide a simpler way to make a 2d game with pygame without having to learn how to use pygame itself.
10
+
11
+ engine classes:
12
+ - Display_manager: main display manager class
13
+ - Delta_timer: delta time couculator
14
+ - Util: utility functions
15
+ - Layar_manager: manager for multiple layers (cameras)
16
+ - Camera: layer (camera) class
17
+ - r_obj: renderable object class
18
+ - Loader: asset loader class
19
+ - loger: logging utility
20
+ - Sprite: animated texture class
21
+
22
+ important info:
23
+ -when making chunk genorator funcions make shure that it
24
+ takes in at least 1 peramiter for the chunk obj it will be called in
25
+ and the same gose for chunk update funcions.
26
+ """
27
+
28
+ import os
29
+ import sys
30
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
31
+ if BASE_DIR not in sys.path:
32
+ sys.path.insert(0, BASE_DIR)
33
+
34
+ from rendering_eng import *
35
+ from global_utils import *
36
+ from assets.layar_manager import *
37
+
38
+
39
+
40
+ # example usage:
41
+ """
42
+ import random
43
+ import time
44
+ #import skyport as sp
45
+
46
+ # 1. Setup Display (Using your scaling logic: 500x500 window -> 1500x750 internal)
47
+ dm = sp.Display_manager((500, 500), (1500, 750), False)
48
+ loader = sp.Loader(None, "idk_tm.json")
49
+ sp.r_obj.loader = loader
50
+
51
+ # 2. Define a "Chunk Generator" that draws a grid background
52
+ def chunk_script(sself):
53
+ sself.bg_image = sp.pygame.Surface((sself.size, sself.size))
54
+ sself.bg_image.fill((30, 30, 30))
55
+ # Draw a grid border so we can see the chunks move
56
+ sp.pygame.draw.rect(sself.bg_image, (50, 50, 50), (0, 0, sself.size, sself.size), 2)
57
+ def update_gen(sself):
58
+ sself.surf.blit(sself.bg_image, (0, 0))
59
+ sself.update_gen_script = update_gen
60
+
61
+
62
+ # 3. Create the Layer (Camera)
63
+ # World size: 5000x5000, Chunk size: 250
64
+ layar = sp.Camera(dm.display, 250, (5000, 5000), (10, 10, 10), 0, chunk_genorator_func=chunk_script)
65
+ dm.get_lm().add_layar(layar)
66
+
67
+ # 4. Stress Test Variables
68
+ objects = []
69
+ spawn_rate = 10 # How many objects to add per frame
70
+ max_objects = 2000
71
+
72
+ def spawn_stress_objs(count):
73
+ for _ in range(count):
74
+ # Random position within the 5000x5000 world
75
+ rx = random.randint(0, 4900)
76
+ ry = random.randint(0, 4900)
77
+ # Random size and rotation speed
78
+ obj = sp.r_obj(rx, ry, 40, 40, random.randint(0, 360), 0, "asd.jeff")
79
+ obj.rot_speed = random.uniform(-5, 5)
80
+ dm.get_lm().add_obj(obj, 0)
81
+ objects.append(obj)
82
+
83
+ # 5. Start the engine
84
+ dm.START_RENDERING_THREAD(60) # Capped at 60 for stability, or 0 for unlimited
85
+
86
+ print("--- SKYPORT ENGINE BENCHMARK STARTING ---")
87
+ print("Controls: Arrows to Move, I/K to Zoom, SPACE to spawn 100 more")
88
+
89
+ try:
90
+ while dm.running:
91
+ time.sleep(0.01) # Low sleep to keep input responsive
92
+
93
+ # Benchmarking Stats
94
+ fps = dm.clock.get_fps()
95
+ obj_count = len(objects)
96
+ print(f"FPS: {fps:.2f} | Objects: {obj_count} | Cam: ({layar.x}, {layar.y})", end="\r")
97
+
98
+ # Automatic Spawning until we hit max
99
+ if obj_count < max_objects and fps > 30:
100
+ spawn_stress_objs(spawn_rate)
101
+
102
+ # Update Object Logic (Rotating them to stress the transform.rotate calls)
103
+ for o in objects:
104
+ o.angle += o.rot_speed
105
+
106
+ # Input Handling
107
+ keys = sp.pygame.key.get_pressed()
108
+ if keys[sp.pygame.K_LEFT]: layar.x -= 10
109
+ if keys[sp.pygame.K_RIGHT]: layar.x += 10
110
+ if keys[sp.pygame.K_UP]: layar.y -= 10
111
+ if keys[sp.pygame.K_DOWN]: layar.y += 10
112
+ if keys[sp.pygame.K_i]: layar.set_zoom(layar.zoom + 0.05)
113
+ if keys[sp.pygame.K_k]: layar.set_zoom(layar.zoom - 0.05)
114
+ if keys[sp.pygame.K_SPACE]: spawn_stress_objs(100)
115
+
116
+ dm.event()
117
+
118
+ except Exception as e:
119
+ # Your "Loving Feature" should catch this!
120
+ print(f"\nBenchmark stopped: {e}")
121
+
122
+ finally:
123
+ dm.STOP_RENDERING_THREAD()
124
+ print(f"\nFinal Score: Handled {len(objects)} objects at {dm.clock.get_fps():.2f} FPS")
125
+
126
+
127
+ """
@@ -0,0 +1,249 @@
1
+ import pygame
2
+ import math
3
+ from rendering_eng import pygame
4
+
5
+ # engine imports
6
+ from skyport.core.paths import PathUtil as pu
7
+ from skyport.core.paths import loger
8
+ from global_utils import *
9
+
10
+ class Camera:
11
+ instances = 0
12
+ def __init__(self, display_surface, chunk_size,world_size,bg_fill_color=None,pryoraty=None,chunk_genorator_func=None):
13
+ self.tiles = {}
14
+ self.all_game_objs = []
15
+ self._qued_game_objs = []
16
+ self.display_surface = display_surface
17
+ self.chunk_size = chunk_size
18
+ self.offset_x = 0
19
+ self.offset_y = 0
20
+ self.x,self.y = 0,0
21
+ self.zoom = 1.0
22
+ self.old_zoom = self.zoom
23
+ self.WORLD_HIGHT = world_size[0]
24
+ self.WORLD_WIDTH = world_size[1]
25
+ self.CHUNKS_ON_X = self.WORLD_WIDTH // self.chunk_size
26
+ self.CHUNKS_ON_Y = self.WORLD_HIGHT // self.chunk_size
27
+ self.print_queue = ""
28
+ self.genorator = chunk_genorator_func
29
+ Camera.instances += 1
30
+ self.pryoraty = util.pryoraty(pryoraty,Camera.instances)
31
+ self.bg_fill_color = bg_fill_color
32
+ self.obj_render_surf = pygame.Surface(display_surface.get_size(),flags=pygame.SRCALPHA)
33
+ loger.log(f"Initialized camera with pryoraty of {self.pryoraty} and {Camera.instances} instances")
34
+
35
+ def render_offset_objs(self,disp=None):
36
+ sw, sh = self.display_surface.get_size() # sw and sh stand for screen width and screen height
37
+ for obj in self.all_game_objs: # r_objs need a .x ,.y .og_x .og_y ,.get_surf
38
+ screen_x = obj.x * self.zoom + self.offset_x
39
+ screen_y = obj.y * self.zoom + self.offset_y
40
+ self.display_surface.blit(obj.get_surf(self.zoom),(screen_x,screen_y))
41
+
42
+ def chunkify(self,obj):
43
+ c_pos = self.get_chunk_cords(obj.x,obj.y)
44
+ chunk = self.get_chunk(c_pos[0], c_pos[1])
45
+ chunk.all_objs.append(obj)
46
+ #self._qued_game_objs.append(obj)
47
+ #if obj not in chunk.all_objs:
48
+ # chunk.all_objs.append(obj)
49
+ # #print(f"{prin_GREEN}Added obj {obj.id} to chunk {c_pos}{prin_RESET}")
50
+ #else:
51
+ # self._qued_game_objs.remove(obj)
52
+
53
+ def re_chunk(self,all_objs,obj):
54
+ all_objs.remove(obj)
55
+ self.chunkify(obj)
56
+
57
+ def get_chunk_cords(self,x,y):
58
+ cx = int(x) // self.chunk_size
59
+ cy = int(y) // self.chunk_size
60
+ return (cx,cy)
61
+
62
+ def get_chunk(self,cx, cy):
63
+ #return chunk at (cx, cy), create if it doesnt exist yet
64
+ if (cx, cy) not in self.tiles:
65
+ self.tiles[(cx, cy)] = Chunk(cx, cy, self.chunk_size,genorator=self.genorator,bg_fill_color=self.bg_fill_color,zoom=self.zoom,cam=self)
66
+ Util.print(f"{prin_GREEN}Created chunk {cx},{cy}{prin_RESET}")
67
+ return self.tiles[(cx, cy)]
68
+
69
+ def tick_ops(self):
70
+ if self.print_queue != "":
71
+ Util.print(self.print_queue)
72
+ self.print_queue = ""
73
+
74
+ def set_zoom(self, level):
75
+ self.zoom = max(0.1, level)
76
+
77
+ def get_min_max_c_pos(self,z,W,H):
78
+ world_left = -self.offset_x / z
79
+ world_top = -self.offset_y / z
80
+ world_right = world_left + W / z
81
+ world_bottom = world_top + H / z
82
+
83
+ min_cx = max(0, int(math.floor(world_left / self.chunk_size)))
84
+ max_cx = min(self.CHUNKS_ON_X - 1, int(math.floor(world_right / self.chunk_size)))
85
+ min_cy = max(0, int(math.floor(world_top / self.chunk_size)))
86
+ max_cy = min(self.CHUNKS_ON_Y - 1, int(math.floor(world_bottom / self.chunk_size)))
87
+ return min_cx,min_cy,max_cx,max_cy
88
+
89
+ def render(self, target_x, target_y):
90
+ W, H = self.display_surface.get_size()
91
+ z = self.zoom
92
+ self.obj_render_surf.fill((0,0,0,0))
93
+ self.offset_x = -target_x * z + W // 2
94
+ self.offset_y = -target_y * z + H // 2
95
+
96
+ min_cx,min_cy,max_cx,max_cy = self.get_min_max_c_pos(z,W,H)
97
+
98
+ for cx in range(min_cx, max_cx + 1):
99
+ for cy in range(min_cy, max_cy + 1):
100
+ chunk = self.get_chunk(cx, cy)
101
+ screen_x = cx * self.chunk_size * z + self.offset_x
102
+ screen_y = cy * self.chunk_size * z + self.offset_y
103
+ surf = chunk.scaled_surface(z)
104
+ self.display_surface.blit(surf, (screen_x, screen_y))
105
+ chunk.update(self.zoom,self,screen_x,screen_y)
106
+ self.display_surface.blit(self.obj_render_surf,(0,0))
107
+ self.tick_ops()
108
+
109
+ def get_surf(self):
110
+ return self.display_surface
111
+
112
+ def remove_chunk_obj(self,obj):
113
+ obj_chunk = self.get_chunk_cords(obj.x,obj.y)
114
+ for y in range(-1,1):
115
+ for x in range(-1,1):
116
+ chunk = self.get_chunk(obj_chunk[0]+x,obj_chunk[1]+y)
117
+ if obj in chunk.all_objs:
118
+ chunk.all_objs.remove(obj)
119
+
120
+ class Chunk:
121
+ instances = 0
122
+ def __init__(self, cx, cy, chunk_size ,bg_fill_color=None,genorator=None,zoom=0,cam=None):
123
+ self.cx = cx
124
+ self.cy = cy
125
+ self.size = chunk_size
126
+ self.surf = pygame.Surface((chunk_size, chunk_size), flags=pygame.SRCALPHA)
127
+ self.surf.fill((0, 0, 0))
128
+ self._scaled = None
129
+ self._last_zoom = None
130
+ self.tags = {}
131
+ self.all_objs = []
132
+ self.bg_surf = None
133
+ self.update_gen_script = None
134
+ self.generate_terrain(genorator)
135
+ self.bg_fill_color = bg_fill_color
136
+ #self.update(zoom,cam,)
137
+ if self.bg_fill_color != None:
138
+ self.surf.fill(self.bg_fill_color)
139
+ if self.update_gen_script != None:
140
+ self.update_gen_script(self)
141
+ self.scaled_surface(zoom)
142
+ Chunk.instances += 1
143
+ loger.log(f"Initialized chunk at {cx},{cy} with a total of {Chunk.instances} created")
144
+
145
+ def scale__(self,zoom):
146
+ w = max(1, int(self.size * zoom))
147
+ h = max(1, int(self.size * zoom))
148
+ self._scaled = pygame.transform.scale(self.surf, (w, h))
149
+ self._last_zoom = zoom
150
+
151
+ def scaled_surface(self, zoom):
152
+ if self._last_zoom != zoom or self._scaled is None:
153
+ self.scale__(zoom)
154
+ return self._scaled
155
+
156
+ def generate_terrain(self,genorator=None):
157
+ if genorator != None:
158
+ genorator(self)
159
+
160
+ def blit_objs_v2(self,zoom,cam,chunk_screen_x,chunk_screen_y):
161
+ for obj in self.all_objs: # requierd atributes of rendering obj is .get_surf, .x ,.og_x , .y ,.og_y
162
+ surf = obj.get_surf(zoom)
163
+ obj.rect.x = obj.x * zoom + cam.offset_x
164
+ obj.rect.y = obj.y * zoom + cam.offset_y
165
+ screen_x,screen_y = obj.rect.centerx - surf.get_width()//2, obj.rect.centery - surf.get_height()//2
166
+ cam.obj_render_surf.blit(surf,(screen_x,screen_y)) # i was working on centerd rotations -----------------------------------------------
167
+
168
+ if abs(obj.x - obj.og_x) >= self.size or abs(obj.y - obj.og_y) >= self.size: # rechunking
169
+ cam.print_queue += f"obj {obj.id} is at {obj.x},{obj.y} and beeing rechunked\n"
170
+ obj.og_x,obj.og_y = obj.x,obj.y
171
+ cam.re_chunk(self.all_objs,obj)
172
+
173
+ def update(self,zoom,cam,screen_x,screen_y):
174
+ if self.bg_fill_color != None:
175
+ self.surf.fill(self.bg_fill_color)
176
+ if self.update_gen_script != None:
177
+ self.update_gen_script(self)
178
+ self.blit_objs_v2(zoom,cam,screen_x,screen_y)
179
+ #self.scale__(zoom)
180
+
181
+ class Layar_manager:
182
+ def __init__(self,surf):
183
+ self.surf = surf
184
+ self.layars = []
185
+ self.stashed_layars = []
186
+ loger.log("Initialized layar manager")
187
+
188
+ def render(self):
189
+ for l in self.layars:
190
+ l.render(l.x,l.y)
191
+ self.surf.blit(l.get_surf(),(0,0))
192
+ return self.surf
193
+
194
+ def get_surf(self):
195
+ return self.surf
196
+
197
+ def sort(self):
198
+ self.layars = util.sort_objects_by_attr(self.layars,"pryoraty")
199
+
200
+ def add_layar(self,layar):
201
+ self.layars.append(layar)
202
+ self.sort()
203
+ def del_layar(self,pryoraty):
204
+ if pryoraty in self.layars:
205
+ self.layars.pop(pryoraty)
206
+ return True
207
+ return False
208
+ def remove_layar(self,pryoraty):
209
+ if pryoraty in self.layars:
210
+ self.stashed_layars.append(self.layars[pryoraty])
211
+ return True
212
+ print(f"layar {pryoraty} duse not exsis")
213
+ return False
214
+
215
+ def get_layar(self,pryoraty):
216
+ return self.layars[pryoraty]
217
+
218
+
219
+ def get_layar_objs(self,layar):
220
+ offset_objs = layar.all_game_objs
221
+ chunk_objs = {}
222
+ for pos in layar.tiles.key():
223
+ chunk = layar.tiles[pos]
224
+ c_obj = chunk.all_objs
225
+ chunk_objs[pos] = c_obj
226
+ return chunk_objs,offset_objs
227
+
228
+ def set_layar_objs(self,chunk_objs,offset_objs,layar):
229
+ layar.all_game_objs + offset_objs
230
+ for pos in layar.tiles.key():
231
+ chunk = layar.tiles[pos]
232
+ chunk.all_objs + chunk_objs[pos]
233
+ return layar
234
+
235
+ def add_obj(self,obj,layar_pryoraty):
236
+ layar = self.get_layar(layar_pryoraty)
237
+ if obj.render_type == "chunk" or obj.render_type == "CHUNK":
238
+ layar.chunkify(obj)
239
+ else:
240
+ layar.all_game_objs.append(obj)
241
+ def remove_obj(self,obj,layar_pryoraty):
242
+ layar = self.get_layar(layar_pryoraty)
243
+ if obj.render_type == "chunk" or obj.render_type == "CHUNK":
244
+ layar.remove_chunk_obj(obj)
245
+ else:
246
+ if obj in layar.all_game_objs:
247
+ layar.all_game_objs.remove(obj)
248
+
249
+
@@ -0,0 +1,10 @@
1
+ {
2
+ "assets/loader/game_file_maps/engine_assets.json": {
3
+ "type": "d",
4
+ "value": null
5
+ },
6
+ "assets/loader/texture_maps/engine_textures.json": {
7
+ "type": "d",
8
+ "value": null
9
+ }
10
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "assets/sounds/error.mp3": {
3
+ "type": "d",
4
+ "value": null
5
+ }
6
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "assets/images/error.png": {
3
+ "type": "d",
4
+ "value": null
5
+ },
6
+ "assets/images/None.png": {
7
+ "type": "d",
8
+ "value": null
9
+ },
10
+ "assets/images/pt-17.png": {
11
+ "type": "d",
12
+ "value": null
13
+ },
14
+ "assets/images/buttons/how_to_play.png": {
15
+ "type": "d",
16
+ "value": null
17
+ },
18
+ "assets/images/buttons/menue.png": {
19
+ "type": "d",
20
+ "value": null
21
+ },
22
+ "assets/images/buttons/play.png": {
23
+ "type": "d",
24
+ "value": null
25
+ },
26
+ "assets/images/buttons/quit.png": {
27
+ "type": "d",
28
+ "value": null
29
+ }
30
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "fps": 1,
3
+ "total_frames": 3,
4
+ "img_dt": ".png"
5
+ }
@@ -0,0 +1,57 @@
1
+
2
+ import datetime
3
+ import os
4
+ import json
5
+ from pathlib import Path
6
+
7
+ ENGINE_ROOT = Path(__file__).resolve().parent.parent
8
+
9
+ class PathUtil:
10
+ @staticmethod
11
+ def fp(relative_path: str) -> Path:
12
+ p = Path(relative_path)
13
+ if p.is_absolute():
14
+ return p
15
+ return (ENGINE_ROOT / p).resolve()
16
+
17
+ class ENG_Loger:
18
+ ENGINE_LOG_PATH = PathUtil.fp("logs/engine_logs.json")
19
+ if not os.path.exists(ENGINE_LOG_PATH):
20
+ with open(ENGINE_LOG_PATH,"w") as f:
21
+ json.dump({"total_logs": 5,"record_engine_logs": True,"logs": []},indent=4)
22
+ with open(ENGINE_LOG_PATH,"r") as f:
23
+ log_file = json.load(f)
24
+ take_logs = log_file["record_engine_logs"]
25
+ log_data_retaintion_amount = 5
26
+ print(f"--engine logging is set to {take_logs}--")
27
+ def __init__(self):
28
+ self.log_start_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
29
+ self.run_time_log = ""
30
+ if ENG_Loger.take_logs:
31
+ self.log = self._true_log
32
+ else:
33
+ self.log = self._false_log
34
+
35
+ def save(self):
36
+ ENG_Loger.log_file["logs"].append({
37
+ "log_start_time":self.log_start_time,
38
+ "log_end_time":datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
39
+ "run_time_log":self.run_time_log
40
+ })
41
+ if len(ENG_Loger.log_file["logs"]) > ENG_Loger.log_data_retaintion_amount:
42
+ ENG_Loger.log_file["logs"].pop(0)
43
+ ENG_Loger.log_file["total_logs"] = ENG_Loger.log_data_retaintion_amount
44
+ with open(ENG_Loger.ENGINE_LOG_PATH,"w") as f:
45
+ json.dump(ENG_Loger.log_file,f,indent=4)
46
+ def print(self):
47
+ for log in ENG_Loger.log_file["logs"]:
48
+ for line in log["run_time_log"].split("\n"):
49
+ print(line)
50
+ print("----- end of log")
51
+
52
+ def _true_log(self,message):
53
+ self.run_time_log += f"[{datetime.datetime.now().strftime('%H:%M:%S')}] :-: {message}\n"
54
+ def _false_log(self,message):
55
+ pass
56
+
57
+ loger = ENG_Loger()
@@ -0,0 +1,51 @@
1
+ import os
2
+ import json
3
+
4
+ def main():
5
+ base_dir = input("enter the file dir : ").strip()
6
+ base_dir = os.path.abspath(base_dir)
7
+
8
+ count = int(input("how meny file formats to use : "))
9
+ extensions = []
10
+
11
+ for i in range(count):
12
+ ext = input("file type : ").strip().lower()
13
+ if not ext.startswith("."):
14
+ ext = "." + ext
15
+ extensions.append(ext)
16
+
17
+ print(f"\nScanning directory: {base_dir}")
18
+ print(f"Including file types: {extensions}\n")
19
+
20
+ manifest = {}
21
+
22
+ for root, _, files in os.walk(base_dir):
23
+ for file in files:
24
+ if any(file.lower().endswith(ext) for ext in extensions):
25
+ full_path = os.path.join(root, file)
26
+ rel_path = os.path.relpath(full_path, base_dir)
27
+ rel_path = rel_path.replace("\\", "/") # engine-safe
28
+
29
+ manifest[rel_path] = {
30
+ "type": "d",
31
+ "value": None
32
+ }
33
+
34
+ print("--- GENERATED ASSET MANIFEST (JSON) ---")
35
+ print(json.dumps(manifest, indent=4))
36
+ """
37
+ save = input("\nSave to file? (y/n): ").lower()
38
+ if save == "y":
39
+ out_name = input("Output file name (ex: assets.json): ").strip()
40
+ with open(out_name, "w", encoding="utf-8") as f:
41
+ json.dump(manifest, f, indent=4)
42
+ print(f"Saved to {out_name}")
43
+ """
44
+
45
+ #input("\npress any key to exit:")
46
+ def gen_map():
47
+ main()
48
+
49
+ if __name__ == "__main__":
50
+ main()
51
+ confirm = input("Press Enter to exit...")
@@ -0,0 +1,415 @@
1
+
2
+ import numpy as np
3
+ #import pygame
4
+ import math
5
+ import time
6
+ import json
7
+ import os
8
+ from skyport.core.paths import PathUtil as pu
9
+ from skyport.core.paths import loger
10
+ from rendering_eng import pygame
11
+
12
+ class Util:
13
+ instanses = 0
14
+ print_que = ""
15
+ def __init__(self):
16
+ Util.instanses += 1
17
+ #print(Util.instanses)
18
+ #self.ROOT_PATH = Path(__file__).resolve().parent.parent
19
+ if Util.instanses <= 3:
20
+ self.fp = self.e_fp
21
+ else:
22
+ self.fp = self.m_fp
23
+ loger.log(f"Util instans {Util.instanses} inisalized")
24
+ self.tags = {}
25
+
26
+
27
+ def output_print_data():
28
+ print(f"{Util.print_que}__")
29
+ Util.print_que = ""
30
+ def print(string):
31
+ Util.print_que += string+"\n"
32
+
33
+ def m_fp(self, relative_fp):
34
+ return relative_fp
35
+ def e_fp(self, relative_fp):
36
+ return pu.fp(relative_fp)
37
+
38
+ def get_angle_and_dist(self,x1,y1,x,y):
39
+ dx = x1 - x
40
+ dy = y1 - y
41
+ dist = math.hypot(dx, dy)
42
+ angle = (math.degrees(math.atan2(dy, dx)) + 180) % 360
43
+ return angle,dist
44
+
45
+ def color_swap(self,surface: pygame.Surface, old_color: tuple, new_color: tuple) -> pygame.Surface:
46
+ arr_rgb = pygame.surfarray.array3d(surface)
47
+ arr_alpha = pygame.surfarray.array_alpha(surface)
48
+ mask = np.all(arr_rgb == old_color, axis=-1)
49
+ arr_rgb[mask] = new_color
50
+ new_surface = pygame.Surface(surface.get_size(), pygame.SRCALPHA, 32)
51
+ new_surface = new_surface.convert_alpha()
52
+ pygame.surfarray.blit_array(new_surface, arr_rgb)
53
+ pygame.surfarray.pixels_alpha(new_surface)[:] = arr_alpha
54
+ return new_surface
55
+
56
+ def pryoraty(self,a=None,b=None):
57
+ if a != None:
58
+ return a
59
+ else:
60
+ return b
61
+
62
+ def sort_objects_by_attr(self,obj_list : list, attr_name : str, reverse=False):
63
+ return sorted(obj_list, key=lambda x: getattr(x, attr_name), reverse=reverse)
64
+
65
+ class Loader:
66
+ loader_instanses = 0
67
+ lutil = Util()
68
+ error_img=pygame.image.load(lutil.fp("assets/images/error.png")).convert_alpha()
69
+ error_sound=pygame.mixer.Sound(lutil.fp("assets/sounds/error.mp3"))
70
+ def __init__(self,texture_map_path=None,GF_map_path=None,sound_map_path=None,loader_name=None,error_img=None,error_sound=None):
71
+ self.lutil = Util()
72
+ self.texture_map = {}
73
+ self.file_map = {}
74
+ self.sound_map = {}
75
+ if texture_map_path != None:
76
+ self.load_texture_map(texture_map_path)
77
+ if GF_map_path != None:
78
+ self.load_file_map(GF_map_path)
79
+ if sound_map_path != None:
80
+ self.load_sound_map(sound_map_path)
81
+ # loader naming for debuging
82
+ self.error_assets = {"img":self.lutil.pryoraty(error_img,Loader.error_img),"sound":self.lutil.pryoraty(error_sound,Loader.error_sound)}
83
+ Loader.loader_instanses += 1
84
+ self.loader_name = util.pryoraty(loader_name,str(Loader.loader_instanses))
85
+ print(f"{prin_BLUE}++| inisalized Loader instans '{self.loader_name}' |++{prin_RESET}")
86
+ loger.log(f"Loader instans '{self.loader_name}' inisalized with {Loader.loader_instanses} loader_instanses")
87
+
88
+ def _error(self,Type,error,path):
89
+ error_msg = f"{prin_RED}!!-error loading {Type} : {path} ->> in loader {self.loader_name} with error >> {error} -!!{prin_RESET}"
90
+ loger.log(error_msg)
91
+ print(error_msg)
92
+
93
+ def _loade_img_catagory(self,val):
94
+ paths = val["value"]
95
+ images = []
96
+ for path in paths:
97
+ images.append(pygame.image.load(self.lutil.fp(path)).convert_alpha())
98
+ val["value"] = images
99
+ return val
100
+ def init_comon_textures(self,texture_map):
101
+ all_keys = texture_map.keys()
102
+ TM = texture_map
103
+ for key in all_keys:
104
+ val = TM[key]
105
+ Type = val["type"].lower()
106
+ if Type == "d" or Type == "defalt":
107
+ val["value"] = pygame.image.load(self.lutil.fp(key)).convert_alpha()
108
+ TM[key] = val
109
+ elif Type == "r" or Type == "replace":
110
+ val["value"] = pygame.image.load(val["value"]).convert_alpha()
111
+ TM[key] = val
112
+ elif Type == "c" or Type == "catagory":
113
+ val = self._loade_img_catagory(self.lutil.fp(val))
114
+ else:
115
+ val["value"] = pygame.image.load(self.lutil.fp(key)).convert_alpha()
116
+ TM[key] = val
117
+ return TM
118
+ def load_texture_map(self,map_path):
119
+ map_path = self.lutil.fp(map_path)
120
+ with open(map_path,"r") as file:
121
+ texture_map = json.load(file)
122
+ self.texture_map = self.init_comon_textures(texture_map)
123
+
124
+ def _loade_file_catagory(self,val):
125
+ paths = val["value"]
126
+ files = []
127
+ for path in paths:
128
+ with open(self.lutil.fp(path),"r") as file:
129
+ files.append(json.load(file))
130
+ val["value"] = files
131
+ return val
132
+ def init_game_files(self,file_map):
133
+ all_keys = file_map.keys()
134
+ TM = file_map
135
+ for key in all_keys:
136
+ val = TM[key]
137
+ Type = val["type"].lower()
138
+ if Type == "d" or Type == "defalt":
139
+ with open(self.lutil.fp(key),"r") as file:
140
+ val["value"] = json.load(file)
141
+ TM[key] = val
142
+ elif Type == "r" or Type == "replace":
143
+ with open(self.lutil.fp(val["value"]),"r") as file:
144
+ val["value"] = json.load(file)
145
+ TM[key] = val
146
+ elif Type == "c" or Type == "catagory":
147
+ val = self._loade_file_catagory(val)
148
+ else:
149
+ with open(self.lutil.fp(key),"r") as file:
150
+ val["value"] = json.load(file)
151
+ TM[key] = val
152
+ return TM
153
+ def load_file_map(self,map_path):
154
+ map_path = self.lutil.fp(map_path)
155
+ with open(map_path,"r") as file:
156
+ file_map = json.load(file)
157
+ self.file_map = self.init_game_files(file_map)
158
+
159
+ def _loade_sound_catagory(self,val):
160
+ file_paths = val["value"]
161
+ sounds = []
162
+ for file_path in file_paths:
163
+ sounds.append(pygame.mixer.Sound(self.lutil.fp(file_path)))
164
+ val["value"] = sounds
165
+ return val
166
+ def init_sound_map(self,sound_map):
167
+ all_keys = sound_map.keys()
168
+ TM = sound_map
169
+ for key in all_keys:
170
+ val = TM[key]
171
+ Type = val["type"].lower()
172
+ if Type == "d" or Type == "defalt":
173
+ val["value"] = pygame.mixer.Sound(self.lutil.fp(key))
174
+ TM[key] = val
175
+ elif Type == "r" or Type == "replace":
176
+ val["value"] = pygame.mixer.Sound(self.lutil.fp(val["value"]))
177
+ TM[key] = val
178
+ elif Type == "c" or Type == "catagory":
179
+ val = self._loade_sound_catagory(val)
180
+ else:
181
+ val["value"] = pygame.mixer.Sound(self.lutil.fp(key))
182
+ TM[key] = val
183
+ return TM
184
+ def load_sound_map(self,map_path):
185
+ map_path = self.lutil.fp(map_path)
186
+ with open(map_path,"r") as file:
187
+ sound_map = json.load(file)
188
+ self.sound_map = self.init_sound_map(sound_map)
189
+
190
+ def image(self,path):
191
+ try:
192
+ return self.texture_map[path]["value"]
193
+ except KeyError:
194
+ try:
195
+ return pygame.image.load(self.lutil.fp(path)).convert_alpha()
196
+ except Exception as e:
197
+ self._error("image",e,path)
198
+ return self.error_assets["img"]
199
+ def data(self,file_path):
200
+ try:
201
+ return self.file_map[file_path]["value"]
202
+ except KeyError:
203
+ try:
204
+ with open(self.lutil.fp(file_path),"r") as file:
205
+ return json.load(file)
206
+ except Exception as e:
207
+ self._error("data",e,file_path)
208
+ return -1
209
+ def sound(self,file_path):
210
+ try:
211
+ return self.sound_map[file_path]["value"]
212
+ except KeyError:
213
+ try:
214
+ return pygame.mixer.Sound(self.lutil.fp(file_path))
215
+ except Exception as e:
216
+ self._error("sound",e,file_path)
217
+ return self.error_assets["sound"]
218
+
219
+ def warp_image(self,image,sizex,sizey,angle):
220
+ image1 = pygame.transform.scale(image,(sizex,sizey))
221
+ image2 = pygame.transform.rotate(image1,angle)
222
+ return image2
223
+ def rotate_image(self,image,angle):
224
+ image2 = pygame.transform.rotate(image,angle)
225
+ return image2
226
+ def scale_image(self,image,sizex,sizey):
227
+ image1 = pygame.transform.scale(image,(sizex,sizey))
228
+ return image1
229
+
230
+ def play_sound(self,file_path, volume=0.5,loops=0):
231
+ try:
232
+ sound = self.sound(file_path)
233
+ sound.set_volume(volume)
234
+ sound.play(loops)
235
+ return 1
236
+ except Exception as e:
237
+ print(f" error >> {e} from loader >> {self.loader_name} ")
238
+
239
+ prin_RED = '\033[91m'
240
+ prin_GREEN = '\033[92m'
241
+ prin_BLUE = '\033[94m'
242
+ prin_RESET = '\033[0m'
243
+ util = Util()
244
+ loader = Loader(
245
+ "assets/loader/texture_maps/engine_textures.json",
246
+ "assets/loader/game_file_maps/engine_assets.json",
247
+ "assets/loader/sound_maps/engine_sounds.json",
248
+ loader_name="engine_loader"
249
+ )
250
+ class Delta_timer:
251
+ def __init__(self):
252
+ # Using perf_counter for highest precision
253
+ self.prev_time = time.perf_counter()
254
+ self.dt = 0.0
255
+
256
+ def get_dt(self):
257
+ now = time.perf_counter()
258
+ self.dt = now - self.prev_time
259
+ self.prev_time = now
260
+ return self.dt
261
+
262
+ class Sprite:
263
+ instanses = 0
264
+ ld = loader
265
+ def __init__(self,file_path,game_fps):
266
+ self.dt = Delta_timer()
267
+ Sprite.instanses += 1
268
+ self.bace_path = file_path # bace path would be something like assets/sprites/test1.sptite
269
+ self.data = Sprite.ld.data(f"{self.bace_path}/settings.json")
270
+ self.game_fps = game_fps
271
+ self.fps = self.data["fps"]
272
+ self.total_frames = self.data["total_frames"]
273
+ self.img_dt = self.data["img_dt"]
274
+ self._imgs = []
275
+ self.scaled_imgs = []
276
+ self.elapsed_time = 0.0
277
+ self._last_zoom = None
278
+ self.init_imgs(file_path)
279
+
280
+ def get_frame_index(self, dt):
281
+ self.elapsed_time += dt
282
+ raw_frame = int(self.elapsed_time * self.fps)
283
+ index = raw_frame % self.total_frames
284
+ return index
285
+
286
+ def get_surf(self,zoom,angle):
287
+ if self._last_zoom != zoom:
288
+ self.scale_all(zoom)
289
+ ind = self.get_frame_index(self.dt.get_dt())
290
+ surf = self.scaled_imgs[ind]
291
+ surf = pygame.transform.rotate(surf,angle)
292
+
293
+ def scale_all(self,zoom):
294
+ surf = pygame.surface.Surface((10,10))
295
+ surf.get_size()
296
+ self.scaled_imgs.clear()
297
+ for i in self._imgs:
298
+ surf = i
299
+ surf_size = i.get_size()
300
+ surf_size[0] *= zoom
301
+ surf_size[1] *= zoom
302
+ surf = pygame.transform.scale(surf,surf_size)
303
+ self.scaled_imgs.append(surf)
304
+
305
+ def init_imgs(self,FP):
306
+ self._imgs = Sprite.ld.image(FP)
307
+
308
+ def manual_init_imgs(self,FP):
309
+ for i in range(self.total_frames):
310
+ fp = f"img_{i}{self.img_dt}"
311
+ full_fp = f"{self.bace_path}/images/{fp}"
312
+ self._imgs.append(Sprite.ld.image(full_fp))
313
+
314
+ class r_obj:
315
+ instanses = 0
316
+ loader = loader
317
+ def __init__(self,x,y,sx,sy,angle,zoom,texture_fp=None,hitbox_rect=None,render_type="chunk",children=[]):
318
+ self.obj_bound_to = children
319
+ self.tags = {}
320
+ r_obj.instanses += 1
321
+ self.id = r_obj.instanses
322
+ self.x,self.y,self.sx,self.sy = x,y,sx,sy
323
+ self.og_x,self.og_y = self.x,self.y
324
+ self.angle = angle
325
+ self.last_zoom = None
326
+ self.last_angle = None
327
+ self.texture_path = texture_fp
328
+ self.render_type = render_type
329
+
330
+ self.init_bound_objs_realative_cords()
331
+ self.init_render_type(texture_fp)
332
+ self.OG_IMAGE = self.get_df_img(texture_fp)
333
+ self.surf = self.get_surf(zoom)
334
+ self.rect = self.surf.get_rect()
335
+
336
+ if hitbox_rect != None:
337
+ self.hitbox_rect = hitbox_rect
338
+ else:
339
+ self.hitbox_rect = pygame.Rect(x,y,sx,sy)
340
+ loger.log(f"r_obj instans {self.id} inisalized at position ({self.x},{self.y}) with size ({self.sx},{self.sy})")
341
+
342
+ def init_render_type(self,fp):
343
+ if fp != None:
344
+ file_extension = os.path.splitext(fp)[1]
345
+ if file_extension == "sprite":
346
+ self.render_method = self.sprite_render
347
+ return
348
+ self.render_method = self.render
349
+ return
350
+ else:
351
+ self.render_method = self.render
352
+ return
353
+
354
+ def get_df_img(self,fp):
355
+ if fp == None:
356
+ return loader.image("assets/images/error.png")
357
+ return self.image(fp)
358
+
359
+ def image(self,fp):
360
+ return r_obj.loader.image(fp)
361
+ def file(self,fp):
362
+ return r_obj.loader.data(fp)
363
+
364
+ def get_img(self,zoom):
365
+ return self.OG_IMAGE
366
+ def get_scaled_img(self,zoom,angle):
367
+ return self.scaled_surf
368
+
369
+ def should_scale(self,zoom):
370
+ if self.last_zoom != zoom:
371
+ self.last_zoom = zoom
372
+ return True
373
+ return False
374
+
375
+ def should_rotate(self,angle):
376
+ if angle != self.last_angle:
377
+ self.last_angle = angle
378
+ return True
379
+ return False
380
+
381
+ def sprite_render(self,zoom):
382
+ img = self.OG_IMAGE.get_surf(zoom,self.angle)
383
+ return img
384
+
385
+ def render(self,zoom):
386
+ if self.should_scale(zoom):
387
+ self.scaled_surf = pygame.transform.scale(self.OG_IMAGE,(self.sx * zoom , self.sy * zoom))
388
+ self.surf = pygame.transform.rotate(self.scaled_surf,self.angle)
389
+ elif self.should_rotate(self.angle):
390
+ self.surf = pygame.transform.rotate(self.scaled_surf,self.angle)
391
+ return self.surf
392
+
393
+ def init_bound_objs_realative_cords(self):
394
+ for obj in self.obj_bound_to:
395
+ dx = self.x - obj.x
396
+ dy = self.y - obj.y
397
+ obj.tags["rel_dx"] = dx
398
+ obj.tags["rel_dy"] = dy
399
+ #print(f"{dx}---{dy}\n")
400
+ def update_bound_objs(self):
401
+ for obj in self.obj_bound_to:
402
+ x = self.x + obj.tags.get("rel_dx",0)
403
+ y = self.y + obj.tags.get("rel_dy",0)
404
+ obj.set_pos(x,y)
405
+ #print(f"updated bound obj {obj.id} to ({obj.x},{obj.y}) from parent obj {self.id} at ({self.x},{self.y})")
406
+
407
+ def get_surf(self,zoom):
408
+ return self.render_method(zoom)
409
+
410
+ def set_pos(self,x,y):
411
+ self.x = x
412
+ self.y = y
413
+ self.hitbox_rect.topleft = (self.x,self.y)
414
+ self.update_bound_objs()
415
+
@@ -0,0 +1,31 @@
1
+ {
2
+ "total_logs": 5,
3
+ "record_engine_logs": true,
4
+ "logs": [
5
+ {
6
+ "log_start_time": "2026-01-31 18:16:33",
7
+ "log_end_time": "2026-01-31 18:16:35",
8
+ "run_time_log": "[18:16:33] :-: Util instans 1 inisalized\n[18:16:33] :-: Util instans 2 inisalized\n[18:16:33] :-: Util instans 3 inisalized\n[18:16:34] :-: Loader instans 'engine_loader' inisalized with 1 loader_instanses\n[18:16:34] :-: Initialized layar manager\n[18:16:34] :-: Util instans 4 inisalized\n[18:16:34] :-: Display manager initialized\n[18:16:34] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:16:34] :-: r_obj instans 1 inisalized at position (300,250) with size (40,40)\n[18:16:34] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:16:34] :-: r_obj instans 2 inisalized at position (400,300) with size (40,40)\n[18:16:34] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:16:34] :-: r_obj instans 3 inisalized at position (240,150) with size (40,40)\n[18:16:34] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:16:34] :-: r_obj instans 4 inisalized at position (100,90) with size (40,40)\n[18:16:34] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:16:34] :-: r_obj instans 5 inisalized at position (200,200) with size (40,40)\n[18:16:34] :-: Initialized camera with pryoraty of 0 and 1 instances\n[18:16:34] :-: Initialized chunk at 0,0 with a total of 1 created\n[18:16:34] :-: Initialized chunk at 1,1 with a total of 2 created\n[18:16:34] :-: Initialized chunk at 0,1 with a total of 3 created\n[18:16:34] :-: Initialized chunk at 1,0 with a total of 4 created\n[18:16:34] :-: Initialized chunk at 2,0 with a total of 5 created\n[18:16:34] :-: Initialized chunk at 2,1 with a total of 6 created\n[18:16:34] :-: Initialized chunk at 3,0 with a total of 7 created\n[18:16:34] :-: Initialized chunk at 3,1 with a total of 8 created\n[18:16:35] :-: Rendering thread stopped\n[18:16:35] :-: Rendering thread stopped\n"
9
+ },
10
+ {
11
+ "log_start_time": "2026-01-31 18:17:02",
12
+ "log_end_time": "2026-01-31 18:17:08",
13
+ "run_time_log": "[18:17:02] :-: Util instans 1 inisalized\n[18:17:02] :-: Util instans 2 inisalized\n[18:17:02] :-: Util instans 3 inisalized\n[18:17:02] :-: Loader instans 'engine_loader' inisalized with 1 loader_instanses\n[18:17:02] :-: \u001b[91m!!-error loading image : asd.asd ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.asd'. -!!\u001b[0m\n[18:17:03] :-: Initialized layar manager\n[18:17:03] :-: Util instans 4 inisalized\n[18:17:03] :-: Display manager initialized\n[18:17:03] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:03] :-: r_obj instans 1 inisalized at position (300,250) with size (40,40)\n[18:17:03] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:03] :-: r_obj instans 2 inisalized at position (400,300) with size (40,40)\n[18:17:03] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:03] :-: r_obj instans 3 inisalized at position (240,150) with size (40,40)\n[18:17:03] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:03] :-: r_obj instans 4 inisalized at position (100,90) with size (40,40)\n[18:17:03] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:03] :-: r_obj instans 5 inisalized at position (200,200) with size (40,40)\n[18:17:03] :-: Initialized camera with pryoraty of 0 and 1 instances\n[18:17:03] :-: Initialized chunk at 0,0 with a total of 1 created\n[18:17:03] :-: Initialized chunk at 1,1 with a total of 2 created\n[18:17:03] :-: Initialized chunk at 0,1 with a total of 3 created\n[18:17:03] :-: Initialized chunk at 1,0 with a total of 4 created\n[18:17:03] :-: Initialized chunk at 2,0 with a total of 5 created\n[18:17:03] :-: Initialized chunk at 2,1 with a total of 6 created\n[18:17:03] :-: Initialized chunk at 3,0 with a total of 7 created\n[18:17:03] :-: Initialized chunk at 3,1 with a total of 8 created\n[18:17:06] :-: Initialized chunk at 1,-1 with a total of 9 created\n[18:17:08] :-: Initialized chunk at 2,-1 with a total of 10 created\n[18:17:08] :-: Rendering thread stopped\n"
14
+ },
15
+ {
16
+ "log_start_time": "2026-01-31 18:17:02",
17
+ "log_end_time": "2026-01-31 18:17:08",
18
+ "run_time_log": "[18:17:02] :-: Util instans 1 inisalized\n[18:17:02] :-: Util instans 2 inisalized\n[18:17:02] :-: Util instans 3 inisalized\n[18:17:02] :-: Loader instans 'engine_loader' inisalized with 1 loader_instanses\n[18:17:02] :-: \u001b[91m!!-error loading image : asd.asd ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.asd'. -!!\u001b[0m\n[18:17:03] :-: Initialized layar manager\n[18:17:03] :-: Util instans 4 inisalized\n[18:17:03] :-: Display manager initialized\n[18:17:03] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:03] :-: r_obj instans 1 inisalized at position (300,250) with size (40,40)\n[18:17:03] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:03] :-: r_obj instans 2 inisalized at position (400,300) with size (40,40)\n[18:17:03] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:03] :-: r_obj instans 3 inisalized at position (240,150) with size (40,40)\n[18:17:03] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:03] :-: r_obj instans 4 inisalized at position (100,90) with size (40,40)\n[18:17:03] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:03] :-: r_obj instans 5 inisalized at position (200,200) with size (40,40)\n[18:17:03] :-: Initialized camera with pryoraty of 0 and 1 instances\n[18:17:03] :-: Initialized chunk at 0,0 with a total of 1 created\n[18:17:03] :-: Initialized chunk at 1,1 with a total of 2 created\n[18:17:03] :-: Initialized chunk at 0,1 with a total of 3 created\n[18:17:03] :-: Initialized chunk at 1,0 with a total of 4 created\n[18:17:03] :-: Initialized chunk at 2,0 with a total of 5 created\n[18:17:03] :-: Initialized chunk at 2,1 with a total of 6 created\n[18:17:03] :-: Initialized chunk at 3,0 with a total of 7 created\n[18:17:03] :-: Initialized chunk at 3,1 with a total of 8 created\n[18:17:06] :-: Initialized chunk at 1,-1 with a total of 9 created\n[18:17:08] :-: Initialized chunk at 2,-1 with a total of 10 created\n[18:17:08] :-: Rendering thread stopped\n[18:17:08] :-: Rendering thread stopped\n"
19
+ },
20
+ {
21
+ "log_start_time": "2026-01-31 18:17:16",
22
+ "log_end_time": "2026-01-31 18:17:27",
23
+ "run_time_log": "[18:17:16] :-: Util instans 1 inisalized\n[18:17:16] :-: Util instans 2 inisalized\n[18:17:16] :-: Util instans 3 inisalized\n[18:17:16] :-: Loader instans 'engine_loader' inisalized with 1 loader_instanses\n[18:17:16] :-: \u001b[91m!!-error loading image : asd.asd ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.asd'. -!!\u001b[0m\n[18:17:16] :-: Initialized layar manager\n[18:17:16] :-: Util instans 4 inisalized\n[18:17:16] :-: Display manager initialized\n[18:17:16] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:16] :-: r_obj instans 1 inisalized at position (300,250) with size (40,40)\n[18:17:16] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:16] :-: r_obj instans 2 inisalized at position (400,300) with size (40,40)\n[18:17:16] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:16] :-: r_obj instans 3 inisalized at position (240,150) with size (40,40)\n[18:17:16] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:16] :-: r_obj instans 4 inisalized at position (100,90) with size (40,40)\n[18:17:16] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:16] :-: r_obj instans 5 inisalized at position (200,200) with size (40,40)\n[18:17:16] :-: Initialized camera with pryoraty of 0 and 1 instances\n[18:17:16] :-: Initialized chunk at 0,0 with a total of 1 created\n[18:17:16] :-: Initialized chunk at 1,1 with a total of 2 created\n[18:17:16] :-: Initialized chunk at 0,1 with a total of 3 created\n[18:17:16] :-: Initialized chunk at 1,0 with a total of 4 created\n[18:17:16] :-: Initialized chunk at 2,0 with a total of 5 created\n[18:17:16] :-: Initialized chunk at 2,1 with a total of 6 created\n[18:17:16] :-: Initialized chunk at 3,0 with a total of 7 created\n[18:17:16] :-: Initialized chunk at 3,1 with a total of 8 created\n[18:17:19] :-: Initialized chunk at 1,-1 with a total of 9 created\n[18:17:21] :-: Initialized chunk at 2,-1 with a total of 10 created\n[18:17:23] :-: Initialized chunk at 3,-1 with a total of 11 created\n[18:17:27] :-: Rendering thread stopped\n"
24
+ },
25
+ {
26
+ "log_start_time": "2026-01-31 18:17:16",
27
+ "log_end_time": "2026-01-31 18:17:27",
28
+ "run_time_log": "[18:17:16] :-: Util instans 1 inisalized\n[18:17:16] :-: Util instans 2 inisalized\n[18:17:16] :-: Util instans 3 inisalized\n[18:17:16] :-: Loader instans 'engine_loader' inisalized with 1 loader_instanses\n[18:17:16] :-: \u001b[91m!!-error loading image : asd.asd ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.asd'. -!!\u001b[0m\n[18:17:16] :-: Initialized layar manager\n[18:17:16] :-: Util instans 4 inisalized\n[18:17:16] :-: Display manager initialized\n[18:17:16] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:16] :-: r_obj instans 1 inisalized at position (300,250) with size (40,40)\n[18:17:16] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:16] :-: r_obj instans 2 inisalized at position (400,300) with size (40,40)\n[18:17:16] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:16] :-: r_obj instans 3 inisalized at position (240,150) with size (40,40)\n[18:17:16] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:16] :-: r_obj instans 4 inisalized at position (100,90) with size (40,40)\n[18:17:16] :-: \u001b[91m!!-error loading image : asd.jeff ->> in loader engine_loader with error >> No such file or directory: 'C:\\Users\\matth\\source\\repos\\ex2\\ex2\\skyport\\asd.jeff'. -!!\u001b[0m\n[18:17:16] :-: r_obj instans 5 inisalized at position (200,200) with size (40,40)\n[18:17:16] :-: Initialized camera with pryoraty of 0 and 1 instances\n[18:17:16] :-: Initialized chunk at 0,0 with a total of 1 created\n[18:17:16] :-: Initialized chunk at 1,1 with a total of 2 created\n[18:17:16] :-: Initialized chunk at 0,1 with a total of 3 created\n[18:17:16] :-: Initialized chunk at 1,0 with a total of 4 created\n[18:17:16] :-: Initialized chunk at 2,0 with a total of 5 created\n[18:17:16] :-: Initialized chunk at 2,1 with a total of 6 created\n[18:17:16] :-: Initialized chunk at 3,0 with a total of 7 created\n[18:17:16] :-: Initialized chunk at 3,1 with a total of 8 created\n[18:17:19] :-: Initialized chunk at 1,-1 with a total of 9 created\n[18:17:21] :-: Initialized chunk at 2,-1 with a total of 10 created\n[18:17:23] :-: Initialized chunk at 3,-1 with a total of 11 created\n[18:17:27] :-: Rendering thread stopped\n[18:17:27] :-: Rendering thread stopped\n"
29
+ }
30
+ ]
31
+ }
@@ -0,0 +1,129 @@
1
+
2
+ import os
3
+ import sys
4
+ import pygame
5
+ import threading
6
+ #from pygame._sdl2.video import Window, Renderer, Texture
7
+ from skyport.core.paths import PathUtil as pu
8
+ from skyport.core.paths import loger
9
+
10
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
11
+ if BASE_DIR not in sys.path:
12
+ sys.path.insert(0, BASE_DIR)
13
+
14
+ pygame.init()
15
+ pygame.display.init()
16
+ pygame.display.set_mode((1, 1), pygame.HIDDEN)
17
+
18
+ # engine imports
19
+ from assets.layar_manager import *
20
+ from global_utils import *
21
+
22
+ class Display_manager:
23
+ def __init__(self,window_size,display_size,force_full_screen=True,window_name="spyport engine window",window_ico=None,resizable=True):
24
+ self.loops = 0
25
+ self.print_rate = 8
26
+ #self.win = Window("skyport engine window--", size=window_size)
27
+ self.running = True
28
+ self.window_ico = window_ico
29
+ self.clock = pygame.time.Clock()
30
+ self._stop_event = threading.Event()
31
+ self.rendering_thread = None
32
+ self.force_full_screen = force_full_screen
33
+ self.window_size = window_size
34
+ self.display_size = display_size
35
+ self.display = pygame.Surface(self.display_size)
36
+ pygame.display.set_icon(self.window_ico) if self.window_ico else None
37
+ self.window = pygame.display.set_mode(window_size,pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)
38
+ pygame.display.set_caption(window_name)
39
+ lm = Layar_manager(self.display)
40
+ self.dt = Delta_timer()
41
+ self.util = Util()
42
+ self.print_que = ""
43
+ self.curent_game_state = "main"
44
+ self.game_states = {"main":lm}
45
+
46
+ if not pygame.display.is_fullscreen() and force_full_screen:
47
+ pygame.display.toggle_fullscreen()
48
+
49
+ self.couculate_window_scaling()
50
+ loger.log("Display manager initialized")
51
+
52
+ def get_lm(self):
53
+ return self.game_states[self.curent_game_state]
54
+ def add_game_stare(self,name,lm):
55
+ self.game_states[name] = lm
56
+ loger.log(f"added game state {name}")
57
+ def remove_game_stare(self,name):
58
+ if name in self.game_states:
59
+ del self.game_states[name]
60
+ loger.log(f"removed game state {name}")
61
+ else:
62
+ loger.log(f"tried to remove game state {name} but it does not exist")
63
+
64
+ def cclock(self,TFPS):
65
+ #self._event()
66
+ self.loops += 1
67
+ self.s_display = pygame.transform.scale(self.display, self.new_size)
68
+ self.window.blit(self.s_display,self.W_pos)
69
+ Util.print(f"loops are at {self.loops} and fps is at {self.clock.get_fps():.2f}")
70
+ pygame.display.flip()
71
+ self.clock.tick(TFPS)
72
+
73
+ def couculate_window_scaling(self):
74
+ self.display_rect = self.display.get_rect(center=(self.window.get_width() // 2, self.window.get_height() // 2))
75
+ self.window_width = self.window.get_width()
76
+ self.window_height = self.window.get_height()
77
+ self._scale = min(self.window_width / self.display.get_width(), self.window_height / self.display.get_height())
78
+ self.new_size = (int(self.display.get_width() * self._scale), int(self.display.get_height() * self._scale))
79
+ self.W_pos = ((self.window_width - self.new_size[0]) // 2, (self.window_height - self.new_size[1]) // 2)
80
+
81
+ self.center_x = self.display.get_width() / 2
82
+ self.center_y = self.display.get_height() / 2
83
+
84
+ def get_mouse_pos(self):
85
+ mx, my = pygame.mouse.get_pos()
86
+ self,mouse_pos = (((mx - self.W_pos[0]) / self._scale),((my - self.W_pos[1]) / self._scale))
87
+
88
+ def render(self):
89
+ self.display.blit(self.game_states[self.curent_game_state].render(),(0,0))
90
+
91
+ def _rendering_loop(self):
92
+ try:
93
+ while not self._stop_event.is_set():
94
+ self.render()
95
+ self.cclock(self.fps)
96
+ self.dt.get_dt()
97
+ except Exception as e:
98
+ print(f"exiting render loop do to {e}")
99
+ loger.log(f"exiting render loop do to {e}")
100
+
101
+ def START_RENDERING_THREAD(self, fps):
102
+ self.fps = fps
103
+ self._stop_event.clear()
104
+ self.rendering_thread = threading.Thread(target=self._rendering_loop, daemon=True)
105
+ self.rendering_thread.start()
106
+
107
+ def STOP_RENDERING_THREAD(self):
108
+ if self.rendering_thread and self.rendering_thread.is_alive():
109
+ self._stop_event.set()
110
+ self.rendering_thread.join()
111
+ loger.log("Rendering thread stopped")
112
+ loger.save()
113
+ def event(self):
114
+ if self.loops % self.print_rate == 0:
115
+ Util.output_print_data()
116
+ try:
117
+ events = pygame.event.get()
118
+ for event in events:
119
+ if event.type == pygame.QUIT:
120
+ self.running = False
121
+ print("\nquit pressed\n")
122
+ self.STOP_RENDERING_THREAD()
123
+ pygame.quit()
124
+ if event.type == pygame.VIDEORESIZE:
125
+ self.couculate_window_scaling()
126
+ except Exception as e:
127
+ loger.log(f"error in event handeling: {e}")
128
+
129
+
@@ -0,0 +1,9 @@
1
+
2
+ from rendering_eng import *
3
+ from paths import PathUtil
4
+
5
+
6
+
7
+
8
+
9
+
@@ -0,0 +1,6 @@
1
+ Metadata-Version: 2.4
2
+ Name: skyport_engine
3
+ Version: 0.1.5
4
+ Requires-Dist: pygame-ce>=2.5.5
5
+ Requires-Dist: numpy>=2.3.2
6
+ Dynamic: requires-dist
@@ -0,0 +1,27 @@
1
+ setup.py
2
+ skyport/__init__.py
3
+ skyport/engine_setup.py
4
+ skyport/gf_map_cunstructor.py
5
+ skyport/global_utils.py
6
+ skyport/rendering_eng.py
7
+ skyport/skyport.py
8
+ skyport/assets/layar_manager.py
9
+ skyport/assets/images/None.png
10
+ skyport/assets/images/error.png
11
+ skyport/assets/images/pt-17.png
12
+ skyport/assets/images/buttons/how_to_play.png
13
+ skyport/assets/images/buttons/menue.png
14
+ skyport/assets/images/buttons/play.png
15
+ skyport/assets/images/buttons/quit.png
16
+ skyport/assets/loader/game_file_maps/engine_assets.json
17
+ skyport/assets/loader/sound_maps/engine_sounds.json
18
+ skyport/assets/loader/texture_maps/engine_textures.json
19
+ skyport/assets/sounds/error.mp3
20
+ skyport/assets/sprites/test1.sprite/settings.json
21
+ skyport/core/paths.py
22
+ skyport/logs/engine_logs.json
23
+ skyport_engine.egg-info/PKG-INFO
24
+ skyport_engine.egg-info/SOURCES.txt
25
+ skyport_engine.egg-info/dependency_links.txt
26
+ skyport_engine.egg-info/requires.txt
27
+ skyport_engine.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ pygame-ce>=2.5.5
2
+ numpy>=2.3.2