commit 09564da198824f3707923019ccceb9fdb2f6d213 Author: frank Date: Sat Feb 4 15:34:12 2023 -0500 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57bcd4b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +games/* +!games/__init__.py diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..5fed10a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/pgfw"] + path = lib/pgfw + url = https://open.shampoo.ooo/shampoo/pgfw diff --git a/Playzing.py b/Playzing.py new file mode 100755 index 0000000..f56e0c3 --- /dev/null +++ b/Playzing.py @@ -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() diff --git a/config b/config new file mode 100644 index 0000000..ea1f559 --- /dev/null +++ b/config @@ -0,0 +1,16 @@ +[display] +clear = 0, 0, 0 +caption = Playzing +dimensions = 480, 720 +#dimensions = 720, 480 + +[logo] +fire = fire.png +text = text.png +margin = 18 +trail = no +restart = 22000 +delay = 3000 + +[input] +confirm-quit = yes diff --git a/fire.png b/fire.png new file mode 100644 index 0000000..2a9c139 Binary files /dev/null and b/fire.png differ diff --git a/games/__init__.py b/games/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/pgfw b/lib/pgfw new file mode 160000 index 0000000..34451c3 --- /dev/null +++ b/lib/pgfw @@ -0,0 +1 @@ +Subproject commit 34451c3f4cacee9b2df3b0dff68e6539f5754bc4 diff --git a/text.png b/text.png new file mode 100644 index 0000000..d5a8752 Binary files /dev/null and b/text.png differ