PyScene 1.0.8__tar.gz → 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. {pyscene-1.0.8 → pyscene-1.1.0}/.gitignore +2 -0
  2. {pyscene-1.0.8 → pyscene-1.1.0}/PKG-INFO +2 -2
  3. {pyscene-1.0.8 → pyscene-1.1.0}/README.md +1 -1
  4. {pyscene-1.0.8 → pyscene-1.1.0}/pyproject.toml +1 -1
  5. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/Game.py +12 -2
  6. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/__init__.py +2 -1
  7. pyscene-1.1.0/src/PyScene/__main__.py +24 -0
  8. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/objs/GameObj.py +1 -1
  9. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/objs/Shapes.py +0 -3
  10. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/objs/Text.py +4 -2
  11. pyscene-1.1.0/src/PyScene/objs/Tilemap.py +91 -0
  12. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/objs/__init__.py +2 -1
  13. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/objs/animation.py +8 -4
  14. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/utils/Assets.py +5 -3
  15. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/utils/Subscreen.py +1 -1
  16. pyscene-1.1.0/test.py +28 -0
  17. pyscene-1.1.0/tests/tileset.png +0 -0
  18. pyscene-1.0.8/test.py +0 -30
  19. {pyscene-1.0.8 → pyscene-1.1.0}/LICENSE +0 -0
  20. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/Collisions.py +0 -0
  21. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/Keys.py +0 -0
  22. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/Math.py +0 -0
  23. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/Net.py +0 -0
  24. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/objs/Collision_shapes.py +0 -0
  25. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/objs/Timer.py +0 -0
  26. {pyscene-1.0.8 → pyscene-1.1.0}/src/PyScene/utils/__init__.py +0 -0
  27. {pyscene-1.0.8 → pyscene-1.1.0}/tests/flappy_bird.py +0 -0
  28. {pyscene-1.0.8 → pyscene-1.1.0}/tests/pause.png +0 -0
  29. {pyscene-1.0.8 → pyscene-1.1.0}/tests/testColl.py +0 -0
@@ -10,3 +10,5 @@ dist/
10
10
 
11
11
  .vscode/
12
12
  .idea/
13
+
14
+ .pyscene/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: PyScene
3
- Version: 1.0.8
3
+ Version: 1.1.0
4
4
  Summary: A python and pygame Game Engine
5
5
  Project-URL: Homepage, https://github.com/sfertig/PyScene
6
6
  Project-URL: Issues, https://github.com/sfertig/PyScene/issues
@@ -19,5 +19,5 @@ This is not a pygame wrapper, as it goed beyons the basic helper features and di
19
19
 
20
20
  Please Note: This engine is still in development and many features, like tilemaps and audio, are a work in progress. It also lack any form of documentation, I ask for patience as docs will be rolled out once the core features are more solidified.
21
21
 
22
- PyScene is in developement and API's may change offten, a fully stable version should come with v2.0.0, currently on v1.0.8
22
+ PyScene is in developement and API's may change offten, a fully stable version should come with v2.0.0, currently on v1.1.0
23
23
 
@@ -5,5 +5,5 @@ This is not a pygame wrapper, as it goed beyons the basic helper features and di
5
5
 
6
6
  Please Note: This engine is still in development and many features, like tilemaps and audio, are a work in progress. It also lack any form of documentation, I ask for patience as docs will be rolled out once the core features are more solidified.
7
7
 
8
- PyScene is in developement and API's may change offten, a fully stable version should come with v2.0.0, currently on v1.0.8
8
+ PyScene is in developement and API's may change offten, a fully stable version should come with v2.0.0, currently on v1.1.0
9
9
 
@@ -3,7 +3,7 @@ requires = ["hatchling >= 1.26"]
3
3
  build-backend = "hatchling.build"
4
4
  [project]
5
5
  name = "PyScene"
6
- version = "1.0.8"
6
+ version = "1.1.0"
7
7
  authors = [
8
8
  { name="Sam Fertig", email="sfertig007@gmail.com" },
9
9
  ]
@@ -1,5 +1,6 @@
1
1
  import pygame
2
2
  import sys
3
+ import os
3
4
 
4
5
  from .Keys import Keys
5
6
  from .Math import Vector2D
