10 Commits

12 changed files with 166 additions and 67 deletions

View File

@@ -11,7 +11,6 @@ if __name__ == '__main__':
enable_dev = False enable_dev = False
resolution = 240 resolution = 240
# enable dev mode if --dev argument is passed
if len(sys.argv) > 0: if len(sys.argv) > 0:
for arg in sys.argv: for arg in sys.argv:
if arg == '--delete-save': if arg == '--delete-save':
@@ -19,8 +18,10 @@ if __name__ == '__main__':
os.remove(save_dir + '/save.json') os.remove(save_dir + '/save.json')
if '--res=' in arg: if '--res=' in arg:
resolution = int(arg.split('=')[1]) resolution = int(arg.split('=')[1])
if arg == '--dev':
enable_dev = True
game.start_game(resolution) game.start_game(resolution=resolution, dev=enable_dev)
pygame.quit() pygame.quit()
sys.exit() sys.exit()

View File

@@ -11,9 +11,20 @@ def reboot_system():
def shutdown_system(): def shutdown_system():
os.system('sudo shutdown now') os.system('sudo shutdown now')
def update(): def update():
pygame.quit()
os.system('bash ~/update.sh') os.system('bash ~/update.sh')
sys.exit(1) sys.exit(1)
def restart_app(): def restart_app():
sys.exit(1) sys.exit(1)
def show_black():
return 'show_black'
def quit():
sys.exit(0)

View File

@@ -0,0 +1,33 @@
import pygame
from pocket_friends.elements import surface
class Surface(surface.GameSurface):
def __init__(self, game_res, resources_dir, game_fps, **kwargs):
super().__init__(game_res, resources_dir, game_fps)
self.game_fps = game_fps
self.frames = -3 * game_fps
self.delay = 1
self.font = pygame.font.Font(resources_dir + '/fonts/5Pts5.ttf', 10)
self.title = pygame.image.load(resources_dir + '/images/debug/invalid.png').convert_alpha()
self.next_surface = '_dev_menu'
def update(self):
self.preprocess()
self.fill((0, 0, 0))
text_1 = self.font.render('Press B', False, (64, 64, 64))
text_2 = self.font.render('to return', False, (64, 64, 64))
if self.frames < 0:
self.blit(text_1, (3, 20))
self.blit(text_2, (3, 40))
self.frames += 1
if self.frames > self.game_fps:
self.frames = 0
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_b:
self.running = False

View File

@@ -1,13 +1,15 @@
import pygame import pygame
from pocket_friends.elements import surface from pocket_friends.elements import surface
from pocket_friends.development.sprites import FunctionSelector from pocket_friends._development._sprites import FunctionSelector
import pocket_friends.development.dev as dev import pocket_friends._development._dev as dev
dev_functions = { dev_functions = {
'Restart': 'reboot_system', 'Restart': 'reboot_system',
'Shutdown': 'shutdown_system', 'Shutdown': 'shutdown_system',
'Update': 'update', 'Update': 'update',
'Re-open App': 'restart_app' 'Re-open App': 'restart_app',
'Black screen': 'show_black',
'!!! Close App': 'quit'
} }
@@ -18,7 +20,7 @@ class Surface(surface.GameSurface):
self.game_fps = game_fps self.game_fps = game_fps
self.delay = 1 self.delay = 1
self.font = pygame.font.Font(resources_dir + '/fonts/5Pts5.ttf', 10) self.font = pygame.font.Font(resources_dir + '/fonts/5Pts5.ttf', 10)
self.bg = pygame.image.load(self.resource_dir + '/images/dev_menu/dev_bg.png').convert_alpha() self.background = pygame.image.load(self.resource_dir + '/images/dev_menu/dev_bg.png').convert_alpha()
functions = [] functions = []
for key in dev_functions.keys(): for key in dev_functions.keys():
@@ -29,7 +31,10 @@ class Surface(surface.GameSurface):
def execute(self): def execute(self):
executing_function = getattr(dev, dev_functions.get(self.function_selector.get_function())) executing_function = getattr(dev, dev_functions.get(self.function_selector.get_function()))
executing_function() output = executing_function()
if output == 'show_black':
self.next_surface = '_black_screen'
self.running = False
def update(self): def update(self):
self.preprocess() self.preprocess()

