Compare commits

..

9 Commits

Author SHA1 Message Date
08d6261d3f Updated version 2025-06-21 23:08:39 +01:00
95afab5431 Implemented centre() 2025-06-21 23:03:38 +01:00
d897a3744d Added documentation for createAnimObj() 2025-06-21 23:03:27 +01:00
4161ec9c5b Added timeouts 2025-06-21 23:03:11 +01:00
a421069a63 Added animation events 2025-06-20 19:26:43 +01:00
44f75b52d0 Added size property 2025-06-20 18:21:50 +01:00
8f2dcbfd21 Removed unused debug functions 2025-06-20 18:08:13 +01:00
2c79adaf36 So apparently if you don't put all of this in it's own directory, pip explodes. 2025-06-20 18:05:57 +01:00
f4e0e24774 Moved initialisation from BaseGame to GameUtils 2025-06-20 14:46:29 +01:00
8 changed files with 138 additions and 41 deletions

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project] [project]
name = "gameUtils" name = "gameUtils"
version = "0.0.1.dev0" version = "1.0.0"
description = "A set of utilities to make the game development process less painful (despite the organisation name) and more unified." description = "A set of utilities to make the game development process less painful (despite the organisation name) and more unified."
authors = [{ name = "Brosef" }] authors = [{ name = "Brosef" }]
dependencies = ["pygame-ce"] dependencies = ["pygame-ce"]

View File

@ -1,12 +0,0 @@
class Game:
def __init__(self):
pass
def update(self):
pass
def onEvent(self, event):
pass
def close(self):
pass

View File

@ -2,3 +2,6 @@ from .base import Game
from .utils import centre from .utils import centre
from .anim import AnimationHandler from .anim import AnimationHandler
from .anim import AnimatedObject from .anim import AnimatedObject
from .events import AnimStart
from .events import AnimFinish
from .events import Timeout

View File

@ -1,3 +1,5 @@
from .events import AnimStart
from .events import AnimFinish
import pygame import pygame
import time import time
@ -18,16 +20,21 @@ class AnimatedObject:
""" """
""" """
def __init__(self, baseFrame): def __init__(self, _game, objectID: str, baseFrame: str):
""" """
Args: Args:
_game: Used internally.
objectID: Used to identify this animated object.
baseFrame: A still image that gets displayed when no other animation is playing. baseFrame: A still image that gets displayed when no other animation is playing.
""" """
self._game = _game
self.objectID = objectID
self._currentAnim = None self._currentAnim = None
self._animStart = None self._animStart = None
self._animations = {} self._animations = {}
self.baseFrame = pygame.image.load(baseFrame) self.baseFrame = pygame.image.load(baseFrame)
self.size = self.baseFrame.size
self._surf = pygame.Surface(self.baseFrame.size) self._surf = pygame.Surface(self.baseFrame.size)
def getFrame(self) -> pygame.Surface: def getFrame(self) -> pygame.Surface:
@ -46,6 +53,7 @@ class AnimatedObject:
frame = min(round((time.perf_counter() - self._animStart) * self._currentAnim.fps), self._currentAnim.frameCount - 1) frame = min(round((time.perf_counter() - self._animStart) * self._currentAnim.fps), self._currentAnim.frameCount - 1)
self._surf.blit(self._currentAnim.frames[frame][0], (0, 0)) self._surf.blit(self._currentAnim.frames[frame][0], (0, 0))
if frame == self._currentAnim.frameCount - 1: if frame == self._currentAnim.frameCount - 1:
self._game.onEvent(AnimFinish(self.objectID, self._currentAnim.animationID))
self._currentAnim = None self._currentAnim = None
self._animStart = None self._animStart = None
@ -62,24 +70,16 @@ class AnimatedObject:
""" """
self._animations.update({animation.animationID: animation}) self._animations.update({animation.animationID: animation})
def playAnim(self, animationID: str): def playAnim(self, animationID: str, overrideCurrentAnim=False):
""" """
Plays an animation. Plays an animation.
Args: Args:
animationID (str): The animation ID to play. animationID (str): The animation ID to play.
""" """
if self._currentAnim != None and not overrideCurrentAnim: return
self._animStart = time.perf_counter() self._animStart = time.perf_counter()
self._currentAnim = self._animations[animationID] self._currentAnim = self._animations[animationID]
self._game.onEvent(AnimStart(self.objectID, animationID))
def get_view(self):
print(f'get_view called')
return super().get_view()
def get_buffer(self):
print(f'get_buffer called')
return super().get_buffer()
def copy(self):
print(f'copy called')
return super().copy()

