Compare commits

..

11 Commits

Author SHA1 Message Date
4d32ff6f5a Added pishock to requirements 2025-07-16 12:07:07 +01:00
dee653ca31 Updated to use new internal parts of GameUtils 2025-06-24 14:36:43 +01:00
32aa61533c Linted code 2025-06-24 08:01:53 +01:00
214edfbe3a Updated to use GameUtils internal calls 2025-06-24 08:01:48 +01:00
1b84249f47 Removed redundant variable 2025-06-24 08:01:17 +01:00
89241c2939 Updated TODO 2025-06-22 20:00:43 +01:00
77406db737 Added check to close the launcher along with the game if the game was launched directly 2025-06-22 17:56:08 +01:00
f324848c19 Removed debug line 2025-06-22 17:55:44 +01:00
48bd8126a5 It's not done, but it "works" 2025-06-22 17:37:06 +01:00
1cbf9ef2af Added initaliser for players.json 2025-06-22 17:33:20 +01:00
bf3392236a Created setup.py 2025-06-22 17:12:54 +01:00
3 changed files with 149 additions and 40 deletions

View File

@ -7,13 +7,11 @@ import attr
import sys
import os
# TODO: Auto install game requirements
# TODO: Add Discord rich presence
logging.basicConfig(level=logging.DEBUG)
log = logging.getLogger('PainJamLauncher')
print(sys.executable)
# Store the current working directory
# This is used to revert the cd change
originalCWD = os.getcwd()
@ -24,6 +22,7 @@ parser.add_argument('-sw', '--width', type=int, default=1280)
parser.add_argument('-sh', '--height', type=int, default=720)
parser.add_argument('-fps', '--fpsCap', type=int, default=60)
parser.add_argument('-f', '--fullscreen', action='store_true')
parser.add_argument('gameID', nargs='?', type=str, default=None)
args = parser.parse_args()
@attr.s
@ -54,46 +53,78 @@ for path in os.listdir('../'):
log.debug(f'Loaded game {gameID}')
screen = pygame.display.set_mode((args.width, args.height))
gameSurface = pygame.Surface(screen.size)
run = True
currentGame = None
def loadGame(game):
# Set the current working directory
# to the base path of the game
os.chdir(game.path)
spec = importlib.util.spec_from_file_location(game.id, os.path.join(game.path, 'game.py'))
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
return foo.Game(gameSurface)
pygame.init()
currentGame = loadGame(games['russianRoulette'])
# I'm sorry, I prefer object-oriented programming. So sue me.
class Launcher:
def __init__(self):
# The primary display.
self.screen = pygame.display.set_mode((args.width, args.height))
# The surface that the games render to.
self.gameSurface = pygame.Surface(self.screen.size)
# The current Game object. None means no game is running
self.currentGame = None
self.clock = pygame.time.Clock()
# Is the launcher running (including if a game is running).
self.running = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
# If there's no game running
if currentGame == None:
# Exit the launcher
run = False
# Otherwise
pygame.display.set_caption('Pain Jam Launcher')
def loadGame(self, game):
# Set the current working directory
# to the base path of the game.
os.chdir(game.path)
# Load the games game.py file.
spec = importlib.util.spec_from_file_location(game.id, os.path.join(game.path, 'game.py'))
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
# Initialise the games Game class, then set the
# current game to that.
self.currentGame = module.Game(self.gameSurface)
# Set the window title to the games name
pygame.display.set_caption(game.name)
def update(self):
for event in pygame.event.get():
if self.gameRunning:
self.currentGame._onEvent(event)
# CTRL+ESC
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE and event.mod == 64):
# Close the game.
# TODO: Fade out game?
self.currentGame.close()
self.currentGame = None
os.chdir(originalCWD)
pygame.display.set_caption('Pain Jam Launcher')
# If we launched directly into a game
if args.gameID is not None:
# Exit the launcher when we exit the game
self.running = False
else:
# Close the game
# TODO: Fade out game?
currentGame.close()
currentgame = None
os.chdir(originalCWD)
if event.type == pygame.QUIT:
# Exit the launcher.
self.running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_1:
self.loadGame(games['russianRoulette'])
if currentGame != None:
currentGame.onEvent(event)
if self.gameRunning:
self.currentGame._update()
self.screen.blit(self.currentGame._surf, (0, 0))
else:
self.screen.fill((0, 0, 0))
if currentGame != None:
currentGame.update()
screen.blit(currentGame.surf, (0, 0))
pygame.display.update()
pygame.display.update()
self.clock.tick(args.fpsCap)
@property
def gameRunning(self):
return self.currentGame is not None
launcher = Launcher()
if args.gameID is not None:
launcher.loadGame(games[args.gameID])
while launcher.running:
launcher.update()

View File

@ -1,2 +1,3 @@
pygame-ce
pishock
attrs

77
setup.py Normal file
View File

@ -0,0 +1,77 @@
"""
Initalises the launchers virtual environment,
and installs all dependancies.
"""
import subprocess as sp
import platform
import shutil
import sys
import os
def getVenvExec():
"""
Gets the path of the virtual environment
based on the current opperating system.
"""
plat = platform.system()
if plat == 'Linux':
return f'./.venv/bin/python3'
elif plat == 'Windows':
return f'./.venv/Scripts/python.exe'
else:
print(f'WARNING: Playform type "{plat}" is not recognised. Exiting...')
exit(1)
def inputYN(prompt: str, default=None):
"""
A simply yes/no prompt.
"""
while True:
i = input(prompt)
if i.lower() in ['y', 'yes', '1', 'true']: return True
elif i.lower() in ['n', 'no', '0', 'false']: return False
elif i == '' and default != None: return default
def installRequirements(requirementsPath: str):
"""
Installs a requirements.txt file to the current venv.
"""
print(f'---------- Installing {requirementsPath} ----------')
sp.run([getVenvExec(), '-m', 'pip', 'install', '-r', requirementsPath])
# Check for a pre-existing venv
if os.path.isdir('./.venv/'):
# If one exists, ask the user if they want to delete it
replace = inputYN(f'Virtual environment already exists, would you like to replace it? (y/n) > ')
if replace:
# If so, remove the .venv directory
print(f'---------- Removing old virtual environment ----------')
shutil.rmtree('./.venv/')
# Initailise a venv, creating one if it doesn't exist
print(f'---------- Initalising virtual environment ----------')
sp.run([sys.executable, '-m', 'venv', './.venv/'])
# Upgrade pip
print(f'---------- Upgrading pip ----------')
sp.run([getVenvExec(), '-m', 'pip', 'install', '-U', 'pip'])
# Install all requirements.txt files
for path in os.listdir('../'):
requirementsPath = os.path.join('../', path, 'requirements.txt')
if not os.path.isfile(requirementsPath):
print(f'{path} does not have a requirements.txt, skipping...')
continue
installRequirements(requirementsPath)
if os.path.isfile('../players.json'):
newPlayerJSON = inputYN(f'player.json already exists, would you like to overwrite it? (y/n) > ')
else:
newPlayerJSON = True
if newPlayerJSON:
print(f'---------- Copying example players.json ----------')
shutil.copyfile('../NoPELib/players.json', '../players.json')