Compare commits

..

5 Commits

8 changed files with 132 additions and 72 deletions

View File

@ -0,0 +1 @@
"""Sub-module for use in the game. Helps with the drawing of various objects such as sprites and text boxes."""

View File

@ -4,53 +4,78 @@ import json
class SpriteSheet: class SpriteSheet:
""" """
Imports a sprite sheet as separate pygame images given an image file and a json file. Class to be used by sprites in order to give them a texture and an animation.
Attributes:
images (list) List of all the sprites in the animation separated from the sprite sheet.
""" """
def __init__(self, sprite_sheet, texture_json): def __init__(self, sprite_sheet, texture_json):
"""
Creates a sprite sheet given a sprite image and its corresponding JSON file.
Args:
sprite_sheet (str): The path of the sprite sheet image component.
texture_json (str): The path of the sprite sheet JSON component, contains the number of frames in the
sprite sheet, and the width and height of an individual sprite from the sprite sheet.
"""
# Load in whole sprite sheet as one image. # Load in whole sprite sheet as one image.
self.sprite_sheet = pygame.image.load(sprite_sheet).convert_alpha() sprite_sheet = pygame.image.load(sprite_sheet).convert_alpha()
self.images = [] self.images = []
print(type(self.images))
# Get the sprite sheet json file. # Get the sprite sheet json file.
with open(texture_json, 'r') as json_file: with open(texture_json, 'r') as json_file:
self.img_attrib = json.load(json_file) img_attrib = json.load(json_file)
json_file.close() json_file.close()
# Count for how many images have been added in the image list # Count for how many images have been added in the image list
image_count = 0 image_count = 0
# Get the sprite size as a tuple # Get the sprite size as a tuple
sprite_size = self.img_attrib['width'], self.img_attrib['height'] sprite_size = img_attrib['width'], img_attrib['height']
# Iterate through every image location on the sprite sheet given the sprite size # Iterate through every image location on the sprite sheet given the sprite size
for i in range(self.sprite_sheet.get_size()[1] // sprite_size[1]): for i in range(sprite_sheet.get_size()[1] // sprite_size[1]):
i *= sprite_size[1] i *= sprite_size[1]
for j in range(self.sprite_sheet.get_size()[0] // sprite_size[0]): for j in range(sprite_sheet.get_size()[0] // sprite_size[0]):
j *= sprite_size[0] j *= sprite_size[0]
# Create a new transparent surface # Create a new transparent surface
sprite = pygame.Surface(sprite_size, pygame.SRCALPHA) sprite = pygame.Surface(sprite_size, pygame.SRCALPHA)
# Blit the sprite onto the image # Blit the sprite onto the image
sprite.blit(self.sprite_sheet, (0, 0), (j, i, sprite_size[0], sprite_size[1])) sprite.blit(sprite_sheet, (0, 0), (j, i, sprite_size[0], sprite_size[1]))
# Add the image to the list of images # Add the image to the list of images
self.images.append(sprite) self.images.append(sprite)
image_count += 1 image_count += 1
# Break the loop if the specified number of frames has been reached. # Break the loop if the specified number of frames has been reached.
if image_count >= self.img_attrib['frames']: if image_count >= img_attrib['frames']:
break break
if image_count >= self.img_attrib['frames']: if image_count >= img_attrib['frames']:
break break
class SelectionEgg(pygame.sprite.Sprite): class SelectionEgg(pygame.sprite.Sprite):
""" """
Class for the eggs on the egg selection screen. Sprite to render the egg on the egg selection screen.
Attributes:
egg_color (str): The color of the egg (also its name).
description (str): The description of the egg to be displayed when selected.
contentedness (int): How likely the egg is to stay happy, ranges from 0-5.
metabolism (int): How quickly the egg will get hungry, ranges from 0-5.
rect (pygame.Rect): Pygame rectangle used to position the egg on screen.
""" """
def __init__(self, egg_color, resources_dir): def __init__(self, egg_color, resources_dir):
"""
Creates a SelectionEgg object given an egg color and a resource location.
Args:
egg_color (str): The color egg that should be rendered.
resources_dir (str): The path of the resources directory.
"""
pygame.sprite.Sprite.__init__(self) pygame.sprite.Sprite.__init__(self)
self.egg_color = egg_color self.egg_color = egg_color
@ -68,20 +93,21 @@ class SelectionEgg(pygame.sprite.Sprite):
# Load the egg from the given color and get the bounding rectangle for the image. # Load the egg from the given color and get the bounding rectangle for the image.
sprite_sheet = SpriteSheet(resources_dir + '/images/bloops/{0}/egg.png'.format(self.egg_color), sprite_sheet = SpriteSheet(resources_dir + '/images/bloops/{0}/egg.png'.format(self.egg_color),
resources_dir + '/images/bloops/{0}/egg.json'.format(self.egg_color)) resources_dir + '/images/bloops/{0}/egg.json'.format(self.egg_color))
self.images = sprite_sheet.images self._images = sprite_sheet.images
# Get the rectangle from the first image in the list # Get the rectangle from the first image in the list
self.rect = self.images[0].get_rect() self.rect = self._images[0].get_rect()
self.index = 0 print(type(self.rect))
self.image = self.images[self.index] self._index = 0
self.image = self._images[self._index]
def update(self): def update(self):
""" """
Updates the sprite object. Update the sprite to the next animation frame.
""" """
# Animate the sprite # Animate the sprite
self.index = (self.index + 1) % len(self.images) self._index = (self._index + 1) % len(self._images)
self.image = self.images[self.index] self.image = self._images[self._index]
class InfoText: class InfoText:

View File

@ -4,9 +4,11 @@ import json
class SaveData: class SaveData:
""" """
Class that represents the save data of the game. Class used to read and write save data for the game
"""
Attributes:
attributes (dict): Dictionary containing all the attributes to read and write from a save file.
"""
def __init__(self): def __init__(self):
""" """
Constructs the object with all starting values. Constructs the object with all starting values.

View File

@ -1,6 +1,6 @@
""" """
Module used to fake the RPi.GPIO module so that Dummy module that contains empty functions and variables that exist in RPi.GPIO. This module is to be imported
the program can be run without the actual hardware. if importing RPi.GPIO fails.
""" """
# Constants used by RPi.GPIO # Constants used by RPi.GPIO
@ -12,7 +12,11 @@ FALLING = 0
def setmode(new_mode): def setmode(new_mode):
""" """
Fake setmode function. Fake setmode function.
:param new_mode: Args:
new_mode:
Returns:
""" """
pass pass
@ -20,10 +24,14 @@ def setmode(new_mode):
def setup(channel, mode, initial=None, pull_up_down=None): def setup(channel, mode, initial=None, pull_up_down=None):
""" """
Fake setup function. Fake setup function.
:param channel: Args:
:param mode: channel:
:param initial: mode:
:param pull_up_down: initial:
pull_up_down:
Returns:
""" """
pass pass
@ -31,10 +39,14 @@ def setup(channel, mode, initial=None, pull_up_down=None):
def add_event_detect(channel, edge_type, callback=None, bouncetime=0): def add_event_detect(channel, edge_type, callback=None, bouncetime=0):
""" """
Fake function to add a non-existent event detect. Fake function to add a non-existent event detect.
:param channel: Args:
:param edge_type: channel:
:param callback: edge_type:
:param bouncetime: callback:
bouncetime:
Returns:
""" """
pass pass
@ -42,8 +54,11 @@ def add_event_detect(channel, edge_type, callback=None, bouncetime=0):
def event_detected(channel): def event_detected(channel):
""" """
Fake function to detect an event. Always returns false. Fake function to detect an event. Always returns false.
:param channel: Args:
:return: channel:
Returns:
""" """
return False return False
@ -51,6 +66,10 @@ def event_detected(channel):
def cleanup(channel=None): def cleanup(channel=None):
""" """
Fake cleanup function. Fake cleanup function.
:param channel: Args:
channel:
Returns:
""" """
pass pass

View File

@ -1,15 +1,19 @@
""" """Handle inputs from the GPIO pins on the Raspberry Pi and converting them to events to be used in other places (
Handle inputs from the GPIO pins on the Raspberry Pi and converting them to events to be used in other places (pygame, etc.) pygame, etc.)"""
"""
import importlib.util import importlib.util
# If the RPi.GPIO module is not found (aka the program is not running on a Pi), import the fake # If the RPi.GPIO module is not found (aka the program is not running on a Pi), import the fake
# GPIO module instead to prevent a crash. # GPIO module instead to prevent a crash.
ON_HARDWARE = None # Flag to tell other methods if the program is running on hardware or not
try: try:
importlib.util.find_spec('RPi.GPIO') importlib.util.find_spec('RPi.GPIO')
import RPi.GPIO as GPIO import RPi.GPIO as GPIO
ON_HARDWARE = True
except ImportError: except ImportError:
import pocket_friends.game_files.io.fake_gpio as GPIO import pocket_friends.game_files.io.fake_gpio as GPIO
ON_HARDWARE = False
# Dictionary of all the buttons used and what their corresponding GPIO codes are # Dictionary of all the buttons used and what their corresponding GPIO codes are
BUTTONS = { BUTTONS = {
@ -24,9 +28,7 @@ BUTTONS = {
def setup(): def setup():
""" """Prime the GPIO pins for reading the inputs of the buttons."""
Primes the GPIO pins for reading the inputs of the buttons.
"""
GPIO.setmode(GPIO.BOARD) GPIO.setmode(GPIO.BOARD)
GPIO.setup(BUTTONS.get('a'), GPIO.IN) GPIO.setup(BUTTONS.get('a'), GPIO.IN)
@ -47,16 +49,17 @@ def setup():
def teardown(): def teardown():
""" """Clean up the GPIO handler."""
Cleans up the GPIO handler.
"""
GPIO.cleanup() GPIO.cleanup()
def get_press(button): def get_press(button):
""" """
Returns true if a button has changed from not pressed to pressed. Checks if a given button code has been pressed and returns a bool depending on the state.
:param button: button to be detected Args:
:return: True if the button is has been pressed, False otherwise button: button to be detected
Returns: True if the button is has been pressed, False otherwise
""" """
return GPIO.event_detected(button) return GPIO.event_detected(button)

View File

@ -1,5 +1,4 @@
import pygame import pygame
import importlib.util
import pocket_friends.game_files.io.gpio_handler as gpio_handler import pocket_friends.game_files.io.gpio_handler as gpio_handler
@ -7,36 +6,40 @@ class InputHandler:
""" """
Class that is implemented into surfaces in order to control the Class that is implemented into surfaces in order to control the
pressing of buttons on both the real hardware and on a keyboard. pressing of buttons on both the real hardware and on a keyboard.
Attributes:
clock (pygame.time.Clock): Pygame clock used for input time calculations.
last_input_tick (int): The tick that the last input was registered on.
""" """
def __init__(self, pygame_clock): def __init__(self, pygame_clock):
"""
Create a InputHandler object using a given Pygame clock.
Args:
pygame_clock (pygame.time.Clock): A pygame clock to use as the clock for input time calculations.
"""
self.clock = pygame_clock self.clock = pygame_clock
# If not on actual hardware, fake the GPIO in order to get it working correctly.
try:
importlib.util.find_spec('RPi.GPIO')
import RPi.GPIO as GPIO
self.on_hardware = True
except ImportError:
import pocket_friends.game_files.io.fake_gpio as GPIO
self.on_hardware = False
self.last_input_tick = 0 self.last_input_tick = 0
def create_event(self, pressed_button): def create_event(self, pressed_button):
""" """
Creates a pygame event with a given keyboard code Create a pygame event given a GPIO code and post it to the pygame event handler.
:param pressed_button: Args:
pressed_button (int): The GPIO code to be registered and pressed.
""" """
# Register a button click so long as the last button click happened no less than two frames ago # Register a button click so long as the last button click happened no less than two frames ago
if pygame.time.get_ticks() - self.last_input_tick > self.clock.get_time() * 2 or not self.on_hardware: if pygame.time.get_ticks() - self.last_input_tick > self.clock.get_time() * 2 or not gpio_handler.ON_HARDWARE:
pygame.event.post(pygame.event.Event(pygame.KEYDOWN, {'key': pressed_button})) pygame.event.post(pygame.event.Event(pygame.KEYDOWN, {'key': pressed_button}))
pygame.event.post(pygame.event.Event(pygame.KEYUP, {'key': pressed_button})) pygame.event.post(pygame.event.Event(pygame.KEYUP, {'key': pressed_button}))
self.last_input_tick = pygame.time.get_ticks() self.last_input_tick = pygame.time.get_ticks()
def handle_gpio(self): def handle_gpio(self):
""" """
Handles getting GPIO button presses and making a pygame event when a press is detected. Handle GPIO events and create events for them.
""" """
for pressed_button in gpio_handler.BUTTONS: for pressed_button in gpio_handler.BUTTONS:
code = gpio_handler.BUTTONS.get(pressed_button) code = gpio_handler.BUTTONS.get(pressed_button)
@ -45,10 +48,8 @@ class InputHandler:
if gpio_handler.get_press(code): if gpio_handler.get_press(code):
self.create_event(code) self.create_event(code)
def keyboard_handler(self): def handle_keyboard(self):
""" """Handle keyboard presses and generate corresponding GPIO codes to create events."""
Simulates key presses to GPIO button presses. Also handles quitting the game.
"""
# Checks if a corresponding keyboard key has been pressed. If it has, emulate a button press. # Checks if a corresponding keyboard key has been pressed. If it has, emulate a button press.
for keyboard_event in pygame.event.get(): for keyboard_event in pygame.event.get():
@ -73,10 +74,8 @@ class InputHandler:
running = False running = False
def update(self): def update(self):
""" """Run either the GPIO handler or the keyboard handler to check for input and create events."""
Run the input handler and check for inputs. if gpio_handler.ON_HARDWARE:
"""
if self.on_hardware:
self.handle_gpio() self.handle_gpio()
else: else:
self.keyboard_handler() self.handle_keyboard()

View File

@ -1,5 +1,5 @@
import pygame import pygame
from . import sprites from ..elements import sprites
import pocket_friends.game_files.io.gpio_handler as gpio_handler import pocket_friends.game_files.io.gpio_handler as gpio_handler
from ..io.input_handler import InputHandler from ..io.input_handler import InputHandler

View File

@ -1,12 +1,22 @@
import pygame import pygame
from . import sprites from ..elements import sprites
import pocket_friends.game_files.io.gpio_handler as gpio_handler import pocket_friends.game_files.io.gpio_handler as gpio_handler
from .sprites import SelectionEgg
from ..io.input_handler import InputHandler from ..io.input_handler import InputHandler
class Surface(pygame.Surface): class Surface(pygame.Surface):
"""
"""
def __init__(self, window_size, resources_dir, game_fps, **kwargs): def __init__(self, window_size, resources_dir, game_fps, **kwargs):
"""
Args:
window_size:
resources_dir:
game_fps:
**kwargs:
"""
super().__init__(window_size, pygame.SRCALPHA) super().__init__(window_size, pygame.SRCALPHA)
self.name = 'selection_info' self.name = 'selection_info'
self.running = True self.running = True