62
src/gameUtils/base.py Normal file
View File

@ -0,0 +1,62 @@
from .events import Timeout
from .anim import AnimatedObject
import tomllib
import time
class Game:
def __init__(self, surface):
"""
Initialises some things for the game developers.
Args:
surface (pygame.Surface): The surface the game devs draw on.
"""
self.surf = surface
self.size = self.surf.size
self.pm = None
# Holds all the timeouts that haven't been fired yet
self._timeouts = []
with open('./game.toml', 'r') as f:
self.cfg = tomllib.loads(f.read())
def update(self):
"""
Updates some core things in the background.
"""
for timeout in self._timeouts.copy():
if timeout.fireOn <= time.perf_counter():
self.onEvent(timeout)
self._timeouts.remove(timeout)
def onEvent(self, event):
pass
def close(self):
pass
def createAnimObj(self, *args, **kwargs):
"""
Creates an animated object.
Args:
objectID (str): The ID of the object.
baseFrame (str): The path to the base frame.
"""
return AnimatedObject(self, *args, **kwargs)
def timeout(self, id: str, delay: float):
"""
Fires a Timeout event with the specified ID
after the specified delay.
Args:
id (str): The timeout ID.
delay (float): How long (in seconds)
to wait before firing.
"""
self._timeouts.append(Timeout(id, time.perf_counter()+delay))

36
src/gameUtils/events.py Normal file
View File

@ -0,0 +1,36 @@
import time
class _event:
def __init__(self):
self.type = self.__class__
class AnimStart(_event):
def __init__(self, objectID, animationID):
super().__init__()
self.objectID = objectID
self.animationID = animationID
def __repr__(self):
return f'<AnimFinish | {self.objectID=} | {self.animationID=}>'
class AnimFinish(_event):
def __init__(self, objectID, animationID):
super().__init__()
self.objectID = objectID
self.animationID = animationID
def __repr__(self):
return f'<AnimFinish | {self.objectID=} | {self.animationID=}>'
class Timeout(_event):
def __init__(self, timeoutID, fireOn):
super().__init__()
# The timeout ID specified by the user
self.timeoutID = timeoutID
# When the event should be fired
self.fireOn = fireOn
# When it was created
self.created = time.perf_counter()
def __repr__(self):
return f'<Timeout | {self.timeoutID=} | {self.fireOn=} | {self.created=}>'

22
src/gameUtils/utils.py Normal file
View File

@ -0,0 +1,22 @@
import pygame
def centre(surface: pygame.Surface, size: tuple[int, int]) -> pygame.Surface:
"""
Centres a surface within a given rectangle.
Args:
surface: The surface to be centred.
size: The size of the rectangle the surface will be centred in.
Returns:
pygame.Surface
"""
surf = pygame.Surface(size)
offX = surf.size[0]//2 - surface.size[0]//2
offY = surf.size[1]//2 - surface.size[1]//2
surf.blit(surface, (offX, offY))
return surf

View File

@ -1,14 +0,0 @@
import pygame
def centre(surface: pygame.Surface, rect: tuple[int, int, int, int]) -> pygame.Surface:
"""
Centres a surface within a given rectangle.
Args:
surface: The surface to be centred.
rect: The rectangle the surface will be centred in.
Returns:
pygame.Surface
"""
pass