Compare commits
34 Commits
oop-cleanu
...
3fa4e2190e
Author | SHA1 | Date | |
---|---|---|---|
3fa4e2190e | |||
b65f112b36 | |||
5b2c724882 | |||
d8775fb1a9 | |||
4045930bd9 | |||
d322949b5a | |||
b97d54f49d | |||
65365adc3d | |||
f56f775541 | |||
509efa7e23 | |||
327f6cadee | |||
a8674f073e | |||
eff7f2c893 | |||
adfece1a32 | |||
07aae2b075 | |||
bba0af4946 | |||
dd621dbe7a | |||
bbf549c024 | |||
ca9406aab8 | |||
535aa993a5 | |||
4e14204392 | |||
7b8898b77b | |||
da5bacf950 | |||
fd7e1b7492 | |||
bbe97f0de7 | |||
296b6df4a0 | |||
2ffd9bd929 | |||
6f6eaa3c6d | |||
d66d56630d | |||
7073bbb73c | |||
f1c83ade97 | |||
787c1cc252 | |||
36487cad9e | |||
2987bfa7ed |
@@ -13,7 +13,7 @@ There are currently no releases of the game. To install the current version on G
|
|||||||
## Installing From Source
|
## Installing From Source
|
||||||
|
|
||||||
Requirements:
|
Requirements:
|
||||||
- Python 3.10 or greater
|
- Python 3.9 or greater
|
||||||
- Pip
|
- Pip
|
||||||
- Git
|
- Git
|
||||||
|
|
||||||
|
@@ -1 +1,4 @@
|
|||||||
|
"""Pocket Friends is a game where you raise your own little pocket friend! These pocket friends, called bloops,
|
||||||
|
are great little companions to have! You can feed them, play with them, and watch them grow up!"""
|
||||||
|
|
||||||
__version__ = 'dev_0.0.3'
|
__version__ = 'dev_0.0.3'
|
||||||
|
@@ -2,11 +2,10 @@
|
|||||||
Launch script for Pocket Friends.
|
Launch script for Pocket Friends.
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
|
||||||
import pygame
|
import pygame
|
||||||
import sys
|
import sys
|
||||||
from pocket_friends.game_files.game import main as game_main
|
from pathlib import Path
|
||||||
from pocket_friends.development.dev_menu import main as dev_menu_main
|
import pocket_friends.game_files.game as game
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
enable_dev = False
|
enable_dev = False
|
||||||
@@ -14,16 +13,11 @@ if __name__ == '__main__':
|
|||||||
# enable dev mode if --dev argument is passed
|
# enable dev mode if --dev argument is passed
|
||||||
if len(sys.argv) > 0:
|
if len(sys.argv) > 0:
|
||||||
for args in sys.argv:
|
for args in sys.argv:
|
||||||
if args == '--dev':
|
|
||||||
enable_dev = True
|
|
||||||
if args == '--delete-save':
|
if args == '--delete-save':
|
||||||
save_dir = os.path.join(Path.home(), '.pocket_friends')
|
save_dir = os.path.join(Path.home(), '.pocket_friends')
|
||||||
os.remove(save_dir + '/save.json')
|
os.remove(save_dir + '/save.json')
|
||||||
|
|
||||||
if not enable_dev:
|
game.main()
|
||||||
game_main()
|
|
||||||
else:
|
|
||||||
dev_menu_main()
|
|
||||||
|
|
||||||
pygame.quit()
|
pygame.quit()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
Module to test the GPIO input on the Raspberry Pi.
|
Module to test the GPIO input on the Raspberry Pi.
|
||||||
"""
|
"""
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from ..hardware.gpio_handler import Constants, GPIOHandler
|
from pocket_friends.game_files.io.gpio_handler import Constants, GPIOHandler
|
||||||
|
|
||||||
|
|
||||||
def button_test():
|
def button_test():
|
||||||
|
@@ -8,13 +8,13 @@ import pygame
|
|||||||
import time
|
import time
|
||||||
from .button_test import button_test
|
from .button_test import button_test
|
||||||
from .menus import Menu
|
from .menus import Menu
|
||||||
from ..hardware.gpio_handler import GPIOHandler, Constants
|
from pocket_friends.game_files.io.gpio_handler import GPIOHandler, Constants
|
||||||
|
|
||||||
try:
|
try:
|
||||||
importlib.util.find_spec('RPi.GPIO')
|
importlib.util.find_spec('RPi.GPIO')
|
||||||
import RPi.GPIO as GPIO
|
import RPi.GPIO as GPIO
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import pocket_friends.development.FakeGPIO as GPIO
|
import pocket_friends.game_files.io.fake_gpio as GPIO
|
||||||
|
|
||||||
# Global variable to keep track of the current menu.
|
# Global variable to keep track of the current menu.
|
||||||
menu = 'main'
|
menu = 'main'
|
||||||
|
1
pocket_friends/game_files/elements/__init__.py
Normal file
1
pocket_friends/game_files/elements/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
"""Sub-module for use in the game. Helps with the drawing of various objects such as sprites and text boxes."""
|
272
pocket_friends/game_files/elements/sprites.py
Normal file
272
pocket_friends/game_files/elements/sprites.py
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
import pygame
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class SpriteSheet:
|
||||||
|
"""
|
||||||
|
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.
|
||||||
|
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:
|
||||||
|
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 = img_attrib['width'], img_attrib['height']
|
||||||
|
|
||||||
|
# Iterate through every image location on the sprite sheet given the sprite size
|
||||||
|
for i in range(sprite_sheet.get_size()[1] // sprite_size[1]):
|
||||||
|
i *= sprite_size[1]
|
||||||
|
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(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 >= img_attrib['frames']:
|
||||||
|
break
|
||||||
|
if image_count >= img_attrib['frames']:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
class SelectionEgg(pygame.sprite.Sprite):
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
|
||||||
|
# Loads the JSON file of the egg to read in data.
|
||||||
|
with open(resources_dir + '/data/bloop_info/{0}.json'.format(egg_color), 'r') as save_file:
|
||||||
|
json_file = json.load(save_file)
|
||||||
|
save_file.close()
|
||||||
|
|
||||||
|
# Gets the description off the egg from the JSON file.
|
||||||
|
self.description = json_file.get('description')
|
||||||
|
self.contentedness = json_file.get('contentedness')
|
||||||
|
self.metabolism = json_file.get('metabolism')
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Get the rectangle from the first image in the list
|
||||||
|
self.rect = self._images[0].get_rect()
|
||||||
|
print(type(self.rect))
|
||||||
|
self._index = 0
|
||||||
|
self.image = self._images[self._index]
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
"""
|
||||||
|
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]
|
||||||
|
|
||||||
|
|
||||||
|
class InfoText:
|
||||||
|
"""
|
||||||
|
Class for drawing large amounts of text on the screen at a time
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, resources_dir, game_res, text='Lorem ipsum dolor sit amet, consectetur adipiscing elit. '
|
||||||
|
'Nam commodo tempor aliquet. Suspendisse placerat accumsan'
|
||||||
|
' neque, nec volutpat nunc porta ut.'):
|
||||||
|
|
||||||
|
self.font = pygame.font.Font(resources_dir + '/fonts/5Pts5.ttf', 10)
|
||||||
|
self.text = [] # Text broken up into a list according to how it will fit on screen.
|
||||||
|
self.max_lines = 6 # Max number of lines to be shown on screen at a time.
|
||||||
|
self.offset = 0
|
||||||
|
self.game_res = game_res
|
||||||
|
|
||||||
|
# Arrow icons to indicate scrolling
|
||||||
|
self.up_arrow = pygame.image.load(resources_dir + '/images/gui/up_arrow.png').convert_alpha()
|
||||||
|
self.down_arrow = pygame.image.load(resources_dir + '/images/gui/down_arrow.png').convert_alpha()
|
||||||
|
|
||||||
|
raw_text = text # Copy the text to a different variable to be cut up.
|
||||||
|
|
||||||
|
margins = 4.5
|
||||||
|
max_line_width = self.game_res - (margins * 2) # The maximum pixel width that drawn text can be.
|
||||||
|
cut_chars = '.,! ' # Characters that will be considered "cuts" aka when a line break can occur.
|
||||||
|
|
||||||
|
# Prevents freezing if the end of the string does not end in a cut character
|
||||||
|
# Will fix eventually more elegantly
|
||||||
|
if raw_text[-1:] not in cut_chars:
|
||||||
|
raw_text += ' '
|
||||||
|
|
||||||
|
# Calculating line breaks.
|
||||||
|
while len(raw_text) > 0:
|
||||||
|
index = 0
|
||||||
|
test_text = '' # Chunk of text to pseudo-render and test the width of.
|
||||||
|
|
||||||
|
# Loops until the testing text has reached the size limit.
|
||||||
|
while True:
|
||||||
|
|
||||||
|
# Break if the current index is larger than the remaining text.
|
||||||
|
if index + 1 > len(raw_text):
|
||||||
|
index -= 1
|
||||||
|
break
|
||||||
|
|
||||||
|
# Add one character to the testing text from the raw text.
|
||||||
|
test_text += raw_text[index]
|
||||||
|
# Get the width of the pseudo-rendered text.
|
||||||
|
text_width = self.font.size(test_text)[0]
|
||||||
|
|
||||||
|
# Break if the text is larger than the defined max width.
|
||||||
|
if text_width > max_line_width:
|
||||||
|
break
|
||||||
|
index += 1
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Gets the chunk of text to be added to the list.
|
||||||
|
text_chunk = raw_text[0:index + 1]
|
||||||
|
# Determines if the chunk of text has any break characters.
|
||||||
|
has_breaks = any(cut_chars in text_chunk for cut_chars in cut_chars)
|
||||||
|
|
||||||
|
# If the text has break characters, start with the last character and go backwards until
|
||||||
|
# one has been found, decreasing the index each time.
|
||||||
|
if has_breaks:
|
||||||
|
while raw_text[index] not in cut_chars:
|
||||||
|
index -= 1
|
||||||
|
text_chunk = raw_text[0:index + 1]
|
||||||
|
# If there are no break characters in the chunk, simply decrease the index by one and insert
|
||||||
|
# a dash at the end of the line to indicate the word continues.
|
||||||
|
else:
|
||||||
|
index -= 1
|
||||||
|
text_chunk = raw_text[0:index + 1]
|
||||||
|
text_chunk += '-'
|
||||||
|
|
||||||
|
# Append the text chunk to the list of text to draw.
|
||||||
|
self.text.append(text_chunk)
|
||||||
|
|
||||||
|
# Cut the text to repeat the process with the new cut string.
|
||||||
|
raw_text = raw_text[index + 1:]
|
||||||
|
|
||||||
|
def draw(self, surface):
|
||||||
|
"""
|
||||||
|
Draws the text on a given surface.
|
||||||
|
:param surface: The surface for the text to be drawn on.
|
||||||
|
"""
|
||||||
|
# Constants to help draw the text
|
||||||
|
line_separation = 7
|
||||||
|
left_margin = 3
|
||||||
|
top_margin = 25
|
||||||
|
bottom_margin = 10
|
||||||
|
|
||||||
|
# Draw the lines on the screen
|
||||||
|
for i in range(min(len(self.text), self.max_lines)):
|
||||||
|
text = self.font.render(self.text[i + self.offset], False, (64, 64, 64))
|
||||||
|
surface.blit(text, (left_margin, top_margin + (i * line_separation)))
|
||||||
|
|
||||||
|
# Draw the arrows if there is more text than is on screen.
|
||||||
|
if self.offset != 0:
|
||||||
|
surface.blit(self.up_arrow, ((self.game_res / 2) - (self.up_arrow.get_rect().width / 2), top_margin - 3))
|
||||||
|
if len(self.text) - (self.offset + 1) >= self.max_lines:
|
||||||
|
surface.blit(self.down_arrow,
|
||||||
|
((self.game_res / 2) - (self.down_arrow.get_rect().width / 2), self.game_res - bottom_margin))
|
||||||
|
|
||||||
|
def scroll_down(self):
|
||||||
|
"""
|
||||||
|
Scrolls the text on the screen down.
|
||||||
|
"""
|
||||||
|
# Ensures that the offset cannot be too big as to try to render non-existent lines.
|
||||||
|
if len(self.text) - (self.offset + 1) >= self.max_lines:
|
||||||
|
self.offset += 1
|
||||||
|
|
||||||
|
def scroll_up(self):
|
||||||
|
"""
|
||||||
|
Scrolls the text on the screen up.
|
||||||
|
"""
|
||||||
|
if self.offset > 0: # Ensures a non-zero offset is not possible.
|
||||||
|
self.offset -= 1
|
||||||
|
|
||||||
|
|
||||||
|
class EggInfo:
|
||||||
|
"""
|
||||||
|
Class to draw the contentedness and metabolism value off the egg on the info screen.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, resources_dir, contentedness, metabolism, location):
|
||||||
|
self.contentedness = contentedness
|
||||||
|
self.metabolism = metabolism
|
||||||
|
self.x = location[0]
|
||||||
|
self.y = location[1]
|
||||||
|
|
||||||
|
# Create a new surface to blit onto the other surface
|
||||||
|
self.surface = pygame.Surface((44, 15), pygame.SRCALPHA)
|
||||||
|
|
||||||
|
# Blit the two indicator icons on screen
|
||||||
|
smiley = pygame.image.load(resources_dir + '/images/gui/smiley.png').convert_alpha()
|
||||||
|
self.surface.blit(smiley, (0, 0))
|
||||||
|
apple = pygame.image.load(resources_dir + '/images/gui/apple.png').convert_alpha()
|
||||||
|
self.surface.blit(apple, (1, 9))
|
||||||
|
|
||||||
|
# Draw 5 stars. If the value of the contentedness is less than the current star, make it a blank star.
|
||||||
|
for i in range(5):
|
||||||
|
if i < self.contentedness:
|
||||||
|
star = pygame.image.load(resources_dir + '/images/gui/star.png').convert_alpha()
|
||||||
|
else:
|
||||||
|
star = pygame.image.load(resources_dir + '/images/gui/blank_star.png').convert_alpha()
|
||||||
|
self.surface.blit(star, (11 + (i * 6), 1))
|
||||||
|
|
||||||
|
# Draw 5 stars. If the value of the metabolism is less than the current star, make it a blank star.
|
||||||
|
for i in range(5):
|
||||||
|
if i < self.metabolism:
|
||||||
|
star = pygame.image.load(resources_dir + '/images/gui/star.png').convert_alpha()
|
||||||
|
else:
|
||||||
|
star = pygame.image.load(resources_dir + '/images/gui/blank_star.png').convert_alpha()
|
||||||
|
self.surface.blit(star, (11 + (i * 6), 10))
|
||||||
|
|
||||||
|
def draw(self, surface):
|
||||||
|
"""
|
||||||
|
Draw the info icons on a given surface.
|
||||||
|
:param surface: the surface to draw the icons on.
|
||||||
|
"""
|
||||||
|
# Blit the info onto the given surface.
|
||||||
|
surface.blit(self.surface, (self.x, self.y))
|
File diff suppressed because it is too large
Load Diff
2
pocket_friends/game_files/io/__init__.py
Normal file
2
pocket_friends/game_files/io/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
"""Sub-package for handling all I/O operations including keyboard input (GPIO input when connected to a Raspberry Pi)
|
||||||
|
and save data reading and writing."""
|
55
pocket_friends/game_files/io/data.py
Normal file
55
pocket_friends/game_files/io/data.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import pocket_friends
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
class SaveData:
|
||||||
|
"""
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
# Attributes that are saved to a file to recover upon startup.
|
||||||
|
self.attributes = {
|
||||||
|
'version': pocket_friends.__version__,
|
||||||
|
'time_elapsed': 0,
|
||||||
|
'bloop': '',
|
||||||
|
'age': 0,
|
||||||
|
'health': 0,
|
||||||
|
'hunger': 0,
|
||||||
|
'happiness': 0,
|
||||||
|
'care_counter': 0,
|
||||||
|
'missed_care': 0,
|
||||||
|
'adult': 0,
|
||||||
|
'evolution_stage': '',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Frame counter
|
||||||
|
self.frames_passed = 0
|
||||||
|
|
||||||
|
def write_save(self):
|
||||||
|
"""
|
||||||
|
Writes attributes of the save object to "save.json" file.
|
||||||
|
"""
|
||||||
|
with open(save_dir + '/save.json', 'w') as save_file:
|
||||||
|
json.dump(self.attributes, save_file)
|
||||||
|
save_file.close()
|
||||||
|
|
||||||
|
def read_save(self):
|
||||||
|
"""
|
||||||
|
Reads from "save.json" and inserts into the save object's attributes dictionary. Creates file if it does not
|
||||||
|
exist.
|
||||||
|
"""
|
||||||
|
# Open up the save file and read it into self.attributes.
|
||||||
|
try:
|
||||||
|
with open(save_dir + '/save.json', 'r') as save_file:
|
||||||
|
self.attributes = json.load(save_file)
|
||||||
|
save_file.close()
|
||||||
|
|
||||||
|
# If there is no save file, write one with the defaults.
|
||||||
|
except FileNotFoundError:
|
||||||
|
self.write_save()
|
@@ -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 hardware 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
|
65
pocket_friends/game_files/io/gpio_handler.py
Normal file
65
pocket_friends/game_files/io/gpio_handler.py
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
"""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 = {
|
||||||
|
'a': 31, # A button
|
||||||
|
'b': 29, # B button
|
||||||
|
'j_i': 7, # Joystick in
|
||||||
|
'j_u': 11, # Joystick up
|
||||||
|
'j_d': 15, # Joystick down
|
||||||
|
'j_l': 13, # Joystick left
|
||||||
|
'j_r': 16 # Joystick right
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def setup():
|
||||||
|
"""Prime the GPIO pins for reading the inputs of the buttons."""
|
||||||
|
GPIO.setmode(GPIO.BOARD)
|
||||||
|
|
||||||
|
GPIO.setup(BUTTONS.get('a'), GPIO.IN)
|
||||||
|
GPIO.setup(BUTTONS.get('b'), GPIO.IN)
|
||||||
|
GPIO.setup(BUTTONS.get('j_i'), GPIO.IN)
|
||||||
|
GPIO.setup(BUTTONS.get('j_u'), GPIO.IN)
|
||||||
|
GPIO.setup(BUTTONS.get('j_d'), GPIO.IN)
|
||||||
|
GPIO.setup(BUTTONS.get('j_l'), GPIO.IN)
|
||||||
|
GPIO.setup(BUTTONS.get('j_r'), GPIO.IN)
|
||||||
|
|
||||||
|
GPIO.add_event_detect(BUTTONS.get('a'), GPIO.FALLING)
|
||||||
|
GPIO.add_event_detect(BUTTONS.get('b'), GPIO.FALLING)
|
||||||
|
GPIO.add_event_detect(BUTTONS.get('j_i'), GPIO.FALLING)
|
||||||
|
GPIO.add_event_detect(BUTTONS.get('j_u'), GPIO.FALLING)
|
||||||
|
GPIO.add_event_detect(BUTTONS.get('j_d'), GPIO.FALLING)
|
||||||
|
GPIO.add_event_detect(BUTTONS.get('j_l'), GPIO.FALLING)
|
||||||
|
GPIO.add_event_detect(BUTTONS.get('j_r'), GPIO.FALLING)
|
||||||
|
|
||||||
|
|
||||||
|
def teardown():
|
||||||
|
"""Clean up the GPIO handler."""
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
|
||||||
|
def get_press(button):
|
||||||
|
"""
|
||||||
|
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)
|
81
pocket_friends/game_files/io/input_handler.py
Normal file
81
pocket_friends/game_files/io/input_handler.py
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import pygame
|
||||||
|
import pocket_friends.game_files.io.gpio_handler as gpio_handler
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
self.last_input_tick = 0
|
||||||
|
|
||||||
|
def create_event(self, 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 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):
|
||||||
|
"""
|
||||||
|
Handle GPIO events and create events for them.
|
||||||
|
"""
|
||||||
|
for pressed_button in gpio_handler.BUTTONS:
|
||||||
|
code = gpio_handler.BUTTONS.get(pressed_button)
|
||||||
|
|
||||||
|
# Check if a button has been pressed. If it has, create a pygame event for it.
|
||||||
|
if gpio_handler.get_press(code):
|
||||||
|
self.create_event(code)
|
||||||
|
|
||||||
|
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():
|
||||||
|
if keyboard_event.type == pygame.QUIT:
|
||||||
|
running = False
|
||||||
|
if keyboard_event.type == pygame.KEYDOWN:
|
||||||
|
if keyboard_event.key == pygame.K_a:
|
||||||
|
self.create_event(gpio_handler.BUTTONS.get('a'))
|
||||||
|
if keyboard_event.key == pygame.K_b:
|
||||||
|
self.create_event(gpio_handler.BUTTONS.get('b'))
|
||||||
|
if keyboard_event.key == pygame.K_PERIOD:
|
||||||
|
self.create_event(gpio_handler.BUTTONS.get('j_i'))
|
||||||
|
if keyboard_event.key == pygame.K_RIGHT:
|
||||||
|
self.create_event(gpio_handler.BUTTONS.get('j_r'))
|
||||||
|
if keyboard_event.key == pygame.K_LEFT:
|
||||||
|
self.create_event(gpio_handler.BUTTONS.get('j_l'))
|
||||||
|
if keyboard_event.key == pygame.K_DOWN:
|
||||||
|
self.create_event(gpio_handler.BUTTONS.get('j_d'))
|
||||||
|
if keyboard_event.key == pygame.K_UP:
|
||||||
|
self.create_event(gpio_handler.BUTTONS.get('j_u'))
|
||||||
|
if keyboard_event.key == pygame.K_ESCAPE:
|
||||||
|
running = False
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
"""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.handle_keyboard()
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 8.3 KiB |
147
pocket_friends/game_files/surfaces/egg_select.py
Normal file
147
pocket_friends/game_files/surfaces/egg_select.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
import pygame
|
||||||
|
from ..elements import sprites
|
||||||
|
import pocket_friends.game_files.io.gpio_handler as gpio_handler
|
||||||
|
from ..io.input_handler import InputHandler
|
||||||
|
|
||||||
|
|
||||||
|
class Surface(pygame.Surface):
|
||||||
|
def __init__(self, window_size, resources_dir, game_fps, **kwargs):
|
||||||
|
super().__init__(window_size, pygame.SRCALPHA)
|
||||||
|
self.name = 'egg_select'
|
||||||
|
self.running = True
|
||||||
|
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.bg = pygame.image.load(self.resource_dir + '/images/bg.png').convert_alpha()
|
||||||
|
self.sprites = pygame.sprite.Group()
|
||||||
|
|
||||||
|
preselected_color = None
|
||||||
|
for key in kwargs.keys():
|
||||||
|
if key == 'selected_color':
|
||||||
|
preselected_color = kwargs.get(key)
|
||||||
|
|
||||||
|
egg_list = [
|
||||||
|
'dev_egg',
|
||||||
|
'blue',
|
||||||
|
'rainbow'
|
||||||
|
]
|
||||||
|
self.eggs = []
|
||||||
|
for egg in egg_list:
|
||||||
|
self.eggs.append(sprites.SelectionEgg(egg, self.resource_dir))
|
||||||
|
|
||||||
|
self.eggs_per_row = 3
|
||||||
|
distance_between_eggs = 36 / self.eggs_per_row
|
||||||
|
|
||||||
|
# Count the total rows.
|
||||||
|
self.total_rows = -(-len(self.eggs) // self.eggs_per_row)
|
||||||
|
distance_between_rows = 32 / self.eggs_per_row
|
||||||
|
|
||||||
|
# Determine the location of each egg.
|
||||||
|
for egg in self.eggs:
|
||||||
|
current_row = self.eggs.index(egg) // self.eggs_per_row
|
||||||
|
rows_after = self.total_rows - (current_row + 1)
|
||||||
|
egg_in_row = self.eggs.index(egg) % self.eggs_per_row
|
||||||
|
eggs_after = min(len(self.eggs) - (current_row * self.eggs_per_row), self.eggs_per_row) - (egg_in_row + 1)
|
||||||
|
|
||||||
|
x_offset = 32
|
||||||
|
y_offset = 30
|
||||||
|
|
||||||
|
# The x coordinate of an egg is determined by which egg in the row it is, and how many eggs
|
||||||
|
# are in that row. If there is only 1 egg in a row, it is in the middle of the screen. If
|
||||||
|
# there are two, they're on equal halves and so on.
|
||||||
|
x = x_offset - (eggs_after * distance_between_eggs) + (egg_in_row * distance_between_eggs)
|
||||||
|
y = y_offset - (rows_after * distance_between_rows) + (current_row * distance_between_rows)
|
||||||
|
|
||||||
|
egg.rect.x = x
|
||||||
|
egg.rect.y = y
|
||||||
|
|
||||||
|
# Add the egg to the sprite list.
|
||||||
|
self.sprites.add(egg)
|
||||||
|
|
||||||
|
self.selected_egg = 0
|
||||||
|
self.selected_color = ''
|
||||||
|
if preselected_color is not None:
|
||||||
|
self.selected_color = self.eggs[self.selected_egg].egg_color
|
||||||
|
for i in range(len(self.eggs)):
|
||||||
|
if self.eggs[i].egg_color == preselected_color:
|
||||||
|
self.selected_egg = i
|
||||||
|
|
||||||
|
def get_cursor_coords(self):
|
||||||
|
"""
|
||||||
|
Gets the coordinates of an egg on the selection screen by index and returns it as a tuple
|
||||||
|
:return: tuple of the coordinates of the selected egg
|
||||||
|
"""
|
||||||
|
cursor_x_offset = -2
|
||||||
|
cursor_y_offset = -2
|
||||||
|
|
||||||
|
return (self.eggs[self.selected_egg].rect.x + cursor_x_offset,
|
||||||
|
self.eggs[self.selected_egg].rect.y + cursor_y_offset)
|
||||||
|
|
||||||
|
def sel_left(self):
|
||||||
|
"""
|
||||||
|
Select the egg to the left with constraints.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.selected_egg % self.eggs_per_row != 0:
|
||||||
|
self.selected_egg -= 1
|
||||||
|
|
||||||
|
def sel_right(self):
|
||||||
|
"""
|
||||||
|
Select the egg to the right with constraints.
|
||||||
|
"""
|
||||||
|
|
||||||
|
row = self.selected_egg // self.eggs_per_row
|
||||||
|
eggs_in_row = min(len(self.eggs) - (row * self.eggs_per_row), self.eggs_per_row)
|
||||||
|
|
||||||
|
if self.selected_egg % self.eggs_per_row != eggs_in_row - 1:
|
||||||
|
self.selected_egg += 1
|
||||||
|
|
||||||
|
def sel_up(self):
|
||||||
|
"""
|
||||||
|
Select the egg above with constraints.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.selected_egg // self.eggs_per_row != 0:
|
||||||
|
self.selected_egg -= self.eggs_per_row
|
||||||
|
|
||||||
|
def sel_down(self):
|
||||||
|
"""
|
||||||
|
Select the egg below with constraints.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.selected_egg // self.eggs_per_row != self.total_rows - 1:
|
||||||
|
self.selected_egg += self.eggs_per_row
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
self.clock.tick(self.game_fps)
|
||||||
|
|
||||||
|
self.blit(self.bg, (0, 0))
|
||||||
|
self.sprites.update()
|
||||||
|
self.sprites.draw(self)
|
||||||
|
|
||||||
|
self.input_handler.update()
|
||||||
|
|
||||||
|
cursor = pygame.image.load(
|
||||||
|
self.resource_dir + '/images/gui/egg_selector.png').convert_alpha()
|
||||||
|
self.blit(cursor, self.get_cursor_coords())
|
||||||
|
|
||||||
|
self.selected_color = self.eggs[self.selected_egg].egg_color
|
||||||
|
|
||||||
|
for event in pygame.event.get():
|
||||||
|
if event.type == pygame.KEYDOWN:
|
||||||
|
if event.key == gpio_handler.BUTTONS.get('j_r'):
|
||||||
|
self.sel_right()
|
||||||
|
if event.key == gpio_handler.BUTTONS.get('j_l'):
|
||||||
|
self.sel_left()
|
||||||
|
if event.key == gpio_handler.BUTTONS.get('j_d'):
|
||||||
|
self.sel_down()
|
||||||
|
if event.key == gpio_handler.BUTTONS.get('j_u'):
|
||||||
|
self.sel_up()
|
||||||
|
if event.key == gpio_handler.BUTTONS.get('a'):
|
||||||
|
self.additional_args = {'selected_egg': self.selected_color}
|
||||||
|
self.next_surface = 'selection_info'
|
||||||
|
self.running = False
|
41
pocket_friends/game_files/surfaces/error_screen.py
Normal file
41
pocket_friends/game_files/surfaces/error_screen.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import pygame
|
||||||
|
|
||||||
|
from pocket_friends.game_files.io import gpio_handler
|
||||||
|
from pocket_friends.game_files.io.input_handler import InputHandler
|
||||||
|
|
||||||
|
|
||||||
|
class Surface(pygame.Surface):
|
||||||
|
def __init__(self, window_size, resources_dir, game_fps, **kwargs):
|
||||||
|
super().__init__(window_size, pygame.SRCALPHA)
|
||||||
|
self.name = 'error_screen'
|
||||||
|
self.running = True
|
||||||
|
self.next_surface = 'title'
|
||||||
|
self.clock = pygame.time.Clock()
|
||||||
|
self.input_handler = InputHandler(self.clock)
|
||||||
|
self.additional_args = {}
|
||||||
|
|
||||||
|
self.bg = pygame.image.load(resources_dir + '/images/bg.png').convert_alpha()
|
||||||
|
self.title = pygame.image.load(resources_dir + '/images/debug/invalid.png').convert_alpha()
|
||||||
|
self.frames = 1
|
||||||
|
self.game_fps = game_fps
|
||||||
|
self.delay = 1
|
||||||
|
self.font = pygame.font.Font(resources_dir + '/fonts/5Pts5.ttf', 10)
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
self.clock.tick(self.game_fps)
|
||||||
|
|
||||||
|
self.blit(self.bg, (0, 0))
|
||||||
|
self.blit(self.title, (0, -4))
|
||||||
|
text = self.font.render('Frames: {0}'.format(self.frames), False, (64, 64, 64))
|
||||||
|
self.blit(text, (3, 68))
|
||||||
|
|
||||||
|
self.frames += 1
|
||||||
|
self.frames %= self.game_fps
|
||||||
|
|
||||||
|
self.input_handler.update()
|
||||||
|
|
||||||
|
for event in pygame.event.get():
|
||||||
|
if event.type == pygame.KEYDOWN:
|
||||||
|
if event.key == gpio_handler.BUTTONS.get('b'):
|
||||||
|
self.running = False
|
||||||
|
print('stop')
|
72
pocket_friends/game_files/surfaces/selection_info.py
Normal file
72
pocket_friends/game_files/surfaces/selection_info.py
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import pygame
|
||||||
|
from ..elements import sprites
|
||||||
|
import pocket_friends.game_files.io.gpio_handler as gpio_handler
|
||||||
|
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
|
||||||
|
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.bg = pygame.image.load(self.resource_dir + '/images/bg.png').convert_alpha()
|
||||||
|
self.sprites = pygame.sprite.Group()
|
||||||
|
|
||||||
|
self.selected_egg = None
|
||||||
|
for key in kwargs.keys():
|
||||||
|
if key == 'selected_egg':
|
||||||
|
self.selected_egg = kwargs.get(key)
|
||||||
|
|
||||||
|
egg = sprites.SelectionEgg(self.selected_egg, resources_dir)
|
||||||
|
egg.rect.x = 8
|
||||||
|
egg.rect.y = 3
|
||||||
|
self.sprites.add(egg)
|
||||||
|
|
||||||
|
self.info_text = sprites.InfoText(resources_dir, window_size[0], egg.description)
|
||||||
|
self.info_icons = sprites.EggInfo(resources_dir, egg.contentedness, egg.metabolism, (32, 4))
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
self.clock.tick(self.game_fps)
|
||||||
|
|
||||||
|
self.blit(self.bg, (0, 0))
|
||||||
|
self.sprites.update()
|
||||||
|
self.sprites.draw(self)
|
||||||
|
self.info_text.draw(self)
|
||||||
|
self.info_icons.draw(self)
|
||||||
|
|
||||||
|
self.input_handler.update()
|
||||||
|
|
||||||
|
for event in pygame.event.get():
|
||||||
|
if event.type == pygame.KEYDOWN:
|
||||||
|
if event.key == gpio_handler.BUTTONS.get('j_d'):
|
||||||
|
# Scroll down on the info screen.
|
||||||
|
self.info_text.scroll_down()
|
||||||
|
if event.key == gpio_handler.BUTTONS.get('j_u'):
|
||||||
|
# Scroll up on the info screen.
|
||||||
|
self.info_text.scroll_up()
|
||||||
|
if event.key == gpio_handler.BUTTONS.get('a'):
|
||||||
|
self.running = False
|
||||||
|
self.additional_args = {'selected_color': self.selected_egg}
|
||||||
|
self.next_surface = 'playground'
|
||||||
|
if event.key == gpio_handler.BUTTONS.get('b'):
|
||||||
|
self.running = False
|
||||||
|
self.additional_args = {'selected_color': self.selected_egg}
|
||||||
|
self.next_surface = 'egg_select'
|
27
pocket_friends/game_files/surfaces/title.py
Normal file
27
pocket_friends/game_files/surfaces/title.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import pygame
|
||||||
|
|
||||||
|
|
||||||
|
class Surface(pygame.Surface):
|
||||||
|
def __init__(self, window_size, resources_dir, game_fps):
|
||||||
|
super().__init__(window_size, pygame.SRCALPHA)
|
||||||
|
self.name = 'title'
|
||||||
|
self.running = True
|
||||||
|
self.next_surface = None
|
||||||
|
self.clock = pygame.time.Clock()
|
||||||
|
self.additional_args = {}
|
||||||
|
|
||||||
|
self.bg = pygame.image.load(resources_dir + '/images/bg.png').convert_alpha()
|
||||||
|
self.title = pygame.image.load(resources_dir + '/images/title.png').convert_alpha()
|
||||||
|
self.frames = 1
|
||||||
|
self.game_fps = game_fps
|
||||||
|
self.delay = 1
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
self.clock.tick(self.game_fps)
|
||||||
|
self.blit(self.bg, (0, 0))
|
||||||
|
self.blit(self.title, (0, 0))
|
||||||
|
|
||||||
|
self.frames += 1
|
||||||
|
if self.frames > self.game_fps * self.delay:
|
||||||
|
self.next_surface = 'egg_select'
|
||||||
|
self.running = False
|
@@ -1,71 +0,0 @@
|
|||||||
"""
|
|
||||||
Module that helps with the handling of taking 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
|
|
||||||
|
|
||||||
try:
|
|
||||||
importlib.util.find_spec('RPi.GPIO')
|
|
||||||
import RPi.GPIO as GPIO
|
|
||||||
except ImportError:
|
|
||||||
import pocket_friends.development.FakeGPIO as GPIO
|
|
||||||
|
|
||||||
|
|
||||||
class Constants:
|
|
||||||
"""
|
|
||||||
Contains the constants used by the HAT to read in buttons
|
|
||||||
"""
|
|
||||||
buttons = {
|
|
||||||
'a': 31, # A button
|
|
||||||
'b': 29, # B button
|
|
||||||
'j_i': 7, # Joystick in
|
|
||||||
'j_u': 11, # Joystick up
|
|
||||||
'j_d': 15, # Joystick down
|
|
||||||
'j_l': 13, # Joystick left
|
|
||||||
'j_r': 16 # Joystick right
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class GPIOHandler:
|
|
||||||
"""
|
|
||||||
Class to handle the GPIO inputs from the buttons.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def setup():
|
|
||||||
"""
|
|
||||||
Primes the GPIO pins for reading the inputs of the buttons.
|
|
||||||
"""
|
|
||||||
GPIO.setmode(GPIO.BOARD)
|
|
||||||
|
|
||||||
GPIO.setup(Constants.buttons.get('a'), GPIO.IN)
|
|
||||||
GPIO.setup(Constants.buttons.get('b'), GPIO.IN)
|
|
||||||
GPIO.setup(Constants.buttons.get('j_i'), GPIO.IN)
|
|
||||||
GPIO.setup(Constants.buttons.get('j_u'), GPIO.IN)
|
|
||||||
GPIO.setup(Constants.buttons.get('j_d'), GPIO.IN)
|
|
||||||
GPIO.setup(Constants.buttons.get('j_l'), GPIO.IN)
|
|
||||||
GPIO.setup(Constants.buttons.get('j_r'), GPIO.IN)
|
|
||||||
|
|
||||||
GPIO.add_event_detect(Constants.buttons.get('a'), GPIO.FALLING)
|
|
||||||
GPIO.add_event_detect(Constants.buttons.get('b'), GPIO.FALLING)
|
|
||||||
GPIO.add_event_detect(Constants.buttons.get('j_i'), GPIO.FALLING)
|
|
||||||
GPIO.add_event_detect(Constants.buttons.get('j_u'), GPIO.FALLING)
|
|
||||||
GPIO.add_event_detect(Constants.buttons.get('j_d'), GPIO.FALLING)
|
|
||||||
GPIO.add_event_detect(Constants.buttons.get('j_l'), GPIO.FALLING)
|
|
||||||
GPIO.add_event_detect(Constants.buttons.get('j_r'), GPIO.FALLING)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def teardown():
|
|
||||||
"""
|
|
||||||
Cleans up the GPIO handler.
|
|
||||||
"""
|
|
||||||
GPIO.cleanup()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_press(button):
|
|
||||||
"""
|
|
||||||
Returns true if a button has moved from not pressed to pressed.
|
|
||||||
:param button: button to be detected
|
|
||||||
:return: True if the button is has been pressed, False otherwise
|
|
||||||
"""
|
|
||||||
return GPIO.event_detected(button)
|
|
Reference in New Issue
Block a user