Compare commits
23 Commits
187baf6f3e
...
master
Author | SHA1 | Date | |
---|---|---|---|
3fde1996ca | |||
eef3a8756d | |||
8675caaca6 | |||
9fd2bc03df | |||
680a2cab75 | |||
9669e6185d | |||
8c49c62f66 | |||
30e25999c4 | |||
f765bb3dcb | |||
86e8c51494 | |||
f3751def40 | |||
4ba12d5078 | |||
e5c17b60e7 | |||
d7a01340b7 | |||
ad97725634 | |||
2def4f846a | |||
d4ff6d0786 | |||
7c49424350 | |||
1c467371a8 | |||
8a34ed7c01 | |||
b6432e233a | |||
4249a7c3f1 | |||
bcf933992e |
@@ -1,5 +1,5 @@
|
||||
|
||||

|
||||

|
||||
|
||||
[](LICENSE)
|
||||
|
||||
|
@@ -11,7 +11,6 @@ if __name__ == '__main__':
|
||||
enable_dev = False
|
||||
resolution = 240
|
||||
|
||||
# enable dev mode if --dev argument is passed
|
||||
if len(sys.argv) > 0:
|
||||
for arg in sys.argv:
|
||||
if arg == '--delete-save':
|
||||
@@ -19,8 +18,10 @@ if __name__ == '__main__':
|
||||
os.remove(save_dir + '/save.json')
|
||||
if '--res=' in arg:
|
||||
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()
|
||||
sys.exit()
|
||||
|
30
pocket_friends/_development/_dev.py
Normal file
30
pocket_friends/_development/_dev.py
Normal file
@@ -0,0 +1,30 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pygame
|
||||
|
||||
|
||||
def reboot_system():
|
||||
os.system('sudo reboot')
|
||||
|
||||
|
||||
def shutdown_system():
|
||||
os.system('sudo shutdown now')
|
||||
|
||||
|
||||
def update():
|
||||
pygame.quit()
|
||||
os.system('bash ~/update.sh')
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def restart_app():
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def show_black():
|
||||
return 'show_black'
|
||||
|
||||
|
||||
def quit():
|
||||
sys.exit(0)
|
34
pocket_friends/_development/_sprites.py
Normal file
34
pocket_friends/_development/_sprites.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import pygame
|
||||
|
||||
|
||||
class FunctionSelector:
|
||||
|
||||
def __init__(self, resources_dir, game_res, functions):
|
||||
self.font = pygame.font.Font(resources_dir + '/fonts/5Pts5.ttf', 10)
|
||||
self.functions = functions
|
||||
self.max_lines = 6 # Max number of lines to be shown on screen at a time.
|
||||
self.offset = 0
|
||||
self.game_res = game_res
|
||||
|
||||
self.selected = 0
|
||||
self.max_index = len(self.functions) - 1
|
||||
self.selector = pygame.image.load(resources_dir + '/images/dev_menu/selector.png').convert_alpha()
|
||||
|
||||
def draw(self, surface):
|
||||
for i in range(self.max_index + 1):
|
||||
text = self.font.render(self.functions[i], False, (0, 0, 0))
|
||||
surface.blit(text, (8, (-3 + (i * 6))))
|
||||
surface.blit(self.selector, (0, (self.selected * 6)))
|
||||
|
||||
def scroll_down(self):
|
||||
self.selected += 1
|
||||
if self.selected > self.max_index:
|
||||
self.selected = self.max_index
|
||||
|
||||
def scroll_up(self):
|
||||
self.selected -= 1
|
||||
if self.selected < 0:
|
||||
self.selected = 0
|
||||
|
||||
def get_function(self):
|
||||
return self.functions[self.selected]
|
33
pocket_friends/_development/surfaces/_black_screen.py
Normal file
33
pocket_friends/_development/surfaces/_black_screen.py
Normal 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
|
58
pocket_friends/_development/surfaces/_dev_menu.py
Normal file
58
pocket_friends/_development/surfaces/_dev_menu.py
Normal file
@@ -0,0 +1,58 @@
|
||||
import pygame
|
||||
from pocket_friends.elements import surface
|
||||
from pocket_friends._development._sprites import FunctionSelector
|
||||
import pocket_friends._development._dev as dev
|
||||
|
||||
dev_functions = {
|
||||
'Restart': 'reboot_system',
|
||||
'Shutdown': 'shutdown_system',
|
||||
'Update': 'update',
|
||||
'Re-open App': 'restart_app',
|
||||
'Black screen': 'show_black',
|
||||
'!!! Close App': 'quit'
|
||||
}
|
||||
|
||||
|
||||
class Surface(surface.GameSurface):
|
||||
def __init__(self, game_res, resources_dir, game_fps, **kwargs):
|
||||
super().__init__(game_res, resources_dir, game_fps)
|
||||
self.frames = 1
|
||||
self.game_fps = game_fps
|
||||
self.delay = 1
|
||||
self.font = pygame.font.Font(resources_dir + '/fonts/5Pts5.ttf', 10)
|
||||
self.background = pygame.image.load(self.resource_dir + '/images/dev_menu/dev_bg.png').convert_alpha()
|
||||
|
||||
functions = []
|
||||
for key in dev_functions.keys():
|
||||
functions.append(key)
|
||||
|
||||
self.function_selector = FunctionSelector(resources_dir, game_res, functions)
|
||||
|
||||
def execute(self):
|
||||
|
||||
executing_function = getattr(dev, dev_functions.get(self.function_selector.get_function()))
|
||||
output = executing_function()
|
||||
if output == 'show_black':
|
||||
self.next_surface = '_black_screen'
|
||||
self.running = False
|
||||
|
||||
def update(self):
|
||||
self.preprocess()
|
||||
|
||||
text = self.font.render('f: {0}'.format(self.frames), False, (128, 128, 128))
|
||||
self.blit(text, (3, 68))
|
||||
self.function_selector.draw(self)
|
||||
|
||||
self.frames += 1
|
||||
self.frames %= self.game_fps
|
||||
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_UP:
|
||||
self.function_selector.scroll_up()
|
||||
if event.key == pygame.K_DOWN:
|
||||
self.function_selector.scroll_down()
|
||||
if event.key == pygame.K_a:
|
||||
self.execute()
|
||||
if event.key == pygame.K_b:
|
||||
self.running = False
|
@@ -6,41 +6,53 @@ from ..io.input_handler import InputHandler
|
||||
class GameSurface(pygame.Surface):
|
||||
"""
|
||||
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:
|
||||
running (bool): Boolean to tell whether the surface is running or not.
|
||||
next_surface (:obj:`str`): What the next surface should be after halting.
|
||||
resource_dir (:obj:`str`): The path of the game's main resource directory.
|
||||
game_fps (int): How many frames per second the game will run at.
|
||||
additional_args (dict): Additional arguments to send to the next surface after halting.
|
||||
running: Boolean to tell whether the surface is running or not.
|
||||
next_surface: String that represents the next surface to be switched to after halting.
|
||||
resource_dir: String that contains the path of the game's main resource directory.
|
||||
game_fps: An integer value of how many frames per second the game will run at.
|
||||
additional_args: Dictionary of additional arguments to send to the next surface after halting.
|
||||
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.
|
||||
Args:
|
||||
game_res (int): The internal resolution of the surface.
|
||||
resources_dir (:obj:`str`): The path of the game's main resource directory.
|
||||
game_fps: (int): How many frames per second the game will run at.
|
||||
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, pygame.SRCALPHA)
|
||||
self.running = True
|
||||
self.running = True # Surfaces should be running by default
|
||||
self.next_surface = None
|
||||
self.resource_dir = resources_dir
|
||||
self._clock = pygame.time.Clock()
|
||||
self.game_fps = game_fps
|
||||
self._input_handler = InputHandler(self._clock)
|
||||
self.additional_args = {}
|
||||
self.dev_override = False
|
||||
|
||||
self._bg = pygame.image.load(self.resource_dir + '/images/bg.png').convert_alpha()
|
||||
self.sprites = pygame.sprite.Group()
|
||||
self.background = pygame.image.load(self.resource_dir + '/images/bg.png').convert_alpha()
|
||||
|
||||
self._clock = pygame.time.Clock()
|
||||
self._input_handler = InputHandler(self._clock)
|
||||
self._sprites = pygame.sprite.Group()
|
||||
|
||||
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.blit(self._bg, (0, 0))
|
||||
self.sprites.update()
|
||||
self.sprites.draw(self)
|
||||
self.blit(self.background, (0, 0))
|
||||
self._sprites.update()
|
||||
self._sprites.draw(self)
|
||||
|
||||
self._input_handler.update()
|
||||
if self._input_handler.dev_found:
|
||||
self.dev_override = True
|
||||
self.running = False
|
||||
|
@@ -1,21 +1,26 @@
|
||||
"""Main module for the game. Runs setting up the Pygame window and handles scene switching."""
|
||||
|
||||
import pygame
|
||||
import os
|
||||
import pocket_friends
|
||||
import importlib
|
||||
|
||||
|
||||
valid_surfaces = [
|
||||
'_dev_menu',
|
||||
'_black_screen',
|
||||
'_error_screen',
|
||||
'title',
|
||||
'egg_select',
|
||||
'selection_info',
|
||||
'error_screen'
|
||||
]
|
||||
|
||||
# Add all the surface modules to a dictionary for easy switching
|
||||
surface_modules = {}
|
||||
for module in valid_surfaces:
|
||||
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))
|
||||
starting_surface = 'title'
|
||||
|
||||
# FPS for the game to run at.
|
||||
game_fps = 16
|
||||
@@ -30,12 +35,13 @@ resources_dir = script_dir + '/resources'
|
||||
os.environ['SDL_FBDEV'] = '/dev/fb1'
|
||||
|
||||
|
||||
def start_game(resolution=240):
|
||||
def start_game(resolution: int, dev: bool):
|
||||
"""
|
||||
Starts the game.
|
||||
|
||||
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()
|
||||
@@ -43,6 +49,11 @@ def start_game(resolution=240):
|
||||
# Hide the cursor for the Pi display.
|
||||
pygame.mouse.set_visible(False)
|
||||
|
||||
if dev:
|
||||
starting_surface = '_dev_menu'
|
||||
else:
|
||||
starting_surface = 'title'
|
||||
|
||||
window = pygame.display.set_mode((resolution, resolution))
|
||||
surface = surface_modules.get(starting_surface).Surface((game_res, game_res), resources_dir, game_fps)
|
||||
|
||||
@@ -62,11 +73,21 @@ def start_game(resolution=240):
|
||||
frame = pygame.transform.scale(surface, (resolution, resolution))
|
||||
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:
|
||||
# Force the dev menu to appear if the flag has been passed
|
||||
if surface.dev_override:
|
||||
next_surface = '_dev_menu'
|
||||
else:
|
||||
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:
|
||||
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,
|
||||
game_fps, **additional_args)
|
||||
pygame.display.flip()
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import pygame
|
||||
|
||||
from collections import deque
|
||||
|
||||
class InputHandler:
|
||||
"""
|
||||
@@ -24,6 +24,12 @@ class InputHandler:
|
||||
self.clock = pygame_clock
|
||||
self.tick_check = tick_check
|
||||
self.last_input_tick = 0
|
||||
self.dev_check = deque()
|
||||
self.dev_code = deque()
|
||||
for button in [pygame.K_DOWN, pygame.K_DOWN, pygame.K_UP, pygame.K_UP, pygame.K_DOWN, pygame.K_LEFT,
|
||||
pygame.K_RIGHT, pygame.K_LEFT, pygame.K_a]:
|
||||
self.dev_code.append(button)
|
||||
self.dev_found = False
|
||||
|
||||
def create_event(self, pressed_button):
|
||||
"""
|
||||
@@ -37,6 +43,9 @@ class InputHandler:
|
||||
if pygame.time.get_ticks() - self.last_input_tick > self.clock.get_time() * 2:
|
||||
pygame.event.post(pygame.event.Event(pygame.KEYDOWN, {'key': pressed_button}))
|
||||
pygame.event.post(pygame.event.Event(pygame.KEYUP, {'key': pressed_button}))
|
||||
self.dev_check.append(pressed_button)
|
||||
if len(self.dev_check) > len(self.dev_code):
|
||||
self.dev_check.popleft()
|
||||
else:
|
||||
pygame.event.post(pygame.event.Event(pygame.KEYDOWN, {'key': pressed_button}))
|
||||
pygame.event.post(pygame.event.Event(pygame.KEYUP, {'key': pressed_button}))
|
||||
@@ -70,3 +79,5 @@ class InputHandler:
|
||||
def update(self):
|
||||
"""Run either the GPIO handler or the keyboard handler to check for input and create events."""
|
||||
self.handle_keyboard()
|
||||
if self.dev_code == self.dev_check:
|
||||
self.dev_found = True
|
||||
|
BIN
pocket_friends/resources/images/dev_menu/dev_bg.png
Normal file
BIN
pocket_friends/resources/images/dev_menu/dev_bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
BIN
pocket_friends/resources/images/dev_menu/selector.png
Normal file
BIN
pocket_friends/resources/images/dev_menu/selector.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 839 B |
@@ -48,7 +48,7 @@ class Surface(surface.GameSurface):
|
||||
egg.rect.y = y
|
||||
|
||||
# Add the egg to the sprite list.
|
||||
self.sprites.add(egg)
|
||||
self._sprites.add(egg)
|
||||
|
||||
self.selected_egg = 0
|
||||
self.selected_color = ''
|
||||
|
@@ -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
|
||||
from pocket_friends.elements import sprites
|
||||
from pocket_friends.elements import surface
|
||||
|
||||
|
||||
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)
|
||||
|
||||
preselected_color = None
|
||||
for key in kwargs.keys():
|
||||
if key == 'selected_color':
|
||||
preselected_color = kwargs.get(key)
|
||||
|
||||
self.selected_egg = None
|
||||
self._selected_egg = None
|
||||
for key in kwargs.keys():
|
||||
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.y = 3
|
||||
self.sprites.add(egg)
|
||||
self._sprites.add(egg)
|
||||
|
||||
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_text = sprites.InfoText(resources_dir, game_res[0], egg.description)
|
||||
self._info_icons = sprites.EggInfo(resources_dir, egg.contentedness, egg.metabolism, (32, 4))
|
||||
|
||||
def update(self):
|
||||
"""
|
||||
Draw objects on the screen and advance the surface logic by one frame; Handle user input.
|
||||
"""
|
||||
self.preprocess()
|
||||
|
||||
self.info_text.draw(self)
|
||||
self.info_icons.draw(self)
|
||||
self._info_text.draw(self)
|
||||
self._info_icons.draw(self)
|
||||
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.KEYDOWN:
|
||||
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:
|
||||
# Scroll up on the info screen.
|
||||
self.info_text.scroll_up()
|
||||
self._info_text.scroll_up()
|
||||
if event.key == pygame.K_a:
|
||||
self.running = False
|
||||
self.additional_args = {'selected_color': self.selected_egg}
|
||||
self.additional_args = {'selected_color': self._selected_egg}
|
||||
self.next_surface = 'playground'
|
||||
if event.key == pygame.K_b:
|
||||
self.running = False
|
||||
self.additional_args = {'selected_color': self.selected_egg}
|
||||
self.additional_args = {'selected_color': self._selected_egg}
|
||||
self.next_surface = 'egg_select'
|
||||
|
@@ -1,24 +1,37 @@
|
||||
"""Title screen module. Contains the surface object to be rendered on the screen."""
|
||||
import pygame
|
||||
from pocket_friends.elements import surface
|
||||
|
||||
|
||||
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)
|
||||
|
||||
self.frames = 0
|
||||
self.delay = 1
|
||||
self._frames = 0 # Counter for the number of frames passed
|
||||
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):
|
||||
"""
|
||||
Advance the surface logic by one frame.
|
||||
"""
|
||||
self.preprocess()
|
||||
self.blit(self.title, (0, 0))
|
||||
self.blit(self._title, (0, 0))
|
||||
|
||||
self.frames += 1
|
||||
if self.frames > self.game_fps * self.delay:
|
||||
self._frames += 1
|
||||
if self._frames > self.game_fps * self._delay:
|
||||
self.next_surface = 'egg_select'
|
||||
self.running = False
|
||||
|
Reference in New Issue
Block a user