@@ -59,6 +60,13 @@ class _game:
59
60
  #other flags
60
61
  self.always_global = False
61
62
 
63
+ self.__check_dir_files()
64
+
65
+ def __check_dir_files(self): #check and create dir and files
66
+ if os.path.exists(".pyscene"): return
67
+ os.mkdir(".pyscene")
68
+ os.mkdir(".pyscene/tilemaps")
69
+
62
70
 
63
71
  def _queue_add(self, obj):
64
72
  if self.active_scene is None: self.queue_creation.append(obj)
@@ -137,7 +145,8 @@ class _game:
137
145
  if _clear: self.screen.fill(self.bg)
138
146
  #render call
139
147
  if self.active_scene is None:
140
- for obj in self.render_queue: obj.render()
148
+ for obj in self.render_queue:
149
+ if obj.visible: obj.render()
141
150
  #render scene
142
151
  else:
143
152
  self.active_scene.render()
@@ -212,7 +221,8 @@ class Scene:
212
221
  _length = len(self._objects)+len(Game.objects)
213
222
  if _length != len(self._render_queue): self.__update_render_queue()
214
223
  #render
215
- for obj in self._render_queue: obj.render()
224
+ for obj in self._render_queue:
225
+ if obj.visible: obj.render()
216
226
 
217
227
  def _queue_add(self, obj): self.queue_creation.append(obj)
218
228
  def _queue_remove(self, obj): self.queue_del.append(obj)
@@ -1,6 +1,6 @@
1
1
  #imports
2
2
  "PyScene is a custom python + pygame framework / engine developed to streamline 2d game development."
3
- "Version: 1.0.8"
3
+ "Version: 1.0.9"
4
4
 
5
5
  from .Game import Game, Scene, handle_collision
6
6
  from .Math import *