View File

@@ -6,47 +6,53 @@ from ..io.input_handler import InputHandler
class GameSurface(pygame.Surface): class GameSurface(pygame.Surface):
""" """
Class to be used as the backbone of all game surfaces. Class to be used as the backbone of all game surfaces.
The GameSurface class is what the game uses to draw all other elements on top of. It controls a number of game
operations, including input handling, frame rate limiting, and surface switching. It is a child class of Pygame's
Surface class and utilizes Pygame's sprite handling along with the ability to blit certain things on the screen
in order to draw elements easily.
Attributes: Attributes:
running (bool): Boolean to tell whether the surface is running or not. running: Boolean to tell whether the surface is running or not.
next_surface (:obj:`str`): What the next surface should be after halting. next_surface: String that represents the next surface to be switched to after halting.
resource_dir (:obj:`str`): The path of the game's main resource directory. resource_dir: String that contains the path of the game's main resource directory.
game_fps (int): How many frames per second the game will run at. game_fps: An integer value of how many frames per second the game will run at.
additional_args (dict): Additional arguments to send to the next surface after halting. additional_args: Dictionary of additional arguments to send to the next surface after halting.
bg (:obj:`pygame.Surface`): The background of the surface. background: A Pygame surface that will be drawn behind all other elements.
""" """
def __init__(self, game_res, resources_dir, game_fps): def __init__(self, game_res: tuple, resources_dir: str, game_fps: int):
""" """
Create a GameSurface object. Create a GameSurface object.
Args: Args:
game_res (int): The internal resolution of the surface. game_res: The internal resolution of the surface.
resources_dir (:obj:`str`): The path of the game's main resource directory. resources_dir: The path of the game's main resource directory.
game_fps: (int): How many frames per second the game will run at. game_fps: How many frames per second the game will run at.
""" """
super().__init__(game_res, pygame.SRCALPHA) super().__init__(game_res, pygame.SRCALPHA)
self.running = True self.running = True # Surfaces should be running by default
self.next_surface = None self.next_surface = None
self.resource_dir = resources_dir self.resource_dir = resources_dir
self._clock = pygame.time.Clock()
self.game_fps = game_fps self.game_fps = game_fps
self._input_handler = InputHandler(self._clock)
self.additional_args = {} self.additional_args = {}
self.dev_override = False self.dev_override = False
self.bg = pygame.image.load(self.resource_dir + '/images/bg.png').convert_alpha() self.background = pygame.image.load(self.resource_dir + '/images/bg.png').convert_alpha()
self.sprites = pygame.sprite.Group()
self._clock = pygame.time.Clock()
self._input_handler = InputHandler(self._clock)
self._sprites = pygame.sprite.Group()
def preprocess(self): def preprocess(self):
""" """
Advance the surface by one frame and draw the background. Draw the surface background and advance all the surface's sprites by one frame; Run the input handler.
""" """
self._clock.tick(self.game_fps) self._clock.tick(self.game_fps)
self.blit(self.bg, (0, 0)) self.blit(self.background, (0, 0))
self.sprites.update() self._sprites.update()
self.sprites.draw(self) self._sprites.draw(self)
self._input_handler.update() self._input_handler.update()
if self._input_handler.dev_found: if self._input_handler.dev_found:
self.next_surface = 'dev_menu'
self.dev_override = True self.dev_override = True
self.running = False self.running = False

View File

