pygame-foundation 0.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.
- pygame_foundation-0.1.0/LICENSE +21 -0
- pygame_foundation-0.1.0/PKG-INFO +72 -0
- pygame_foundation-0.1.0/README.md +55 -0
- pygame_foundation-0.1.0/pyproject.toml +37 -0
- pygame_foundation-0.1.0/setup.cfg +4 -0
- pygame_foundation-0.1.0/src/pygame_foundation/__init__.py +8 -0
- pygame_foundation-0.1.0/src/pygame_foundation/core/__int__.py +11 -0
- pygame_foundation-0.1.0/src/pygame_foundation/core/constants.py +7 -0
- pygame_foundation-0.1.0/src/pygame_foundation/core/debug.py +48 -0
- pygame_foundation-0.1.0/src/pygame_foundation/core/entities.py +125 -0
- pygame_foundation-0.1.0/src/pygame_foundation/core/game.py +50 -0
- pygame_foundation-0.1.0/src/pygame_foundation/core/world.py +284 -0
- pygame_foundation-0.1.0/src/pygame_foundation.egg-info/PKG-INFO +72 -0
- pygame_foundation-0.1.0/src/pygame_foundation.egg-info/SOURCES.txt +15 -0
- pygame_foundation-0.1.0/src/pygame_foundation.egg-info/dependency_links.txt +1 -0
- pygame_foundation-0.1.0/src/pygame_foundation.egg-info/requires.txt +2 -0
- pygame_foundation-0.1.0/src/pygame_foundation.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pygame-foundation
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A modern wrapper around Pygame.
|
|
5
|
+
Author: Arad Rezakhani
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: pygame,game,gamedev,engine,framework
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: pygame>=2.6
|
|
15
|
+
Requires-Dist: termcolor>=3.1
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# pygame-foundation
|
|
19
|
+
|
|
20
|
+
A foundation for building Pygame projects and games.
|
|
21
|
+
|
|
22
|
+
pygame-foundation is currently in active development. Version 0.1.0 is the initial public release, and additional features are planned for future versions.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
pip install pygame-foundation
|
|
27
|
+
|
|
28
|
+
## Features
|
|
29
|
+
|
|
30
|
+
- Game class
|
|
31
|
+
- World class
|
|
32
|
+
- Entity class
|
|
33
|
+
- Layered rendering
|
|
34
|
+
- Update priorities
|
|
35
|
+
- Tag management
|
|
36
|
+
- Visibility control
|
|
37
|
+
- Active/paused states
|
|
38
|
+
- Update intervals
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from pygame_foundation import Game, World, Entity
|
|
44
|
+
|
|
45
|
+
game = Game()
|
|
46
|
+
world = game.world
|
|
47
|
+
|
|
48
|
+
player = Entity(
|
|
49
|
+
x=100,
|
|
50
|
+
y=100,
|
|
51
|
+
size=(50, 50)
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
world.add(player)
|
|
55
|
+
|
|
56
|
+
game.run()
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Roadmap
|
|
60
|
+
|
|
61
|
+
- Scene system
|
|
62
|
+
- Camera
|
|
63
|
+
- Input manager
|
|
64
|
+
- Asset manager
|
|
65
|
+
- Animation system
|
|
66
|
+
- Timer system
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
## License
|
|
70
|
+
|
|
71
|
+
This project is licensed under the MIT License.
|
|
72
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# pygame-foundation
|
|
2
|
+
|
|
3
|
+
A foundation for building Pygame projects and games.
|
|
4
|
+
|
|
5
|
+
pygame-foundation is currently in active development. Version 0.1.0 is the initial public release, and additional features are planned for future versions.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
pip install pygame-foundation
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Game class
|
|
14
|
+
- World class
|
|
15
|
+
- Entity class
|
|
16
|
+
- Layered rendering
|
|
17
|
+
- Update priorities
|
|
18
|
+
- Tag management
|
|
19
|
+
- Visibility control
|
|
20
|
+
- Active/paused states
|
|
21
|
+
- Update intervals
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from pygame_foundation import Game, World, Entity
|
|
27
|
+
|
|
28
|
+
game = Game()
|
|
29
|
+
world = game.world
|
|
30
|
+
|
|
31
|
+
player = Entity(
|
|
32
|
+
x=100,
|
|
33
|
+
y=100,
|
|
34
|
+
size=(50, 50)
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
world.add(player)
|
|
38
|
+
|
|
39
|
+
game.run()
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Roadmap
|
|
43
|
+
|
|
44
|
+
- Scene system
|
|
45
|
+
- Camera
|
|
46
|
+
- Input manager
|
|
47
|
+
- Asset manager
|
|
48
|
+
- Animation system
|
|
49
|
+
- Timer system
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
This project is licensed under the MIT License.
|
|
55
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pygame-foundation"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A modern wrapper around Pygame."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "Arad Rezakhani" }
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
dependencies = [
|
|
18
|
+
"pygame>=2.6",
|
|
19
|
+
"termcolor>=3.1"
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
keywords = [
|
|
23
|
+
"pygame",
|
|
24
|
+
"game",
|
|
25
|
+
"gamedev",
|
|
26
|
+
"engine",
|
|
27
|
+
"framework"
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
classifiers = [
|
|
31
|
+
"Programming Language :: Python :: 3",
|
|
32
|
+
"License :: OSI Approved :: MIT License",
|
|
33
|
+
"Operating System :: OS Independent"
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.packages.find]
|
|
37
|
+
where = ["src"]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
from functools import wraps
|
|
2
|
+
from termcolor import colored
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
def debug_and_log(messages:dict, expected_errors=[Exception], end='\n'):
|
|
6
|
+
'''
|
|
7
|
+
A decorator that checks for errors and log the data to the terminal
|
|
8
|
+
|
|
9
|
+
NOTE:
|
|
10
|
+
Leave expected_errors as empty list to catch no errors
|
|
11
|
+
and leave it as default to catch all errors
|
|
12
|
+
'''
|
|
13
|
+
if expected_errors is None:
|
|
14
|
+
expected_errors = (Exception,)
|
|
15
|
+
else:
|
|
16
|
+
expected_errors = tuple(expected_errors)
|
|
17
|
+
|
|
18
|
+
def get_error_message(error):
|
|
19
|
+
error_messages = messages.get("errors", {})
|
|
20
|
+
|
|
21
|
+
for error_type in type(error).__mro__:
|
|
22
|
+
if error_type in error_messages:
|
|
23
|
+
return error_messages[error_type]
|
|
24
|
+
|
|
25
|
+
return messages["error"]
|
|
26
|
+
|
|
27
|
+
def decorator(func):
|
|
28
|
+
@wraps(func)
|
|
29
|
+
def wrapper(*args, **kwargs):
|
|
30
|
+
# For instance methods, args[0] is normally `self`.
|
|
31
|
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
32
|
+
current_time = f"[{colored(timestamp, 'yellow')}]"
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
result = func(*args, **kwargs)
|
|
36
|
+
|
|
37
|
+
except expected_errors as error:
|
|
38
|
+
message = colored(get_error_message(error), "red")
|
|
39
|
+
print(f"{current_time}: {message}: {error}", end=end)
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
success = colored(messages["success"], "green")
|
|
43
|
+
print(f"{current_time}: {success}", end=end)
|
|
44
|
+
|
|
45
|
+
return result
|
|
46
|
+
|
|
47
|
+
return wrapper
|
|
48
|
+
return decorator
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
from .constants import WHITE, UPDATE_EVERY_FRAME
|
|
2
|
+
from .debug import debug_and_log
|
|
3
|
+
import pygame
|
|
4
|
+
|
|
5
|
+
class Entity(pygame.sprite.Sprite):
|
|
6
|
+
''' A super class to be used to create subclasses '''
|
|
7
|
+
def __init__(self,
|
|
8
|
+
x,
|
|
9
|
+
y,
|
|
10
|
+
imagepath=None,
|
|
11
|
+
size=(0, 0),
|
|
12
|
+
color=WHITE,
|
|
13
|
+
visible:bool=True,
|
|
14
|
+
paused:bool=False,
|
|
15
|
+
active:bool=True,
|
|
16
|
+
priority:int=0,
|
|
17
|
+
layer:int=0,
|
|
18
|
+
update_interval:float=UPDATE_EVERY_FRAME,
|
|
19
|
+
tags:set=None,
|
|
20
|
+
name='NONE'):
|
|
21
|
+
''' Initializes the Entity Class '''
|
|
22
|
+
super().__init__()
|
|
23
|
+
if imagepath:
|
|
24
|
+
self.image = pygame.image.load(imagepath)
|
|
25
|
+
self.rect = self.image.get_rect(topleft=(x, y))
|
|
26
|
+
|
|
27
|
+
else:
|
|
28
|
+
self.image = None
|
|
29
|
+
self.rect = pygame.Rect(x, y, *size)
|
|
30
|
+
self.color = color
|
|
31
|
+
|
|
32
|
+
self._world = None
|
|
33
|
+
|
|
34
|
+
self.visible = visible
|
|
35
|
+
self.paused = paused
|
|
36
|
+
self.active = active
|
|
37
|
+
self._priority = priority
|
|
38
|
+
self._layer = layer
|
|
39
|
+
self.update_interval = update_interval
|
|
40
|
+
self._elapsed = 0.0
|
|
41
|
+
self._tags = set() if tags is None else set(tags)
|
|
42
|
+
self.name = name
|
|
43
|
+
|
|
44
|
+
def __str__(self):
|
|
45
|
+
return self.name
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def world(self):
|
|
49
|
+
return self._world
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def tags(self):
|
|
53
|
+
return frozenset(self._tags)
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def layer(self):
|
|
57
|
+
return self._layer
|
|
58
|
+
|
|
59
|
+
@layer.setter
|
|
60
|
+
def layer(self, value):
|
|
61
|
+
if self._layer == value:
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
old_layer = self._layer
|
|
65
|
+
self._layer = value
|
|
66
|
+
|
|
67
|
+
if self._world is not None:
|
|
68
|
+
self._world._move_layer(self, old_layer, value)
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def priority(self):
|
|
72
|
+
return self._priority
|
|
73
|
+
|
|
74
|
+
@priority.setter
|
|
75
|
+
def priority(self, value):
|
|
76
|
+
if self._priority == value:
|
|
77
|
+
return
|
|
78
|
+
|
|
79
|
+
old_priority = self._priority
|
|
80
|
+
self._priority = value
|
|
81
|
+
|
|
82
|
+
if self._world is not None:
|
|
83
|
+
self._world._move_priority(self, old_priority, value)
|
|
84
|
+
|
|
85
|
+
def update(self, dt):
|
|
86
|
+
'''Override in subclasses'''
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
def draw(self, surface):
|
|
90
|
+
''' Draw or blit self to screen '''
|
|
91
|
+
if self.visible:
|
|
92
|
+
if self.image:
|
|
93
|
+
surface.blit(self.image, self.rect)
|
|
94
|
+
|
|
95
|
+
else:
|
|
96
|
+
pygame.draw.rect(surface, self.color, self.rect)
|
|
97
|
+
|
|
98
|
+
@debug_and_log({
|
|
99
|
+
'success':'Succussfully added tag.',
|
|
100
|
+
'error':'Tag Addition Error',
|
|
101
|
+
})
|
|
102
|
+
def add_tag(self, tag):
|
|
103
|
+
if tag in self._tags:
|
|
104
|
+
return
|
|
105
|
+
|
|
106
|
+
self._tags.add(tag)
|
|
107
|
+
|
|
108
|
+
if self._world is not None:
|
|
109
|
+
self._world._add_tag(self, tag)
|
|
110
|
+
|
|
111
|
+
@debug_and_log({
|
|
112
|
+
'success':'Succussfully removed tag.',
|
|
113
|
+
'error':'Tag Removal Error',
|
|
114
|
+
})
|
|
115
|
+
def remove_tag(self, tag):
|
|
116
|
+
if tag not in self._tags:
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
self._tags.remove(tag)
|
|
120
|
+
|
|
121
|
+
if self._world is not None:
|
|
122
|
+
self._world._remove_tag(self, tag)
|
|
123
|
+
|
|
124
|
+
def has_tag(self, tag):
|
|
125
|
+
return tag in self._tags
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from .debug import debug_and_log
|
|
2
|
+
from .constants import *
|
|
3
|
+
from .world import World
|
|
4
|
+
import pygame
|
|
5
|
+
|
|
6
|
+
class Game:
|
|
7
|
+
''' A class that acts as a manager for all events in the game '''
|
|
8
|
+
def __init__(self, window_width, window_height, caption, fps):
|
|
9
|
+
''' Initialize the Game class and pygame '''
|
|
10
|
+
pygame.init()
|
|
11
|
+
|
|
12
|
+
self.window_width = window_width
|
|
13
|
+
self.window_height = window_height
|
|
14
|
+
self.fps = fps
|
|
15
|
+
|
|
16
|
+
self.surface = pygame.display.set_mode((window_width, window_height))
|
|
17
|
+
pygame.display.set_caption(caption)
|
|
18
|
+
|
|
19
|
+
self.clock = pygame.time.Clock()
|
|
20
|
+
|
|
21
|
+
self.world = World()
|
|
22
|
+
|
|
23
|
+
def update(self, dt):
|
|
24
|
+
''' Update the Game '''
|
|
25
|
+
self.world.update(dt)
|
|
26
|
+
|
|
27
|
+
pygame.display.update()
|
|
28
|
+
|
|
29
|
+
def draw(self):
|
|
30
|
+
''' Draw and blit Objects to the screen '''
|
|
31
|
+
self.world.draw(self.surface)
|
|
32
|
+
|
|
33
|
+
@debug_and_log({
|
|
34
|
+
'success':'Successfully closed game',
|
|
35
|
+
'error':'Error has occured during game',
|
|
36
|
+
})
|
|
37
|
+
def run(self):
|
|
38
|
+
''' Run the Game '''
|
|
39
|
+
self.running = True
|
|
40
|
+
while self.running:
|
|
41
|
+
dt = self.clock.tick(self.fps) / 1000.0
|
|
42
|
+
for event in pygame.event.get():
|
|
43
|
+
if event.type == pygame.QUIT:
|
|
44
|
+
self.running = False
|
|
45
|
+
|
|
46
|
+
self.surface.fill((0, 12, 12))
|
|
47
|
+
self.draw()
|
|
48
|
+
|
|
49
|
+
self.update(dt)
|
|
50
|
+
pygame.quit()
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
from .constants import UPDATE_EVERY_FRAME, WHITE, BLACK, GREEN
|
|
2
|
+
from .debug import debug_and_log
|
|
3
|
+
from termcolor import colored
|
|
4
|
+
import pygame
|
|
5
|
+
import random
|
|
6
|
+
|
|
7
|
+
class World(pygame.sprite.Group):
|
|
8
|
+
"""An enhanced Sprite Group used to manage game entities."""
|
|
9
|
+
|
|
10
|
+
def __init__(self):
|
|
11
|
+
super().__init__()
|
|
12
|
+
print(colored('Info:', 'blue'), 'The Message above is normal even when no obj is added to the world')
|
|
13
|
+
|
|
14
|
+
self._layers = {}
|
|
15
|
+
self._priorities = {}
|
|
16
|
+
self._tags = {}
|
|
17
|
+
|
|
18
|
+
@debug_and_log(
|
|
19
|
+
{
|
|
20
|
+
'success':'Succussfully added obj/objs to World',
|
|
21
|
+
'error':'World Obj Addition Error'
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
def add(self, *sprites: pygame.sprite.Sprite) -> None:
|
|
25
|
+
super().add(*sprites)
|
|
26
|
+
|
|
27
|
+
for sprite in sprites:
|
|
28
|
+
sprite._world = self
|
|
29
|
+
|
|
30
|
+
self._update_layers(*sprites)
|
|
31
|
+
self._update_priorities(*sprites)
|
|
32
|
+
self._update_tags(*sprites)
|
|
33
|
+
|
|
34
|
+
@debug_and_log(
|
|
35
|
+
{
|
|
36
|
+
'success':'Succussfully removed obj/objs from World',
|
|
37
|
+
'error':'World Obj Removal Error'
|
|
38
|
+
}
|
|
39
|
+
)
|
|
40
|
+
def remove(self, *sprites):
|
|
41
|
+
super().remove(*sprites)
|
|
42
|
+
|
|
43
|
+
for sprite in sprites:
|
|
44
|
+
|
|
45
|
+
self._layers[sprite.layer].remove(sprite)
|
|
46
|
+
self._priorities[sprite.priority].remove(sprite)
|
|
47
|
+
|
|
48
|
+
if not self._layers[sprite.layer]:
|
|
49
|
+
del self._layers[sprite.layer]
|
|
50
|
+
|
|
51
|
+
if not self._priorities[sprite.priority]:
|
|
52
|
+
del self._priorities[sprite.priority]
|
|
53
|
+
|
|
54
|
+
for tag in sprite.tags:
|
|
55
|
+
self._tags[tag].remove(sprite)
|
|
56
|
+
|
|
57
|
+
if not self._tags[tag]:
|
|
58
|
+
del self._tags[tag]
|
|
59
|
+
|
|
60
|
+
sprite._world = None
|
|
61
|
+
|
|
62
|
+
def _update_tags(self, *sprites):
|
|
63
|
+
for sprite in sprites:
|
|
64
|
+
for tag in sprite.tags:
|
|
65
|
+
self._tags.setdefault(tag, []).append(sprite)
|
|
66
|
+
|
|
67
|
+
def _add_tag(self, sprite, tag):
|
|
68
|
+
self._tags.setdefault(tag, []).append(sprite)
|
|
69
|
+
|
|
70
|
+
def _remove_tag(self, sprite, tag):
|
|
71
|
+
if tag in self._tags:
|
|
72
|
+
self._tags[tag].remove(sprite)
|
|
73
|
+
|
|
74
|
+
if not self._tags[tag]:
|
|
75
|
+
del self._tags[tag]
|
|
76
|
+
|
|
77
|
+
def _update_priorities(self, *sprites):
|
|
78
|
+
for sprite in sprites:
|
|
79
|
+
if sprite.priority in self._priorities:
|
|
80
|
+
self._priorities[sprite.priority].append(sprite)
|
|
81
|
+
|
|
82
|
+
else:
|
|
83
|
+
self._priorities[sprite.priority] = [sprite]
|
|
84
|
+
|
|
85
|
+
def _move_priority(self, sprite, old_priority, new_priority):
|
|
86
|
+
self._priorities[old_priority].remove(sprite)
|
|
87
|
+
|
|
88
|
+
if not self._priorities[old_priority]:
|
|
89
|
+
del self._priorities[old_priority]
|
|
90
|
+
|
|
91
|
+
self._priorities.setdefault(new_priority, []).append(sprite)
|
|
92
|
+
|
|
93
|
+
def _update_layers(self, *sprites):
|
|
94
|
+
for sprite in sprites:
|
|
95
|
+
if sprite.layer in self._layers:
|
|
96
|
+
self._layers[sprite.layer].append(sprite)
|
|
97
|
+
|
|
98
|
+
else:
|
|
99
|
+
self._layers[sprite.layer] = [sprite]
|
|
100
|
+
|
|
101
|
+
def _move_layer(self, sprite, old_layer, new_layer):
|
|
102
|
+
# Remove from old layer
|
|
103
|
+
self._layers[old_layer].remove(sprite)
|
|
104
|
+
|
|
105
|
+
# Delete empty layer
|
|
106
|
+
if not self._layers[old_layer]:
|
|
107
|
+
del self._layers[old_layer]
|
|
108
|
+
|
|
109
|
+
# Add to new layer
|
|
110
|
+
self._layers.setdefault(new_layer, []).append(sprite)
|
|
111
|
+
|
|
112
|
+
def _find_tags(self, *tags, match_all=False):
|
|
113
|
+
sprites = []
|
|
114
|
+
matcher = all if match_all else any
|
|
115
|
+
|
|
116
|
+
for sprite in self.sprites():
|
|
117
|
+
if matcher(tag in sprite._tags for tag in tags):
|
|
118
|
+
sprites.append(sprite)
|
|
119
|
+
|
|
120
|
+
return sprites
|
|
121
|
+
|
|
122
|
+
def draw(self, surface):
|
|
123
|
+
for layer in sorted(self._layers):
|
|
124
|
+
for sprite in self._layers[layer]:
|
|
125
|
+
if not sprite.active:
|
|
126
|
+
continue
|
|
127
|
+
|
|
128
|
+
sprite.draw(surface)
|
|
129
|
+
|
|
130
|
+
def update(self, dt):
|
|
131
|
+
''' Updates the objects in the world according to their update_interval and priority. '''
|
|
132
|
+
for priority in sorted(self._priorities):
|
|
133
|
+
for sprite in self._priorities[priority]:
|
|
134
|
+
if not sprite.active or sprite.paused:
|
|
135
|
+
continue
|
|
136
|
+
|
|
137
|
+
sprite._elapsed += dt
|
|
138
|
+
|
|
139
|
+
if sprite.update_interval is UPDATE_EVERY_FRAME:
|
|
140
|
+
sprite.update(dt)
|
|
141
|
+
|
|
142
|
+
elif sprite._elapsed >= sprite.update_interval:
|
|
143
|
+
sprite.update(dt)
|
|
144
|
+
sprite._elapsed -= sprite.update_interval
|
|
145
|
+
|
|
146
|
+
@debug_and_log({
|
|
147
|
+
'success':'Succussfully found sprites by tags',
|
|
148
|
+
'error':'Sprites Search by Tags Error'
|
|
149
|
+
}
|
|
150
|
+
)
|
|
151
|
+
def find_by_tags(self, *tags) -> list:
|
|
152
|
+
'''
|
|
153
|
+
Gets all the sprites that contains the specified tags.
|
|
154
|
+
This function gets all the sprites that contain any of the tags
|
|
155
|
+
not filter them by tags.
|
|
156
|
+
'''
|
|
157
|
+
sprites = []
|
|
158
|
+
|
|
159
|
+
for tag in tags:
|
|
160
|
+
for sprite in self._tags.get(tag, []):
|
|
161
|
+
if sprite not in sprites:
|
|
162
|
+
sprites.append(sprite)
|
|
163
|
+
|
|
164
|
+
return sprites
|
|
165
|
+
|
|
166
|
+
@debug_and_log({
|
|
167
|
+
'success':'Succussfully found sprites by tags',
|
|
168
|
+
'error':'Sprites Search by Tags(Match All) Error'
|
|
169
|
+
}
|
|
170
|
+
)
|
|
171
|
+
def find_by_tags_all(self, *tags) -> list:
|
|
172
|
+
'''
|
|
173
|
+
Gets all the sprites that contains the specified tags.
|
|
174
|
+
This function filters and gets all the sprites that have all the tags
|
|
175
|
+
not only one.
|
|
176
|
+
'''
|
|
177
|
+
sprites = set(self._tags.get(tags[0], []))
|
|
178
|
+
for tag in tags[1:]:
|
|
179
|
+
sprites &= set(self._tags.get(tag, []))
|
|
180
|
+
|
|
181
|
+
return list(sprites)
|
|
182
|
+
|
|
183
|
+
@debug_and_log(
|
|
184
|
+
{
|
|
185
|
+
'success':'Succussfully paused sprites by tags',
|
|
186
|
+
'error':'Sprites Pause by Tags Error'
|
|
187
|
+
}
|
|
188
|
+
)
|
|
189
|
+
def pause_tags(self, *tags) -> list:
|
|
190
|
+
'''
|
|
191
|
+
Pauses the sprites that contains the specified tags.
|
|
192
|
+
It does this by changing the paused attribute on the entity to True.
|
|
193
|
+
'''
|
|
194
|
+
sprites = self._find_tags(*tags)
|
|
195
|
+
for sprite in sprites:
|
|
196
|
+
sprite.paused = True
|
|
197
|
+
|
|
198
|
+
return sprites
|
|
199
|
+
|
|
200
|
+
@debug_and_log(
|
|
201
|
+
{
|
|
202
|
+
'success':'Succussfully resumed sprites by tags',
|
|
203
|
+
'error':'Sprites Resume by Tags Error'
|
|
204
|
+
}
|
|
205
|
+
)
|
|
206
|
+
def resume_tags(self, *tags) -> list:
|
|
207
|
+
'''
|
|
208
|
+
Resumes the sprites that contains the specified tags.
|
|
209
|
+
It does this by changing the paused attribute on the entity to False.
|
|
210
|
+
'''
|
|
211
|
+
sprites = self._find_tags(*tags)
|
|
212
|
+
for sprite in sprites:
|
|
213
|
+
sprite.paused = False
|
|
214
|
+
|
|
215
|
+
return sprites
|
|
216
|
+
|
|
217
|
+
@debug_and_log(
|
|
218
|
+
{
|
|
219
|
+
'success':'Succussfully hid sprites by tags',
|
|
220
|
+
'error':'Sprites Hide by Tags Error'
|
|
221
|
+
}
|
|
222
|
+
)
|
|
223
|
+
def hide_tags(self, *tags) -> list:
|
|
224
|
+
'''
|
|
225
|
+
Hides the sprites that contains the specified tags.
|
|
226
|
+
It does this by changing the visible attribute on the entity to False.
|
|
227
|
+
'''
|
|
228
|
+
sprites = self._find_tags(*tags)
|
|
229
|
+
for sprite in sprites:
|
|
230
|
+
sprite.visible = False
|
|
231
|
+
|
|
232
|
+
return sprites
|
|
233
|
+
|
|
234
|
+
@debug_and_log(
|
|
235
|
+
{
|
|
236
|
+
'success':'Succussfully shown sprites by tags',
|
|
237
|
+
'error':'Sprites Show by Tags Error'
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
def show_tags(self, *tags) -> list:
|
|
241
|
+
'''
|
|
242
|
+
Show the hidden sprites that contains the specified tags.
|
|
243
|
+
It does this by changing the visible attribute on the entity to True.
|
|
244
|
+
'''
|
|
245
|
+
sprites = self._find_tags(*tags)
|
|
246
|
+
for sprite in sprites:
|
|
247
|
+
sprite.visible = True
|
|
248
|
+
|
|
249
|
+
return sprites
|
|
250
|
+
|
|
251
|
+
@debug_and_log(
|
|
252
|
+
{
|
|
253
|
+
'success':'Succussfully activated sprites by tags',
|
|
254
|
+
'error':'Sprites Activation by Tags Error'
|
|
255
|
+
}
|
|
256
|
+
)
|
|
257
|
+
def activate_tags(self, *tags) -> list:
|
|
258
|
+
'''
|
|
259
|
+
Activate the sprites that contains the specified tags.
|
|
260
|
+
It does this by changing the active attribute on the entity to True.
|
|
261
|
+
'''
|
|
262
|
+
sprites = self._find_tags(*tags)
|
|
263
|
+
for sprite in sprites:
|
|
264
|
+
sprite.active = True
|
|
265
|
+
|
|
266
|
+
return sprites
|
|
267
|
+
|
|
268
|
+
@debug_and_log(
|
|
269
|
+
{
|
|
270
|
+
'success':'Succussfully deactivated sprites by tags',
|
|
271
|
+
'error':'Sprites Deactivation by Tags Error'
|
|
272
|
+
}
|
|
273
|
+
)
|
|
274
|
+
def deactivate_tags(self, *tags) -> list:
|
|
275
|
+
'''
|
|
276
|
+
Deactivate the sprites that contains the specified tags.
|
|
277
|
+
It does this by changing the active attribute on the entity to False.
|
|
278
|
+
'''
|
|
279
|
+
sprites = self._find_tags(*tags)
|
|
280
|
+
for sprite in sprites:
|
|
281
|
+
sprite.active = False
|
|
282
|
+
|
|
283
|
+
return sprites
|
|
284
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pygame-foundation
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A modern wrapper around Pygame.
|
|
5
|
+
Author: Arad Rezakhani
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: pygame,game,gamedev,engine,framework
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: pygame>=2.6
|
|
15
|
+
Requires-Dist: termcolor>=3.1
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# pygame-foundation
|
|
19
|
+
|
|
20
|
+
A foundation for building Pygame projects and games.
|
|
21
|
+
|
|
22
|
+
pygame-foundation is currently in active development. Version 0.1.0 is the initial public release, and additional features are planned for future versions.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
pip install pygame-foundation
|
|
27
|
+
|
|
28
|
+
## Features
|
|
29
|
+
|
|
30
|
+
- Game class
|
|
31
|
+
- World class
|
|
32
|
+
- Entity class
|
|
33
|
+
- Layered rendering
|
|
34
|
+
- Update priorities
|
|
35
|
+
- Tag management
|
|
36
|
+
- Visibility control
|
|
37
|
+
- Active/paused states
|
|
38
|
+
- Update intervals
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from pygame_foundation import Game, World, Entity
|
|
44
|
+
|
|
45
|
+
game = Game()
|
|
46
|
+
world = game.world
|
|
47
|
+
|
|
48
|
+
player = Entity(
|
|
49
|
+
x=100,
|
|
50
|
+
y=100,
|
|
51
|
+
size=(50, 50)
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
world.add(player)
|
|
55
|
+
|
|
56
|
+
game.run()
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Roadmap
|
|
60
|
+
|
|
61
|
+
- Scene system
|
|
62
|
+
- Camera
|
|
63
|
+
- Input manager
|
|
64
|
+
- Asset manager
|
|
65
|
+
- Animation system
|
|
66
|
+
- Timer system
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
## License
|
|
70
|
+
|
|
71
|
+
This project is licensed under the MIT License.
|
|
72
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/pygame_foundation/__init__.py
|
|
5
|
+
src/pygame_foundation.egg-info/PKG-INFO
|
|
6
|
+
src/pygame_foundation.egg-info/SOURCES.txt
|
|
7
|
+
src/pygame_foundation.egg-info/dependency_links.txt
|
|
8
|
+
src/pygame_foundation.egg-info/requires.txt
|
|
9
|
+
src/pygame_foundation.egg-info/top_level.txt
|
|
10
|
+
src/pygame_foundation/core/__int__.py
|
|
11
|
+
src/pygame_foundation/core/constants.py
|
|
12
|
+
src/pygame_foundation/core/debug.py
|
|
13
|
+
src/pygame_foundation/core/entities.py
|
|
14
|
+
src/pygame_foundation/core/game.py
|
|
15
|
+
src/pygame_foundation/core/world.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pygame_foundation
|