@@ -27,6 +27,7 @@ __all__ = [
27
27
  "Text",
28
28
  "Image",
29
29
  "Timer",
30
+ "Tilemap",
30
31
 
31
32
  "Animation",
32
33
  "AnimationManager",
@@ -0,0 +1,24 @@
1
+ import sys
2
+ import os
3
+
4
+ def main():
5
+ args = sys.argv[1:]
6
+ if not args:
7
+ print("PyScene CLI Tools")
8
+ print("Usage:")
9
+ print(" python -m PyScene manager - Launch tilemap & asset manager GUI")
10
+ #print(" python -m PyScene clean - Scan and remove orphaned engine files")
11
+ return
12
+
13
+ command = args[0].lower()
14
+
15
+ if command == "manager":
16
+ # Import and launch the PyGame GUI manager
17
+ #from PyScene.tools.manager_gui import launch_manager
18
+ #launch_manager()
19
+ pass
20
+ else:
21
+ print(f"Unknown PyScene command: '{command}'")
22
+
23
+ if __name__ == "__main__":
24
+ main()
@@ -3,7 +3,7 @@ from ..Math import Vector2D
3
3
  from ..Game import Game
4
4
 
5
5
  class GameObj: #this will be the base class of every game obj
6
- def __init__(self, pos, z_index=0, active=True, visible=True, Global=False):
6
+ def __init__(self, pos=Vector2D(0, 0), z_index=0, active=True, visible=True, Global=False):
7
7
  self.pos: Vector2D = pos
8
8
  self.vel: Vector2D = Vector2D(0, 0)
9
9
  self.z_index = z_index
@@ -17,7 +17,6 @@ class Rect(GameObj):
17
17
  if self.pos.to_int() != self.rect.topleft: self.rect.topleft = self.pos.to_int()
18
18
 
19
19
  def render(self):
20
- if not self.visible: return
21
20
  Game.cam.draw_rect(self.rect, self.color, self.width, self.offset)
22
21
 
23
22
  class Circle(GameObj):
@@ -29,7 +28,6 @@ class Circle(GameObj):
29
28
  self.offset = offset
30
29
 
31
30
  def render(self):
32
- if not self.visible: return
33
31
  Game.cam.draw_circle(self.pos, self.radius, self.color, self.width, self.offset)
34
32
 
35
33
  class Line(GameObj):
@@ -41,5 +39,4 @@ class Line(GameObj):
41
39
  self.offset = offset
42
40
 
43
41
  def render(self):
44
- if not self.visible: return
45
42
  Game.cam.draw_line(self.pos, self.end, self.color, self.width, self.offset)
@@ -35,8 +35,9 @@ class Text(GameObj):
35
35
  self.rect = self.surface.get_rect(**{self.align: self.pos})
36
36
 
37
37
  def render(self):
38
- if not self.visible: return
39
38
  Game.cam.draw_text(self.surface, self.rect, self.offset)
39
+ def render_to(self, surface):
40
+ surface.blit(self.surface, self.rect)
40
41
 
41
42
  class Image(GameObj):
42
43
  def __init__(self, image, pos=Vector2D(0, 0), z_index=0, active=True, visible=True, offset=True, Global=False):
@@ -45,6 +46,7 @@ class Image(GameObj):
45
46
  self.offset = offset
46
47
 
47
48
  def render(self):
48
- if not self.visible: return
49
49
  Game.cam.draw_image(self.image, self.pos, self.offset)
50
+ def render_to(self, surface):
51
+ surface.blit(self.image, self.pos.to_int())
50
52
 
@@ -0,0 +1,91 @@
1
+ import os
2
+ import json
3
+ from ..Game import Game
4
+ import pygame
5
+ from .GameObj import GameObj
6
+ from ..Math import Vector2D
7
+ from ..utils import SubScreen
8
+
9
+ class Tilemap(GameObj):
10
+ def __init__(self, name, tileset, size=16, z_index=0, active=True, visible=True, Global=False ):
11
+ super().__init__(Vector2D(0, 0), z_index, active, visible, Global)
12
+ self.name = name
13
+ self.tileset: dict[list[int], pygame.surface.Surface] = tileset
14
+ self.size: int = size
15
+
16
+ self.tilemap: dict[list[int], list[int]] = {}
17
+ self.dirty = True #set to true to load from file
18
+
19
+ self.subscreen = SubScreen(0, 0, Game.width, Game.height, displaySurface=Game.screen)
20
+ self.screen = self.subscreen.screen
21
+
22
+ self.__init_file()
23
+
24
+ def __init_file(self):
25
+ #create file if not exists
26
+ if not os.path.exists(f".pyscene/tilemaps/{self.name}.json"):
27
+ with open(f".pyscene/tilemaps/{self.name}.json", "w") as f:
28
+ json.dump({}, f)
29
+ self._load()
30
+
31
+ def _save(self):
32
+ #check tilemap
33
+ map: dict[str, str] = {}
34
+ for k, v in self.tilemap.items():
35
+ key = f"{k[0]}_{k[1]}"
36
+ value = f"{v[0]}_{v[1]}"
37
+ map[key] = value
38
+ #save tilemap
39
+ with open(f".pyscene/tilemaps/{self.name}.json", "w") as f:
40
+ json.dump(map, f)
41
+ def _load(self):
42
+ with open(f".pyscene/tilemaps/{self.name}.json", "r") as f:
43
+ data = json.load(f)
44
+ if data is None: data = {}
45
+ for k, v in data.items():
46
+ k = k.split("_")
47
+ k = (int(k[0]), int(k[1]))
48
+ v = v.split("_")
49
+ v = (int(v[0]), int(v[1]))
50
+ self.tilemap[k] = v
51
+
52
+ def update(self):
53
+ if not self.tilemap:
54
+ return
55
+ #determine if we need to re-render tilemap
56
+ if not self.dirty: return
57
+
58
+ self.dirty = False
59
+ self._save() #save tilemap with changes
60
+
61
+ #else update
62
+ min_x = min(pos[0] for pos in self.tilemap.keys())
63
+ max_x = max(pos[0] for pos in self.tilemap.keys())
64
+ min_y = min(pos[1] for pos in self.tilemap.keys())
65
+ max_y = max(pos[1] for pos in self.tilemap.keys())
66
+
67
+ # 1. Determine dimensions (+1 to include the max tile itself)
68
+ width = (max_x - min_x + 1) * self.size
69
+ height = (max_y - min_y + 1) * self.size
70
+
71
+ self.pos.x = min_x * self.size
72
+ self.pos.y = min_y * self.size
73
+
74
+ # 2. Create the SubScreen matching this exact bounding box
75
+ # Note: Position this subscreen in world space using (min_x * self.size, min_y * self.size)
76
+ self.subscreen = SubScreen(min_x * self.size, min_y * self.size, width, height, displaySurface=Game.screen)
77
+ self.subscreen.clear()
78
+ self.screen = self.subscreen.screen
79
+
80
+ # 3. Bake the tiles by offsetting negative/arbitrary coords to (0, 0)
81
+
82
+ for (tile_x, tile_y), tile_id in self.tilemap.items():
83
+ # Shift coordinates so min_x/min_y lands at local pixel (0, 0)
84
+ local_x = (tile_x - min_x) * self.size
85
+ local_y = (tile_y - min_y) * self.size
86
+
87
+ self.screen.blit(self.tileset[tile_id], (local_x, local_y))
88
+
89
+ def render(self):
90
+ Game.screen.blit(self.screen, (self.pos-Game.cam.pos).to_int())
91
+
@@ -4,5 +4,6 @@ from .Text import *
4
4
  from .animation import *
5
5
  from .Collision_shapes import *
6
6
  from .Timer import Timer
7
+ from .Tilemap import *
7
8
 
8
- __all__ = ["GameObj", "Rect", "Circle", "Line", "Text", "Image", "Animation", "AnimationManager", "StaticCollisionRect", "DynamicCollisionRect", "Timer"]
9
+ __all__ = ["GameObj", "Rect", "Circle", "Line", "Text", "Image", "Animation", "AnimationManager", "StaticCollisionRect", "DynamicCollisionRect", "Timer", "Tilemap"]
@@ -57,16 +57,19 @@ class Animation(GameObj):
57
57
  def flip_v(self):
58
58
  for i in range(len(self.images)):
59
59
  self.images[i] = pygame.transform.flip(self.images[i], False, True)
60
+ return self
60
61
 
61
62
  def flip_h(self):
62
63
  for i in range(len(self.images)):
63
64
  self.images[i] = pygame.transform.flip(self.images[i], True, False)
65
+ return self
64
66
 
65
67
  def copy(self):
66
68
  return Animation(self.image, self.size, self.fps, self.loop, self.pos, self.z_index, self.active, self.visible, self.offset, self._global)
67
69
  def render(self):
68
- if not self.visible: return
69
70
  Game.cam.draw_image(self.get_image(), self.pos, self.offset)
71
+ def render_to(self, screen):
72
+ screen.blit(self.get_image(), self.pos.to_int())
70
73
 
71
74
  class AnimationManager(GameObj):
72
75
  def __init__(self, animations: dict[str, Animation], current_anim=None, z_index=0, active=True, visible=True, offset=True, Global=False):
@@ -101,7 +104,7 @@ class AnimationManager(GameObj):
101
104
  def update(self):
102
105
  if self.current_anim is None and self.current_anim in self.animations:
103
106
  return
104
- self.animations[self.current_anim].update(Game.dt)
107
+ self.animations[self.current_anim].update()
105
108
  def get_image(self) -> pygame.Surface:
106
109
  if self.current_anim is None and self.current_anim in self.animations:
107
110
  return
@@ -112,5 +115,6 @@ class AnimationManager(GameObj):
112
115
  return self.animations[self.current_anim]
113
116
 
114
117
  def render(self):
115
- if not self.visible: return
116
- self.get_animation().render()
118
+ self.get_animation().render()
119
+ def render_to(self, screen):
120
+ self.get_animation().render_to(screen)
@@ -80,9 +80,11 @@ class _assets:
80
80
  if sWidth is not None and sHeight is not None:
81
81
  image = pygame.transform.scale(image, (sWidth, sHeight))
82
82
  self.images[name] = image.convert()
83
+ return self.images[name]
83
84
 
84
85
  def new_font(self, name, path, size):
85
86
  self.fonts[name] = pygame.font.Font(path, size)
87
+ return self.fonts[name]
86
88
 
87
89
  def new_animation(self, name, image, size=16, fps=3, loop=True, rect=None, pos=Vector2D(0, 0), z_index=0, active=True, visible=True, offset=True, Global=False):
88
90
  m = image
@@ -94,10 +96,11 @@ class _assets:
94
96
  #create image
95
97
  self.new_image(name, path, rect, scale, colorKey, sWidth, sHeight)
96
98
  #create animation
97
- self.new_animation(name, self.images[name], size*scale, fps, loop, pos, z_index, active, visible, offset, Global)
99
+ return self.new_animation(name, self.images[name], size*scale, fps, loop, pos, z_index, active, visible, offset, Global)
98
100
 
99
101
  def new_sound(self, name, path):
100
102
  self.sounds[name] = pygame.mixer.Sound(path)
103
+ return self.sounds[name]
101
104
 
102
105
  def new_tileset(self, path, name, width=16, height=16, scale=1.0, colorkey=None):
103
106
  image = pygame.image.load(path).convert_alpha()
@@ -108,6 +111,7 @@ class _assets:
108
111
  data, cache = load_tileset(image, width*scale, height*scale)
109
112
  self.tilesets[name] = data
110
113
  self._tileset_cache_data[name] = cache
114
+ return self.tilesets[name]
111
115
 
112
116
  #getters
113
117
  def get_image(self, name):
@@ -140,8 +144,6 @@ class _assets:
140
144
  else:
141
145
  return None
142
146
 
143
-
144
-
145
147
  Assets = _assets()
146
148
 
147
149
  def load_tileset(image, width, height):
@@ -4,7 +4,7 @@ from ..Math import Vector2D
4
4
 
5
5
 
6
6
  class SubScreen:
7
- def __init__(self, x, y, w, h, bgColor: None, displaySurface: pygame.Surface = None, parent=None):
7
+ def __init__(self, x, y, w, h, bgColor = None, displaySurface: pygame.Surface = None, parent=None):
8
8
  self.pos = Vector2D(x, y)
9
9
  self.dim = Vector2D(w, h)
10
10
  self.color = bgColor
pyscene-1.1.0/test.py ADDED
@@ -0,0 +1,28 @@
1
+ from src.PyScene import *
2
+ import pygame
3
+
4
+
5
+ Game.init(640, 360, "Test - 01", "darkblue", fullscreen=False)
6
+
7
+ class Player(GameObj):
8
+ def __init__(self):
9
+ super().__init__(Vector2D(0, 0), 0)
10
+ self.rect = Rect(0, 0, 16, 16, "green")
11
+
12
+ def update(self):
13
+ self.vel = (Keys.get_vector(Keys.a, Keys.d, Keys.w, Keys.s, False)*150)*Game.dt
14
+ self.pos += self.vel
15
+ self.rect.pos = self.pos
16
+
17
+ Game.cam.pos.x = -Game.width/2
18
+ Game.cam.pos.y = -Game.height/2
19
+ Player()
20
+
21
+ Assets.new_tileset("tests/tileset.png", "tileset")
22
+ t = Tilemap("test", Assets.get_tileset("tileset"), 16, -1)
23
+
24
+ #t.tilemap[(0, 0)] = (1, 0)
25
+ #t.tilemap[(0, 1)] = (1, 1)
26
+ #t.dirty = True
27
+
28
+ Game.Run(True)
Binary file
pyscene-1.0.8/test.py DELETED
@@ -1,30 +0,0 @@
1
- from src.PyScene import *
2
- import pygame
3
-
4
-
5
- Game.init(640, 360, "Test - 01", "darkblue", fullscreen=False)
6
-
7
- class player(GameObj):
8
- def __init__(self):
9
- super().__init__(Vector2D(0, 0), 0)
10
- #create animation
11
- Assets.new_anim_nIMG("player", 8, 2, "tests/pause.png", (0, 0, 16, 8), colorKey=None, scale=3.0)
12
- self.anim = Assets.get_animation("player")
13
-
14
- def update(self):
15
- self.pos += (Keys.get_vector(Keys.a, Keys.d, Keys.w, Keys.s, False)*150)*Game.dt
16
- self.anim.pos = self.pos #positions stay linked
17
-
18
- class Test(Scene):
19
- def __init__(self):
20
- super().__init__("Test")
21
- player()
22
-
23
- Test()
24
-
25
- Game.Tick()
26
- print(Game.objects)
27
- print(Game.active_scene._objects)
28
-
29
- Game.Run()
30
-
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes