Compare commits

..

8 Commits

3 changed files with 124 additions and 21 deletions

View File

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

View File

@ -1,9 +1,13 @@
from .events import Timeout
from .anim import AnimatedObject
import NoPELib
import tomllib
import time
import NoPELib
import pygame
from .events import Timeout
from .anim import AnimatedObject
from .utils import centre
class Game:
def __init__(self, surface):
"""
@ -16,27 +20,88 @@ class Game:
with open('./game.toml', 'r') as f:
self.cfg = tomllib.loads(f.read())
self.surf = surface
# The surface that gets drawn by the launcher.
# Contains the game surface, and overlays.
self._surf = surface
# The games serface
self.surf = pygame.Surface(self._surf.size)
self.size = self.surf.size
# Used for time delta, stores when the last frame was drawn
self._lastFrame = time.perf_counter()
# How many seconds it's been between frames
self.timeDelta = 0
# Pre-render semi-transparent black surface
self._dimSurf = pygame.Surface(self._surf.size)
self._dimSurf.set_alpha(128)
pygame.draw.rect(self._dimSurf, (50, 50, 50), (0, 0, self.size[0], self.size[1]))
self.pm = NoPELib.PlayersManager(self.cfg['name'], playersPath='../players.json')
# Holds all the timeouts that haven't been fired yet
self._timeouts = []
# The following are used by self.popup() to halt some events
self._haltUpdate = False
self._haltEvents = False
# Will become a pygame.Surface with the popup contents
self._popupMenu = None
def update(self):
"""
Updates some core things in the background.
Intended to be overridden by the game developer.
See BaseGame for documentation.
"""
def _update(self):
"""
Updates some core things in the background, and calls update()
"""
# Handle timeouts
for timeout in self._timeouts.copy():
if timeout.fireOn <= time.perf_counter():
self.onEvent(timeout)
self._timeouts.remove(timeout)
# Game update
if not self._haltUpdate:
self.update()
# Draw the game surface onto the main surface
self._surf.blit(self.surf, (0, 0))
# If there's a popup
if self._popupMenu is not None:
# Dim the screen
self._surf.blit(self._dimSurf, (0, 0))
self._surf.blit(centre(self._popupMenu, self.size), (0, 0))
self.timeDelta = time.perf_counter() - self._lastFrame
self._lastFrame = time.perf_counter()
def onEvent(self, event):
pass
"""
Intended to be overridden by the game developer.
See BaseGame for documentation.
"""
def _onEvent(self, event):
"""
Updates some core things in the background, and calls onEvent()
"""
if not self._haltEvents:
self.onEvent(event)
if event.type == pygame.KEYDOWN and self._popupMenu is not None:
if event.key == 13 and event.mod & 0b10000000: # R-CTRL + ENTER
self._popupMenu = None
self._haltUpdate = False
self._haltEvents = False
def close(self):
pass
"""
Intended to be overridden by the game developer.
See BaseGame for documentation.
"""
def createAnimObj(self, *args, **kwargs):
"""
@ -62,20 +127,59 @@ class Game:
self._timeouts.append(Timeout(id, time.perf_counter()+delay))
def awaitingTimeout(self, id: str):
def awaitingTimeout(self, timeoutID: str):
"""
Tells you if a timeout ID is on the timeout stack.
Args:
id (str): The timeout ID.
timeoutID (str): The timeout ID.
Returns:
bool: True if there is a timeout with that ID
ID on the stack, False otherwise.
"""
return any([timeout.timeoutID == id for timeout in self._timeouts])
return any(timeout.timeoutID == timeoutID for timeout in self._timeouts)
# TODO: Add popup method
def popup(self, title: str, message: str, haltUpdate: bool=False, haltEvents: bool=True):
"""
Pops up a dialogue box.
# TODO: add punish(player, intensity)
Args:
title (str): The big "title" text to be displayed.
message (str): The main body text to be displayed.
haltUpdate (bool): If True, the games update() method will not be called until
the popup is dismissed. Default: False.
haltEvents (bool): If True, the games onEvent() method will not be called until
the popup is dismissed. Default: True.
"""
POPUP_MARGINS = 10
FONT_BIG = pygame.font.SysFont('', 50)
FONT_NORM = pygame.font.SysFont('', 32)
titleSurf = FONT_BIG.render(title, True, (128, 128, 128))
messageSurf = FONT_NORM.render(message, True, (128, 128, 128))
w = max(titleSurf.get_width(), messageSurf.get_width())
w += POPUP_MARGINS*2
h = titleSurf.get_height() + messageSurf.get_height()
h += POPUP_MARGINS*3
self._haltUpdate = haltUpdate
self._haltEvents = haltEvents
self._popupMenu = pygame.Surface((w, h))
self._popupMenu.fill((0, 0, 0))
self._popupMenu.blit(centre(titleSurf, (w, titleSurf.get_height())), (0, POPUP_MARGINS))
self._popupMenu.blit(centre(messageSurf, (w, messageSurf.get_height())), (0, titleSurf.get_height()+POPUP_MARGINS*2))
def punish(self, player, intensity: float):
"""
Handles punishing players for most games.
Handles games preferences on PDO order?
Handles auto popups for messaged events.
Args:
player (NoPELib.Player): The player to punish.
intensity (float): The intensity to punish the player.
"""

View File

@ -12,11 +12,10 @@ def centre(surface: pygame.Surface, size: tuple[int, int]) -> pygame.Surface:
pygame.Surface
"""
surf = pygame.Surface(size)
surf = pygame.Surface(size, pygame.SRCALPHA, 32)
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