restructured directories to make more sense of modules and sub-modules
This commit is contained in:
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."""
|
67
pocket_friends/game_files/io/data_handler.py
Normal file
67
pocket_friends/game_files/io/data_handler.py
Normal file
@@ -0,0 +1,67 @@
|
||||
import pocket_friends
|
||||
import json
|
||||
|
||||
|
||||
class DataHandler:
|
||||
"""
|
||||
Class that handles the hardware attributes and save files.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
# 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 class 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 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()
|
||||
|
||||
def update(self):
|
||||
"""
|
||||
Run the game logic.
|
||||
"""
|
||||
self.frames_passed += 1
|
||||
# Run logic of the game every second.
|
||||
if self.frames_passed >= game_fps:
|
||||
|
||||
# Add one to the age of the bloop.
|
||||
self.attributes['age'] += 1
|
||||
|
||||
# Save the data when the age of the bloop is a multiple of 10.
|
||||
if self.attributes['age'] % 10 == 0:
|
||||
self.write_save()
|
||||
|
||||
# Reset frame counter
|
||||
self.frames_passed = 0
|
56
pocket_friends/game_files/io/fake_gpio.py
Normal file
56
pocket_friends/game_files/io/fake_gpio.py
Normal file
@@ -0,0 +1,56 @@
|
||||
"""
|
||||
Module used to fake the RPi.GPIO module so that
|
||||
the program can be run without the actual hardware.
|
||||
"""
|
||||
|
||||
# Constants used by RPi.GPIO
|
||||
BOARD = 0
|
||||
IN = 0
|
||||
FALLING = 0
|
||||
|
||||
|
||||
def setmode(new_mode):
|
||||
"""
|
||||
Fake setmode function.
|
||||
:param new_mode:
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def setup(channel, mode, initial=None, pull_up_down=None):
|
||||
"""
|
||||
Fake setup function.
|
||||
:param channel:
|
||||
:param mode:
|
||||
:param initial:
|
||||
:param pull_up_down:
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
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:
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def event_detected(channel):
|
||||
"""
|
||||
Fake function to detect an event. Always returns false.
|
||||
:param channel:
|
||||
:return:
|
||||
"""
|
||||
return False
|
||||
|
||||
|
||||
def cleanup(channel=None):
|
||||
"""
|
||||
Fake cleanup function.
|
||||
:param channel:
|
||||
"""
|
||||
pass
|
62
pocket_friends/game_files/io/gpio_handler.py
Normal file
62
pocket_friends/game_files/io/gpio_handler.py
Normal file
@@ -0,0 +1,62 @@
|
||||
"""
|
||||
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.
|
||||
try:
|
||||
importlib.util.find_spec('RPi.GPIO')
|
||||
import RPi.GPIO as GPIO
|
||||
except ImportError:
|
||||
import pocket_friends.game_files.io.fake_gpio as GPIO
|
||||
|
||||
# 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():
|
||||
"""
|
||||
Primes 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():
|
||||
"""
|
||||
Cleans 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
|
||||
"""
|
||||
return GPIO.event_detected(button)
|
82
pocket_friends/game_files/io/input_handler.py
Normal file
82
pocket_friends/game_files/io/input_handler.py
Normal file
@@ -0,0 +1,82 @@
|
||||
import pygame
|
||||
import importlib.util
|
||||
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.
|
||||
"""
|
||||
|
||||
def __init__(self, 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
|
||||
|
||||
def create_event(self, pressed_button):
|
||||
"""
|
||||
Creates a pygame event with a given keyboard code
|
||||
:param pressed_button:
|
||||
"""
|
||||
# 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:
|
||||
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.
|
||||
"""
|
||||
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 keyboard_handler(self):
|
||||
"""
|
||||
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.
|
||||
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 the input handler and check for inputs.
|
||||
"""
|
||||
if self.on_hardware:
|
||||
self.handle_gpio()
|
||||
else:
|
||||
self.keyboard_handler()
|
Reference in New Issue
Block a user