@@ -1,22 +1,26 @@
"""Main module for the game. Runs setting up the Pygame window and handles scene switching."""
import pygame import pygame
import os import os
import pocket_friends import pocket_friends
import importlib import importlib
valid_surfaces = [ valid_surfaces = [
'dev_menu', '_dev_menu',
'_black_screen',
'_error_screen',
'title', 'title',
'egg_select', 'egg_select',
'selection_info', 'selection_info',
'error_screen'
] ]
# Add all the surface modules to a dictionary for easy switching # Add all the surface modules to a dictionary for easy switching
surface_modules = {'dev_menu': importlib.import_module('pocket_friends.development.{0}'.format('dev_menu'))} surface_modules = {}
for module in valid_surfaces: for module in valid_surfaces:
if module != 'dev_menu': if module[0] == '_':
surface_modules[module] = importlib.import_module('pocket_friends._development.surfaces.{0}'.format(module))
else:
surface_modules[module] = importlib.import_module('pocket_friends.surfaces.{0}'.format(module)) surface_modules[module] = importlib.import_module('pocket_friends.surfaces.{0}'.format(module))
starting_surface = 'title'
# FPS for the game to run at. # FPS for the game to run at.
game_fps = 16 game_fps = 16
@@ -31,12 +35,13 @@ resources_dir = script_dir + '/resources'
os.environ['SDL_FBDEV'] = '/dev/fb1' os.environ['SDL_FBDEV'] = '/dev/fb1'
def start_game(resolution=240): def start_game(resolution: int, dev: bool):
""" """
Starts the game. Starts the game.
Args: Args:
resolution (int, optional): Resolution to display the game at. Defaults to 240. resolution: Resolution to display the game at.
dev: Boolean to enable the developer menu at start or not
""" """
pygame.init() pygame.init()
@@ -44,6 +49,11 @@ def start_game(resolution=240):
# Hide the cursor for the Pi display. # Hide the cursor for the Pi display.
pygame.mouse.set_visible(False) pygame.mouse.set_visible(False)
if dev:
starting_surface = '_dev_menu'
else:
starting_surface = 'title'
window = pygame.display.set_mode((resolution, resolution)) window = pygame.display.set_mode((resolution, resolution))
surface = surface_modules.get(starting_surface).Surface((game_res, game_res), resources_dir, game_fps) surface = surface_modules.get(starting_surface).Surface((game_res, game_res), resources_dir, game_fps)
@@ -63,15 +73,21 @@ def start_game(resolution=240):
frame = pygame.transform.scale(surface, (resolution, resolution)) frame = pygame.transform.scale(surface, (resolution, resolution))
window.blit(frame, frame.get_rect()) window.blit(frame, frame.get_rect())
# When the current surface is not running, check to make sure that the next surface will be valid
if not surface.running: if not surface.running:
# Force the dev menu to appear if the flag has been passed
if surface.dev_override: if surface.dev_override:
next_surface = 'dev_menu' next_surface = '_dev_menu'
else: else:
next_surface = surface.next_surface next_surface = surface.next_surface
additional_args = surface.additional_args
# Send to the error screen if the given surface isn't a valid one
if next_surface not in valid_surfaces: if next_surface not in valid_surfaces:
print(next) next_surface = '_error_screen'
next_surface = 'error_screen'
# Get the additional args to pass on from the ending surface to the next one
additional_args = surface.additional_args
# Create the new surface and pass through the additional argss
surface = surface_modules.get(next_surface).Surface((game_res, game_res), resources_dir, surface = surface_modules.get(next_surface).Surface((game_res, game_res), resources_dir,
game_fps, **additional_args) game_fps, **additional_args)
pygame.display.flip() pygame.display.flip()

View File

@@ -48,7 +48,7 @@ class Surface(surface.GameSurface):
egg.rect.y = y egg.rect.y = y
# Add the egg to the sprite list. # Add the egg to the sprite list.
self.sprites.add(egg) self._sprites.add(egg)
self.selected_egg = 0 self.selected_egg = 0
self.selected_color = '' self.selected_color = ''

View File

