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:
"""
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):
"""
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.
self.sprite_sheet = pygame.image.load(sprite_sheet).convert_alpha()
sprite_sheet = pygame.image.load(sprite_sheet).convert_alpha()
self.images = []
print(type(self.images))
# Get the sprite sheet 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()
# Count for how many images have been added in the image list
image_count = 0
# 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
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]
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]
# Create a new transparent surface
sprite = pygame.Surface(sprite_size, pygame.SRCALPHA)
# 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
self.images.append(sprite)
image_count += 1
# 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
if image_count >= self.img_attrib['frames']:
if image_count >= img_attrib['frames']:
break
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):
"""
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)
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.
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))
self.images = sprite_sheet.images
self._images = sprite_sheet.images
# Get the rectangle from the first image in the list
self.rect = self.images[0].get_rect()
self.index = 0
self.image = self.images[self.index]
self.rect = self._images[0].get_rect()
print(type(self.rect))
self._index = 0
self.image = self._images[self._index]
def update(self):
"""
Updates the sprite object.
Update the sprite to the next animation frame.
"""
# Animate the sprite
self.index = (self.index + 1) % len(self.images)
self.image = self.images[self.index]
self._index = (self._index + 1) % len(self._images)
self.image = self._images[self._index]
class InfoText:

View File

@ -4,9 +4,11 @@ import json
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):
"""
Constructs the object with all starting values.

View File

@ -1,6 +1,6 @@
"""
Module used to fake the RPi.GPIO module so that
the program can be run without the actual hardware.
Dummy module that contains empty functions and variables that exist in RPi.GPIO. This module is to be imported
if importing RPi.GPIO fails.
"""
# Constants used by RPi.GPIO
@ -12,7 +12,11 @@ FALLING = 0
def setmode(new_mode):
"""
Fake setmode function.
:param new_mode:
Args:
new_mode:
Returns:
"""
pass
@ -20,10 +24,14 @@ def setmode(new_mode):
def setup(channel, mode, initial=None, pull_up_down=None):
"""
Fake setup function.
:param channel:
:param mode:
:param initial:
:param pull_up_down:
Args:
channel:
mode:
initial:
pull_up_down:
Returns:
"""
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):
"""
Fake function to add a non-existent event detect.
:param channel:
:param edge_type:
:param callback:
:param bouncetime:
Args:
channel:
edge_type:
callback:
bouncetime:
Returns:
"""
pass
@ -42,8 +54,11 @@ def add_event_detect(channel, edge_type, callback=None, bouncetime=0):
def event_detected(channel):
"""
Fake function to detect an event. Always returns false.
:param channel:
:return:
Args:
channel:
Returns:
"""
return False
@ -51,6 +66,10 @@ def event_detected(channel):
def cleanup(channel=None):
"""
Fake cleanup function.
:param channel:
Args:
channel:
Returns:
"""
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 (pygame, etc.)
"""
"""Handle inputs from the GPIO pins on the Raspberry Pi and converting them to events to be used in other places (
pygame, etc.)"""
import importlib.util
# 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.
ON_HARDWARE = None # Flag to tell other methods if the program is running on hardware or not
try:
importlib.util.find_spec('RPi.GPIO')
import RPi.GPIO as GPIO
ON_HARDWARE = True
except ImportError:
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
BUTTONS = {
@ -24,9 +28,7 @@ BUTTONS = {
def setup():
"""
Primes the GPIO pins for reading the inputs of the buttons.
"""
"""Prime the GPIO pins for reading the inputs of the buttons."""
GPIO.setmode(GPIO.BOARD)
GPIO.setup(BUTTONS.get('a'), GPIO.IN)
@ -47,16 +49,17 @@ def setup():
def teardown():
"""
Cleans up the GPIO handler.
"""
"""Clean up the GPIO handler."""
GPIO.cleanup()
def get_press(button):
"""
Returns true if a button has changed from not pressed to pressed.
:param button: button to be detected
:return: True if the button is has been pressed, False otherwise
Checks if a given button code has been pressed and returns a bool depending on the state.
Args:
button: button to be detected
Returns: True if the button is has been pressed, False otherwise
"""
return GPIO.event_detected(button)

View File

@ -1,5 +1,4 @@
import pygame
import importlib.util
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
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):
"""
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
# 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
def create_event(self, pressed_button):
"""
Creates a pygame event with a given keyboard code
:param pressed_button:
Create a pygame event given a GPIO code and post it to the pygame event handler.
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
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.KEYUP, {'key': pressed_button}))
self.last_input_tick = pygame.time.get_ticks()
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:
code = gpio_handler.BUTTONS.get(pressed_button)
@ -45,10 +48,8 @@ class InputHandler:
if gpio_handler.get_press(code):
self.create_event(code)
def keyboard_handler(self):
"""
Simulates key presses to GPIO button presses. Also handles quitting the game.
"""
def handle_keyboard(self):
"""Handle keyboard presses and generate corresponding GPIO codes to create events."""
# Checks if a corresponding keyboard key has been pressed. If it has, emulate a button press.
for keyboard_event in pygame.event.get():
@ -73,10 +74,8 @@ class InputHandler:
running = False
def update(self):
"""
Run the input handler and check for inputs.
"""
if self.on_hardware:
"""Run either the GPIO handler or the keyboard handler to check for input and create events."""
if gpio_handler.ON_HARDWARE:
self.handle_gpio()
else:
self.keyboard_handler()
self.handle_keyboard()

View File

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

View File

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