started using level select object, added preview of animated alien

This commit is contained in:
frank 2022-01-29 17:52:14 -05:00
parent 7036ea9ed0
commit 62831ade79
4 changed files with 104 additions and 51 deletions

101
NS.py
View File

@ -1,5 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
#
# Scrapeboard is an arcade game in development by Frank DeMarco (@diskmem) and Blake Andrews (@snakesandrews).
# It requires custom hardware to play, but it can be tested in keyboard mode with just the code in this
# repository. For more information on setting up and running the game, see the README. For more information
# on the game in general, visit https://scrape.nugget.fun
#
import argparse import argparse
from random import randint, choice, random from random import randint, choice, random
from math import pi from math import pi
@ -34,6 +41,13 @@ from lib.pgfw.pgfw.extension import (
from lib.pgfw.pgfw.gfx_extension import aa_filled_polygon from lib.pgfw.pgfw.gfx_extension import aa_filled_polygon
class NS(Game, Animation): class NS(Game, Animation):
"""
The main game object for Scrapeboard. It initializes and manages most of the other game objects that only have a single
object like the title screen, boss manager, platform, dialog manager, screen wipe manager, main character, and more (see
the objects initialized in __init__). It initializes and manages the serial input from the Arduino, and it listens for and
responds to keyboard input. Its update method is called once per frame by the PGFW code. In its update method it calls the
update methods of its child objects.
"""
LNW, LNE, LSE, LSW = range(4) LNW, LNE, LSE, LSW = range(4)
N, NE, E, NW, S, W = range(6) N, NE, E, NW, S, W = range(6)
@ -130,6 +144,7 @@ class NS(Game, Animation):
ds = self.get_display_surface() ds = self.get_display_surface()
self.background = Surface(ds.get_size()) self.background = Surface(ds.get_size())
self.background.fill((0, 0, 0)) self.background.fill((0, 0, 0))
self.level_select = LevelSelect(self)
self.platform = Platform(self) self.platform = Platform(self)
self.tony = Tony(self) self.tony = Tony(self)
self.logo = Logo(self) self.logo = Logo(self)
@ -202,6 +217,7 @@ class NS(Game, Animation):
self.score_hidden = False self.score_hidden = False
self.idle_elapsed = 0 self.idle_elapsed = 0
self.suppressing_input = False self.suppressing_input = False
self.level_select.reset()
self.title.reset() self.title.reset()
if not leave_wipe_running: if not leave_wipe_running:
self.wipe.reset() self.wipe.reset()
@ -276,6 +292,7 @@ class NS(Game, Animation):
self.reset_arduino() self.reset_arduino()
self.no_reset_elapsed = 0 self.no_reset_elapsed = 0
self.title.update() self.title.update()
self.level_select.update()
self.ending.update() self.ending.update()
self.boss.update() self.boss.update()
if not self.title.active: if not self.title.active:
@ -288,6 +305,44 @@ class NS(Game, Animation):
self.reset() self.reset()
class LevelSelect(GameChild):
"""
Display the available levels. Initialize a platform for each level and display each platform beneath its level glowing
with a pair of pads to press to start that level. Wait for user input, then launch the level of the pair that gets
pressed by the user.
"""
def __init__(self, parent):
GameChild.__init__(self, parent)
self.subscribe(self.respond, KEYDOWN)
def activate(self):
self.active = True
def deactivate(self):
self.active = False
def reset(self):
self.deactivate()
def respond(self, event):
if self.active:
launch_level = None
if event.key == K_1:
launch_level = 0
elif event.key == K_2:
launch_level = 1
elif event.key == K_3:
launch_level = 2
if launch_level is not None:
self.deactivate()
self.get_game().boss.start_level(launch_level)
def update(self):
if self.active:
self.get_display_surface().fill((255, 255, 0))
class Button(Sprite): class Button(Sprite):
MARGIN = 2 MARGIN = 2
@ -559,9 +614,13 @@ class Title(Animation):
self.halt() self.halt()
def start_game(self): def start_game(self):
"""
Turn off the title screen and display the level select. Set the most recent time to None so the most
recent high score stops blinking.
"""
self.deactivate() self.deactivate()
self.get_game().set_most_recent_time(None) self.get_game().set_most_recent_time(None)
self.get_game().boss.start_level(0) self.get_game().level_select.activate()
def draw_scores(self): def draw_scores(self):
step = 75 step = 75
@ -610,19 +669,18 @@ class Title(Animation):
self.get_game().tony.set_frameset("board") self.get_game().tony.set_frameset("board")
def update(self): def update(self):
''' """
Move title, check button presses, and draw screen Scroll the background, check for button presses for the unlock pattern, handle switching between attract mode
''' with the GIFs active and unlocking pattern mode, and draw the screen
"""
Animation.update(self) Animation.update(self)
if self.active: if self.active:
ds = self.get_display_surface() ds = self.get_display_surface()
dsr = ds.get_rect() dsr = ds.get_rect()
self.get_game().logo.update() self.get_game().logo.update()
# advance unlock pattern # Advance through the unlock pattern
platform = self.get_game().platform platform = self.get_game().platform
if not self.get_game().wipe.is_playing() and platform.get_edge_pressed() == self.UNLOCK_MOVES[self.unlock_index]: if not self.get_game().wipe.is_playing() and platform.get_edge_pressed() == self.UNLOCK_MOVES[self.unlock_index]:
# self.first_pressed = True
# self.first_pressed_elapsed = 0
if self.unlock_index == len(self.UNLOCK_MOVES) - 1: if self.unlock_index == len(self.UNLOCK_MOVES) - 1:
platform.set_glowing([]) platform.set_glowing([])
self.get_game().wipe.start(self.start_game) self.get_game().wipe.start(self.start_game)
@ -631,13 +689,8 @@ class Title(Animation):
self.unlock_index += 1 self.unlock_index += 1
platform.set_glowing(platform.get_buttons_from_edges([self.UNLOCK_MOVES[self.unlock_index]])) platform.set_glowing(platform.get_buttons_from_edges([self.UNLOCK_MOVES[self.unlock_index]]))
self.get_audio().play_sfx("land_0") self.get_audio().play_sfx("land_0")
# reset unlock pattern if idle
# if self.first_pressed:
# self.first_pressed_elapsed += self.get_game().time_filter.get_last_frame_duration()
# if self.first_pressed_elapsed > 1000 * 10:
# self.reset()
self.get_game().tony.update() self.get_game().tony.update()
# bounce the gif around the screen # Bounce the GIF around the screen
if self.video.location.right > dsr.right or self.video.location.left < dsr.left: if self.video.location.right > dsr.right or self.video.location.left < dsr.left:
self.angle = reflect_angle(self.angle, 0) self.angle = reflect_angle(self.angle, 0)
if self.video.location.right > dsr.right: if self.video.location.right > dsr.right:
@ -1159,11 +1212,6 @@ class Light(Animation):
shifted = [] shifted = []
for point in self.get_points(): for point in self.get_points():
shifted.append((point[0], point[1] - y)) shifted.append((point[0], point[1] - y))
# ratio = 1 - float(y + 1) / (self.MAX_GLOW_INDEX + 1)
# alpha = int(ratio * 255)
# color = Color(self.color.r, self.color.g, self.color.b, alpha)
# ds = self.get_display_surface()
# intermediate = Surface(ds.get_size(), SRCALPHA)
if self.position == NS.LSW: if self.position == NS.LSW:
saturation = 0 saturation = 0
else: else:
@ -1179,7 +1227,6 @@ class Light(Animation):
), ),
True, shifted, 3 True, shifted, 3
) )
# ds.blit(intermediate, (0, 0))
def in_orientation(self, orientation): def in_orientation(self, orientation):
if self.position == NS.LNW: if self.position == NS.LNW:
@ -1346,20 +1393,28 @@ class Boys(Meter):
class Boss(Animation): class Boss(Animation):
"""
The Boss object also serves as the level object, and it is expected that only one of these objects is initialized.
Its drawing, animations, timings, etc will be determined by the level_index member variable. For example, if
level_index is 0, the kool man sprite will be drawn, but if level_index is 2, the spoopy sprite will be drawn.
"""
def __init__(self, parent): def __init__(self, parent):
"""
Load graphics for boss sprites, avatars, and backgrounds. Initialize boss health and swords objects. Register
animations that control attacks, effects, and dialog.
"""
Animation.__init__(self, parent) Animation.__init__(self, parent)
if self.get_configuration("display", "effects"): if self.get_configuration("display", "effects"):
self.kool_man = RainbowSprite(self, load(self.get_resource("Kool_man_waah.png")).convert_alpha(), hue_shift) self.kool_man = RainbowSprite(self, load(self.get_resource("Kool_man_waah.png")).convert_alpha(), hue_shift)
self.visitor = RainbowSprite(self, load(self.get_resource("Visitor.png")).convert_alpha(), hue_shift)
self.spoopy = RainbowSprite(self, load(self.get_resource("Spoopy.png")).convert_alpha(), hue_shift) self.spoopy = RainbowSprite(self, load(self.get_resource("Spoopy.png")).convert_alpha(), hue_shift)
else: else:
self.kool_man = Sprite(self) self.kool_man = Sprite(self)
self.kool_man.load_from_path("Kool_man_waah.png", True) self.kool_man.load_from_path("Kool_man_waah.png", True)
self.visitor = Sprite(self)
self.visitor.load_from_path("Visitor.png", True)
self.spoopy = Sprite(self) self.spoopy = Sprite(self)
self.spoopy.load_from_path("Spoopy.png", True) self.spoopy.load_from_path("Spoopy.png", True)
self.visitor = Sprite(self, 42)
self.visitor.load_from_path("alienAnimations/alienBoil", True)
for sprite in self.kool_man, self.visitor, self.spoopy: for sprite in self.kool_man, self.visitor, self.spoopy:
sprite.location.topleft = 100, 0 sprite.location.topleft = 100, 0
self.health = Health(self) self.health = Health(self)
@ -1367,7 +1422,7 @@ class Boss(Animation):
self.register(self.brandish, self.cancel_flash, self.show_introduction_dialogue, self.register(self.brandish, self.cancel_flash, self.show_introduction_dialogue,
self.show_end_dialogue, self.end_dialogue) self.show_end_dialogue, self.end_dialogue)
self.kool_man.add_frameset([0], name="normal", switch=True) self.kool_man.add_frameset([0], name="normal", switch=True)
self.visitor.add_frameset([0], name="normal", switch=True) self.visitor.add_frameset(list(range(0, len(self.visitor.frames))), name="normal", switch=True)
self.spoopy.add_frameset([0], name="normal", switch=True) self.spoopy.add_frameset([0], name="normal", switch=True)
self.kool_man_avatar = load(self.get_resource("Kool_man_avatar.png")).convert() self.kool_man_avatar = load(self.get_resource("Kool_man_avatar.png")).convert()
self.visitor_avatar = load(self.get_resource("Visitor_avatar.png")).convert() self.visitor_avatar = load(self.get_resource("Visitor_avatar.png")).convert()

View File

@ -1,33 +1,19 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from os import environ, execvp, chdir, getcwd #
from os.path import exists, join, dirname # Scrapeboard is an arcade game in development by Frank DeMarco (@diskmem) and Blake Andrews (@snakesandrews).
from sys import version_info, argv # It requires custom hardware to play, but it can be tested in keyboard mode with just the code in this
# repository. For more information on setting up and running the game, see the README. For more information
# on the game in general, visit https://scrape.nugget.fun
#
# This is the launcher script that creates a main game object and runs it. If you're running Python 3 with
# the pygame module installed, you should be able to run this script with the --no-serial flag to get it
# running even without the custom hardware:
#
# ./OPEN-GAME --no-serial
#
def can_import(module_name): from sys import argv
try:
__import__(module_name)
except ImportError:
return False
else:
return True
def is_python_3():
return version_info[0] >= 3
def is_current_version(file_name):
version = map(int, file_name.replace("python", "").split("."))
return version == list(version_info)[:2]
def launch_alternative(alternatives):
for alternative in alternatives:
if not is_current_version(alternative):
for root in environ["PATH"].split(":"):
if exists(join(root, alternative)):
execvp(alternative, [alternative] + argv)
def move_to_executable():
chdir(dirname(argv[0]))
if "--go-to-dir" in argv: if "--go-to-dir" in argv:
move_to_executable() move_to_executable()

12
config
View File

@ -1,3 +1,15 @@
#
# Scrapeboard is an arcade game in development by Frank DeMarco (@diskmem) and Blake Andrews (@snakesandrews).
# It requires custom hardware to play, but it can be tested in keyboard mode with just the code in this
# repository. For more information on setting up and running the game, see the README. For more information
# on the game in general, visit https://scrape.nugget.fun
#
# This file contains configurable values that can adjust things like visual effects, performance, and audio.
# A lot of these values are closely tied to how the game is expected to run (for example, the screen resolution),
# but they can still be played around with. There are also a lot of values currently hardcoded in NS.py that
# should be moved into here eventually.
#
[setup] [setup]
license = Public Domain license = Public Domain
title = Scrapeboard title = Scrapeboard

@ -1 +1 @@
Subproject commit 285181d23b789492b4b0186be1cacf160e89672a Subproject commit 6693ca45140aa67df7a6b0622a98d8d5b59079a3