@@ -1,49 +1,63 @@
"""Module for selection info. Shows egg stats after an egg has been selected from the starting
screen. Contains the surface object to be rendered."""
import pygame import pygame
from pocket_friends.elements import sprites from pocket_friends.elements import sprites
from pocket_friends.elements import surface from pocket_friends.elements import surface
class Surface(surface.GameSurface): class Surface(surface.GameSurface):
def __init__(self, game_res, resources_dir, game_fps, **kwargs): """
Surface object for the selection info screen. Contains the selected egg, egg properties, and description in a
scrollable text box. Child class of surface.GameSurface.
"""
def __init__(self, game_res: tuple, resources_dir: str, game_fps: int, **kwargs: str):
"""
Create a selection info surface object.
Args:
game_res: The internal resolution of the surface.
resources_dir: The path of the game's main resource directory.
game_fps: How many frames per second the game will run at.
Keyword Args:
selected_egg: The egg that was selected by the previous screen.
"""
super().__init__(game_res, resources_dir, game_fps) super().__init__(game_res, resources_dir, game_fps)
preselected_color = None self._selected_egg = None
for key in kwargs.keys():
if key == 'selected_color':
preselected_color = kwargs.get(key)
self.selected_egg = None
for key in kwargs.keys(): for key in kwargs.keys():
if key == 'selected_egg': if key == 'selected_egg':
self.selected_egg = kwargs.get(key) self._selected_egg = kwargs.get(key)
egg = sprites.SelectionEgg(self.selected_egg, resources_dir) egg = sprites.SelectionEgg(self._selected_egg, resources_dir)
egg.rect.x = 8 egg.rect.x = 8
egg.rect.y = 3 egg.rect.y = 3
self.sprites.add(egg) self._sprites.add(egg)
self.info_text = sprites.InfoText(resources_dir, game_res[0], egg.description) self._info_text = sprites.InfoText(resources_dir, game_res[0], egg.description)
self.info_icons = sprites.EggInfo(resources_dir, egg.contentedness, egg.metabolism, (32, 4)) self._info_icons = sprites.EggInfo(resources_dir, egg.contentedness, egg.metabolism, (32, 4))
def update(self): def update(self):
"""
Draw objects on the screen and advance the surface logic by one frame; Handle user input.
"""
self.preprocess() self.preprocess()
self.info_text.draw(self) self._info_text.draw(self)
self.info_icons.draw(self) self._info_icons.draw(self)
for event in pygame.event.get(): for event in pygame.event.get():
if event.type == pygame.KEYDOWN: if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN: if event.key == pygame.K_DOWN:
# Scroll down on the info screen. self._info_text.scroll_down()
self.info_text.scroll_down()
if event.key == pygame.K_UP: if event.key == pygame.K_UP:
# Scroll up on the info screen. self._info_text.scroll_up()
self.info_text.scroll_up()
if event.key == pygame.K_a: if event.key == pygame.K_a:
self.running = False self.running = False
self.additional_args = {'selected_color': self.selected_egg} self.additional_args = {'selected_color': self._selected_egg}
self.next_surface = 'playground' self.next_surface = 'playground'
if event.key == pygame.K_b: if event.key == pygame.K_b:
self.running = False self.running = False
self.additional_args = {'selected_color': self.selected_egg} self.additional_args = {'selected_color': self._selected_egg}
self.next_surface = 'egg_select' self.next_surface = 'egg_select'

View File

@@ -1,24 +1,37 @@
"""Title screen module. Contains the surface object to be rendered on the screen."""
import pygame import pygame
from pocket_friends.elements import surface from pocket_friends.elements import surface
class Surface(surface.GameSurface): class Surface(surface.GameSurface):
def __init__(self, game_res, resources_dir, game_fps): """
Surface object for the title screen. Child class of surface.GameSurface.
"""
def __init__(self, game_res: tuple, resources_dir: str, game_fps: int):
"""
Create a title screen surface object.
Args:
game_res: The internal resolution of the surface.
resources_dir: The path of the game's main resource directory.
game_fps: How many frames per second the game will run at.
"""
super().__init__(game_res, resources_dir, game_fps) super().__init__(game_res, resources_dir, game_fps)
self.frames = 0 self._frames = 0 # Counter for the number of frames passed
self.delay = 1 self._delay = 1 # Delay in seconds that the title should stay on screen
self.title = pygame.image.load(resources_dir + '/images/title.png').convert_alpha() # Image of the title screen
self._title = pygame.image.load(resources_dir + '/images/title.png').convert_alpha()
def update(self): def update(self):
""" """
Advance the surface logic by one frame. Advance the surface logic by one frame.
""" """
self.preprocess() self.preprocess()
self.blit(self.title, (0, 0)) self.blit(self._title, (0, 0))
self.frames += 1 self._frames += 1
if self.frames > self.game_fps * self.delay: if self._frames > self.game_fps * self._delay:
self.next_surface = 'egg_select' self.next_surface = 'egg_select'
self.running = False self.running = False