|
|
|
@ -0,0 +1,167 @@
|
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
|
|
# Launch PGFW games in the `games/` folder
|
|
|
|
|
|
|
|
|
|
import argparse, os, pathlib, pygame, sys
|
|
|
|
|
import lib.pgfw.pgfw as pgfw
|
|
|
|
|
from games.ibitfit.electric_sieve.ElectricSieve import ElectricSieve
|
|
|
|
|
|
|
|
|
|
class Playzing(pgfw.Game):
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
"""
|
|
|
|
|
Create logo sprite, clear screen, and subscribe to events.
|
|
|
|
|
"""
|
|
|
|
|
pgfw.Game.__init__(self)
|
|
|
|
|
|
|
|
|
|
# Assign types to configuration values
|
|
|
|
|
self.get_configuration().type_declarations.add_chart({
|
|
|
|
|
"display":
|
|
|
|
|
{
|
|
|
|
|
"int-list": "clear"
|
|
|
|
|
},
|
|
|
|
|
"logo":
|
|
|
|
|
{
|
|
|
|
|
"path": ["fire", "text"],
|
|
|
|
|
"int": ["margin", "restart", "delay"],
|
|
|
|
|
"bool": "trail"
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
# Clear screen to black
|
|
|
|
|
self.get_display_surface().fill(self.configuration.get("display", "clear"))
|
|
|
|
|
|
|
|
|
|
# Subscribe to PGFW command events
|
|
|
|
|
self.subscribe(self.respond)
|
|
|
|
|
|
|
|
|
|
# Load sprites for logo parts
|
|
|
|
|
self.logo_text = pgfw.Sprite(self)
|
|
|
|
|
self.logo_text.load_from_path(self.get_resource(self.configuration.get("logo", "text")), True)
|
|
|
|
|
self.logo_fire = pgfw.Sprite(self)
|
|
|
|
|
self.logo_fire.load_from_path(self.get_resource(self.configuration.get("logo", "fire")), True)
|
|
|
|
|
|
|
|
|
|
# Register logo animation functions and begin animation
|
|
|
|
|
self.register(self.animate_logo)
|
|
|
|
|
self.register(self.reveal_text, interval=40)
|
|
|
|
|
self.play(self.animate_logo, play_once=True)
|
|
|
|
|
|
|
|
|
|
def animate_logo(self):
|
|
|
|
|
"""
|
|
|
|
|
Reset the logo animation to its beginning and start animating.
|
|
|
|
|
"""
|
|
|
|
|
# Place the logo
|
|
|
|
|
screen_rect = self.get_display_surface().get_rect()
|
|
|
|
|
margin = self.configuration.get("logo", "margin")
|
|
|
|
|
self.logo_text.location.center = screen_rect.center
|
|
|
|
|
self.logo_text.move(-self.logo_fire.location.w + margin / 2)
|
|
|
|
|
|
|
|
|
|
# Clear the screen
|
|
|
|
|
self.get_display_surface().fill(self.configuration.get("display", "clear"))
|
|
|
|
|
|
|
|
|
|
# Place the fire at the left side of the logo text
|
|
|
|
|
self.logo_fire.location.midleft = self.logo_text.location.midleft
|
|
|
|
|
|
|
|
|
|
# Close the draw clip for the logo completely
|
|
|
|
|
self.logo_text_clip = self.logo_text.location.copy()
|
|
|
|
|
self.logo_text_clip.width = 0
|
|
|
|
|
|
|
|
|
|
# Queue the text reveal to start
|
|
|
|
|
self.play(self.reveal_text, delay=self.configuration.get("logo", "delay"))
|
|
|
|
|
|
|
|
|
|
def reveal_text(self):
|
|
|
|
|
"""
|
|
|
|
|
Move the fire right, opening the logo text clip rect until it's big enough to show all the text. Queue the animation to restart once finished.
|
|
|
|
|
"""
|
|
|
|
|
self.logo_fire.move(10)
|
|
|
|
|
self.logo_text_clip.width = self.logo_fire.location.left - self.logo_text.location.left
|
|
|
|
|
limit = self.logo_text.location.right + self.configuration.get("logo", "margin") / 2
|
|
|
|
|
if self.logo_fire.location.left > limit:
|
|
|
|
|
self.logo_fire.location.left = limit
|
|
|
|
|
self.halt(self.reveal_text)
|
|
|
|
|
self.play(self.animate_logo, delay=self.configuration.get("logo", "restart"), play_once=True)
|
|
|
|
|
|
|
|
|
|
def respond(self, event):
|
|
|
|
|
"""
|
|
|
|
|
Respond to all PGFW commands. If an any button is pressed, launch the iBitFit game.
|
|
|
|
|
"""
|
|
|
|
|
if self.delegate.compare(event, "any"):
|
|
|
|
|
os.chdir(pathlib.Path("games/ibitfit"))
|
|
|
|
|
print(f"current working dir is {os.getcwd()}")
|
|
|
|
|
ibitfit = ElectricSieve()
|
|
|
|
|
ibitfit.display.set_screen(dimensions=ibitfit.configuration.get("display", "dimensions"))
|
|
|
|
|
ibitfit.run()
|
|
|
|
|
os.chdir(pathlib.Path("../.."))
|
|
|
|
|
self.display.set_screen(dimensions=self.configuration.get("display", "dimensions"))
|
|
|
|
|
print(f"current working dir is {os.getcwd()}")
|
|
|
|
|
|
|
|
|
|
def update(self):
|
|
|
|
|
pgfw.Animation.update(self)
|
|
|
|
|
|
|
|
|
|
# Erase the center of the screen if enabled
|
|
|
|
|
if not self.configuration.get("logo", "trail"):
|
|
|
|
|
erase_rect = self.logo_text.location.copy()
|
|
|
|
|
erase_rect.width = self.logo_fire.location.right - self.logo_text.location.left
|
|
|
|
|
self.get_display_surface().fill(self.configuration.get("display", "clear"), erase_rect)
|
|
|
|
|
|
|
|
|
|
# Draw the logo text clipped to the current state of the animation, then remove the clip
|
|
|
|
|
self.get_display_surface().set_clip(self.logo_text_clip)
|
|
|
|
|
self.logo_text.update()
|
|
|
|
|
self.get_display_surface().set_clip(None)
|
|
|
|
|
|
|
|
|
|
# Draw the fire
|
|
|
|
|
self.logo_fire.update()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
# Parse command line arguments
|
|
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
|
parser.add_argument(
|
|
|
|
|
"--keep-working-directory", action="store_true", help="""
|
|
|
|
|
Keep using the current directory as the working directory. The script expects the games to be in the games/ folder, so they can be imported
|
|
|
|
|
as Python modules. Changing the directory to anything other than the launcher project's root folder will break it under normal circumstances,
|
|
|
|
|
so use with care.
|
|
|
|
|
""")
|
|
|
|
|
parser.add_argument(
|
|
|
|
|
"--kms", action="store_true", help="""
|
|
|
|
|
Use SDL 2's KMS video driver. For use on systems without a windowing system (like Linux in only console mode). See
|
|
|
|
|
https://wiki.libsdl.org/SDL2/FAQUsingSDL#how_do_i_choose_a_specific_video_driver
|
|
|
|
|
""")
|
|
|
|
|
parser.add_argument(
|
|
|
|
|
"--framebuffer", action="store_true", help="""
|
|
|
|
|
Use SDL 1.2's framebuffer video driver. For use on older systems without a windowing system that aren't using KMS. This won't work with
|
|
|
|
|
SDL 2 or Pygame 2. See https://wiki.libsdl.org/SDL2/FAQUsingSDL#how_do_i_choose_a_specific_video_driver
|
|
|
|
|
""")
|
|
|
|
|
parser.add_argument(
|
|
|
|
|
"--ignore-hangup", action="store_true", help="""
|
|
|
|
|
Ignore hangup signals. Enabling this may be necessary for running the launcher as a systemd service. See
|
|
|
|
|
https://stackoverflow.com/questions/57205271/how-to-display-pygame-framebuffer-using-systemd-service
|
|
|
|
|
""")
|
|
|
|
|
arguments = parser.parse_args()
|
|
|
|
|
|
|
|
|
|
# If not keeping the working directory, try to move into the same directory as where this program is stored. Use the location of the program
|
|
|
|
|
# that launched this process to determine the path.
|
|
|
|
|
if not arguments.keep_working_directory:
|
|
|
|
|
target = os.path.dirname(sys.argv[0])
|
|
|
|
|
if not pathlib.Path(os.getcwd()).samefile(target):
|
|
|
|
|
try:
|
|
|
|
|
os.chdir(target)
|
|
|
|
|
except:
|
|
|
|
|
print(f"""
|
|
|
|
|
Warning: detected that the working directory is not the same as the launcher project's root directory and could not change to
|
|
|
|
|
to detected directory {target}
|
|
|
|
|
""")
|
|
|
|
|
|
|
|
|
|
if arguments.kms:
|
|
|
|
|
|
|
|
|
|
# Use the KMS video driver. This works for newer versions of Raspberry Pi with the KMS overlay enabled, SDL 2, and Pygame 2.
|
|
|
|
|
os.putenv("SDL_VIDEODRIVER", "kmsdrm")
|
|
|
|
|
|
|
|
|
|
elif arguments.framebuffer:
|
|
|
|
|
|
|
|
|
|
# Use the framebuffer display. This only works with Pygame 1.9.6 (and SDL 1.2).
|
|
|
|
|
os.putenv("SDL_VIDEODRIVER", "fbcon")
|
|
|
|
|
os.putenv("SDL_FBDEV", "/dev/fb0")
|
|
|
|
|
|
|
|
|
|
# Run the launcher
|
|
|
|
|
playzing = Playzing()
|
|
|
|
|
playzing.run()
|