added option to load the game quickly by turning off some effects
This commit is contained in:
parent
80c06582be
commit
b099c97871
327
NS.py
327
NS.py
|
@ -1,13 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import argparse
|
||||
from random import randint, choice, random
|
||||
from math import pi
|
||||
from copy import copy
|
||||
from glob import iglob
|
||||
from os.path import basename, join
|
||||
from threading import Thread
|
||||
from serial import Serial, SerialException
|
||||
from serial.tools import list_ports
|
||||
from time import sleep
|
||||
from PIL import Image
|
||||
|
||||
|
@ -48,8 +47,22 @@ class NS(Game, Animation):
|
|||
NO_RESET_TIMEOUT = 3000
|
||||
|
||||
def __init__(self):
|
||||
# Specify possible arguments and parse the command line. If the -h flag is passed, the argparse library will
|
||||
# print a help message and end the program.
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--minimize-load-time", action="store_true")
|
||||
parser.add_argument("--serial-port")
|
||||
parser.add_argument("--audio-buffer-size", type=int, default=1024)
|
||||
parser.add_argument("--list-serial-ports", action="store_true")
|
||||
parser.add_argument("--no-serial", action="store_true")
|
||||
parser.add_argument("--show-config", action="store_true")
|
||||
arguments = parser.parse_known_args()[0]
|
||||
# Pre-initialize the mixer to use the specified buffer size in bytes. The default is set to 1024 to prevent lagging
|
||||
# on the Raspberry Pi.
|
||||
pygame.mixer.pre_init(44100, -16, 2, 1024)
|
||||
# Pygame will be loaded in here.
|
||||
Game.__init__(self)
|
||||
# Add type declarations for non-string config name/value pairs that aren't in the default PGFW config dict.
|
||||
self.get_configuration().type_declarations.add_chart(
|
||||
{
|
||||
"time":
|
||||
|
@ -63,15 +76,57 @@ class NS(Game, Animation):
|
|||
},
|
||||
"display":
|
||||
{
|
||||
"float": "attract-gif-alpha"
|
||||
"float": "attract-gif-alpha",
|
||||
"bool": "effects"
|
||||
},
|
||||
"system":
|
||||
{
|
||||
"bool": "minimize-load-time"
|
||||
}
|
||||
})
|
||||
# If a serial port was passed on the command line, override the config file setting
|
||||
if arguments.serial_port is not None:
|
||||
self.get_configuration().set("input", "arduino-port", arguments.serial_port)
|
||||
# Command line flag requesting minimal load time overrides config file setting
|
||||
if arguments.minimize_load_time:
|
||||
self.get_configuration().set("system", "minimize-load-time", True)
|
||||
# Turn off effects if minimal load time is requested. Minimal load time setting overrides display effects setting.
|
||||
if self.get_configuration("system", "minimize-load-time"):
|
||||
self.get_configuration().set("display", "effects", False)
|
||||
# Apply the no serial flag from the command line if requested
|
||||
if arguments.no_serial:
|
||||
self.get_configuration().set("input", "serial", False)
|
||||
# Print the configuration if requested on the command line
|
||||
if arguments.show_config:
|
||||
print(self.get_configuration())
|
||||
# Initialize the serial reader and launch a thread for reading from the serial port
|
||||
if self.serial_enabled():
|
||||
from serial import Serial, SerialException
|
||||
from serial.tools import list_ports
|
||||
# If a list of serial ports was requested, print detected ports and exit.
|
||||
if arguments.list_serial_ports:
|
||||
for port in list_ports.comports():
|
||||
print(f"Detected serial port: {port.device}")
|
||||
exit()
|
||||
# Open the port specified by the configuration or command line if it is found. If the specified port is not found,
|
||||
# open the first found serial port. If no serial ports are found, raise an exception.
|
||||
requested_port = self.get_configuration("input", "arduino-port")
|
||||
devices = [port.device for port in list_ports.comports()]
|
||||
if requested_port in devices:
|
||||
self.serial_reader = Serial(requested_port, timeout=.3)
|
||||
elif devices:
|
||||
self.serial_reader = Serial(devices[0], timeout=.3)
|
||||
else:
|
||||
raise SerialException("No serial port devices were detected. Use --no-serial for keyboard-only mode.")
|
||||
self.serial_kill = False
|
||||
self.serial_data = 0
|
||||
self.reset_arduino()
|
||||
self.serial_thread = Thread(target=self.read_serial)
|
||||
self.serial_thread.start()
|
||||
Animation.__init__(self, self)
|
||||
self.subscribe(self.respond, KEYDOWN)
|
||||
self.subscribe(self.respond, KEYUP)
|
||||
self.subscribe(self.respond)
|
||||
# for bgm in self.audio.bgm.values():
|
||||
# bgm.volume = 0.65
|
||||
ds = self.get_display_surface()
|
||||
self.background = Surface(ds.get_size())
|
||||
self.background.fill((0, 0, 0))
|
||||
|
@ -79,26 +134,11 @@ class NS(Game, Animation):
|
|||
self.tony = Tony(self)
|
||||
self.logo = Logo(self)
|
||||
self.title = Title(self)
|
||||
self.introduction = Introduction(self)
|
||||
self.ending = Ending(self)
|
||||
self.wipe = Wipe(self)
|
||||
self.dialogue = Dialogue(self)
|
||||
self.chemtrails = Chemtrails(self)
|
||||
self.boss = Boss(self)
|
||||
if self.serial_enabled():
|
||||
self.serial_kill = False
|
||||
self.serial_data = 0
|
||||
self.serial_reader = Serial(self.get_configuration("input", "arduino-port"),
|
||||
timeout=.3)
|
||||
self.reset_arduino()
|
||||
# for port in list_ports.comports():
|
||||
# print port.device
|
||||
# print "---"
|
||||
# ports = list_ports.grep(self.get_configuration("input", "arduino-port"))
|
||||
# for port in ports:
|
||||
# print port.device
|
||||
self.serial_thread = Thread(target=self.read_serial)
|
||||
self.serial_thread.start()
|
||||
self.last_press = get_ticks()
|
||||
self.register(self.blink_score, interval=500)
|
||||
self.play(self.blink_score)
|
||||
|
@ -107,7 +147,7 @@ class NS(Game, Animation):
|
|||
clear()
|
||||
|
||||
def serial_enabled(self):
|
||||
return self.get_configuration("input", "serial") and not self.check_command_line("-no-serial")
|
||||
return self.get_configuration("input", "serial")
|
||||
|
||||
def read_serial(self):
|
||||
while not self.serial_kill:
|
||||
|
@ -154,7 +194,7 @@ class NS(Game, Animation):
|
|||
def apply_serial(self):
|
||||
for ii, light in enumerate(self.platform.lights):
|
||||
light.pressed = bool(self.serial_data & (2 ** ii))
|
||||
# reset idle timer is a light is detected as pressed in serial data
|
||||
# reset idle timer if a light is detected as pressed in serial data
|
||||
if light.pressed:
|
||||
self.idle_elapsed = 0
|
||||
|
||||
|
@ -165,7 +205,6 @@ class NS(Game, Animation):
|
|||
self.title.reset()
|
||||
if not leave_wipe_running:
|
||||
self.wipe.reset()
|
||||
self.introduction.reset()
|
||||
self.ending.reset()
|
||||
self.boss.reset()
|
||||
self.chemtrails.reset()
|
||||
|
@ -188,6 +227,18 @@ class NS(Game, Animation):
|
|||
self.suppressing_input = False
|
||||
|
||||
def respond(self, event):
|
||||
"""
|
||||
Respond to keyboard input.
|
||||
|
||||
___ ___
|
||||
| O| P| These keyboard keys correspond to the floor pads.
|
||||
|___|___| (O = top left pad, P = top right pad, L = bottom left pad, ; = bottom right pad)
|
||||
| L| ;| Arrow keys can also be used.
|
||||
|___|___| (UP = top left pad, RIGHT = top right pad, DOWN = bottom left pad, LEFT = bottom right pad)
|
||||
|
||||
The Z key is a shortcut for reset (F8 also resets).
|
||||
The A key force resets the connected Arduino (or does nothing if no Arduino is connected).
|
||||
"""
|
||||
if not self.suppressing_input and event.type in (KEYDOWN, KEYUP):
|
||||
if self.last_press <= get_ticks() - int(self.get_configuration("input", "buffer")):
|
||||
pressed = True if event.type == KEYDOWN else False
|
||||
|
@ -215,8 +266,7 @@ class NS(Game, Animation):
|
|||
last_frame_duration = self.time_filter.get_last_frame_duration()
|
||||
if self.serial_enabled():
|
||||
self.apply_serial()
|
||||
if self.title.active or self.introduction.active or self.ending.active or \
|
||||
self.dialogue.active:
|
||||
if self.title.active or self.ending.active or self.dialogue.active:
|
||||
self.no_reset_elapsed += last_frame_duration
|
||||
# if we received good input, reset the auto reset timer
|
||||
if 0b11 <= self.serial_data <= 0b1100:
|
||||
|
@ -226,7 +276,6 @@ class NS(Game, Animation):
|
|||
self.reset_arduino()
|
||||
self.no_reset_elapsed = 0
|
||||
self.title.update()
|
||||
self.introduction.update()
|
||||
self.ending.update()
|
||||
self.boss.update()
|
||||
if not self.title.active:
|
||||
|
@ -337,18 +386,19 @@ class Tony(Sprite):
|
|||
self.board.load_from_path(self.get_resource("newTony/TonyArms"), True)
|
||||
self.effect = Sprite(self)
|
||||
dsr = self.get_display_surface().get_rect()
|
||||
for offset in range(12):
|
||||
w, h = dsr.w + 40, int(dsr.h * .65)
|
||||
glow = Surface((w, h), SRCALPHA)
|
||||
for ii, y in enumerate(range(h, 0, -8)):
|
||||
hue = range(240, 200, -2)[(ii - offset) % 12]
|
||||
alpha = min(100, int(round(y / float(h - 10) * 100)))
|
||||
color = get_hsla_color(hue, 100, 50, alpha)
|
||||
if ii == 0:
|
||||
aaellipse(glow, w // 2, y, w // 2 - 4, h // 20, color)
|
||||
ellipse(glow, w // 2, y, w // 2 - 4, h // 20, color)
|
||||
filled_ellipse(glow, w // 2, y, w // 2 - 4, h // 20, color)
|
||||
self.effect.add_frame(glow)
|
||||
if self.get_configuration("display", "effects"):
|
||||
for offset in range(12):
|
||||
w, h = dsr.w + 40, int(dsr.h * .65)
|
||||
glow = Surface((w, h), SRCALPHA)
|
||||
for ii, y in enumerate(range(h, 0, -8)):
|
||||
hue = range(240, 200, -2)[(ii - offset) % 12]
|
||||
alpha = min(100, int(round(y / float(h - 10) * 100)))
|
||||
color = get_hsla_color(hue, 100, 50, alpha)
|
||||
if ii == 0:
|
||||
aaellipse(glow, w // 2, y, w // 2 - 4, h // 20, color)
|
||||
ellipse(glow, w // 2, y, w // 2 - 4, h // 20, color)
|
||||
filled_ellipse(glow, w // 2, y, w // 2 - 4, h // 20, color)
|
||||
self.effect.add_frame(glow)
|
||||
self.effect.location.topleft = -20, int(dsr.h * .35)
|
||||
self.add_frame(load(self.get_resource("Big_Tony.png")).convert_alpha())
|
||||
self.load_from_path(self.get_resource("newTony/TonyShirtHead"), True)
|
||||
|
@ -416,7 +466,8 @@ class Video(Sprite):
|
|||
filled_circle(self.mask, rect.centerx, rect.centery, rect.centerx, (0, 0, 0, alpha))
|
||||
filled_circle(self.mask, rect.centerx, rect.centery, rect.centerx - 2, (255, 255, 255, alpha))
|
||||
self.add_frame(self.mask)
|
||||
self.play()
|
||||
if not self.get_configuration("system", "minimize-load-time"):
|
||||
self.play()
|
||||
|
||||
def shift_frame(self):
|
||||
Sprite.shift_frame(self)
|
||||
|
@ -430,17 +481,14 @@ class Video(Sprite):
|
|||
frame = smoothscale(
|
||||
fromstring(self.gif.convert("RGBA").tobytes(), self.gif.size, "RGBA"),
|
||||
(self.mask.get_width(), int(self.gif.width * self.gif.height / self.mask.get_width())))
|
||||
# frame = scale(
|
||||
# fromstring(self.gif.convert("RGBA").tobytes(), self.gif.size, "RGBA"),
|
||||
# (self.mask.get_width(), int(self.gif.width * self.gif.height / self.mask.get_width())))
|
||||
copy = self.mask.copy()
|
||||
rect = frame.get_rect()
|
||||
rect.bottom = copy.get_rect().bottom
|
||||
copy.blit(frame, rect, None, BLEND_RGBA_MIN)
|
||||
# copy.blit(frame, rect)
|
||||
self.clear_frames()
|
||||
self.add_frame(copy)
|
||||
|
||||
|
||||
class Logo(Sprite):
|
||||
|
||||
def __init__(self, parent):
|
||||
|
@ -708,180 +756,6 @@ class Dialogue(Animation):
|
|||
message.update()
|
||||
|
||||
|
||||
class Introduction(Animation):
|
||||
|
||||
TEXT = (
|
||||
"Hey, you lizard slime bag. It's me Giant Tony. " + \
|
||||
"Do you think you\ncan skate like me? Prove it!",
|
||||
"I'll even give you my board for this adventure. And ink my name\n" + \
|
||||
"on it. Now the power of Giant Tony pulses through you.",
|
||||
# "Before you go, show me you can scrape! Use your board to touch\n" + \
|
||||
"Before you play, show me you can scrape! Use your board to touch\n" + \
|
||||
"the glowing pads on the platform!", \
|
||||
# "Good job, lizard scum! Maybe now you're ready to take on Kool\n" + \
|
||||
"Good job, slime bag! Maybe now you're ready to take on Kool\n" + \
|
||||
"Man and his friends. Don't let me down!")
|
||||
SKATEBOARD_START = -30, -20
|
||||
TUTORIAL_MOVES = NS.S, NS.NE, NS.N, NS.E
|
||||
|
||||
def __init__(self, parent):
|
||||
Animation.__init__(self, parent)
|
||||
self.words = []
|
||||
for word in "hey you lizard slime bag show me you can scrape".split(" "):
|
||||
font = Font(self.get_resource(Dialogue.FONT_PATH), 96)
|
||||
sprite = RainbowSprite(self, font.render(word, True, (255, 0, 0)).convert_alpha(), 30)
|
||||
self.words.append(sprite)
|
||||
self.skateboard = Sprite(self)
|
||||
self.skateboard.load_from_path(self.get_resource("Introduction_skateboard.png"), True)
|
||||
self.slime_bag = Sprite(self)
|
||||
self.slime_bag.load_from_path(self.get_resource("Introduction_slime_bag.png"), True)
|
||||
self.slime_bag.load_from_path(self.get_resource("Introduction_slime_bag_board.png"), True)
|
||||
self.slime_bag.add_frameset([0], name="standing", switch=True)
|
||||
self.slime_bag.add_frameset([1], name="board")
|
||||
self.slime_bag.location.center = self.get_display_surface().get_rect().center
|
||||
self.tony_avatar = load(self.get_resource("Introduction_tony_avatar.png")).convert()
|
||||
self.advance_prompt = AdvancePrompt(self)
|
||||
self.skip_prompt = SkipPrompt(self, self.start_wipe)
|
||||
self.register(self.start, self.move_board, self.take_board, self.speak)
|
||||
|
||||
def reset(self):
|
||||
self.deactivate()
|
||||
self.slime_bag.set_frameset("standing")
|
||||
self.slime_bag.unhide()
|
||||
self.halt()
|
||||
self.skateboard.hide()
|
||||
self.text_index = 0
|
||||
self.tutorial_index = 0
|
||||
self.words_index = 0
|
||||
self.advance_prompt.reset()
|
||||
self.skip_prompt.reset()
|
||||
for word in self.words:
|
||||
word.location.center = self.get_display_surface().get_rect().centerx, 100
|
||||
word.hide()
|
||||
|
||||
def deactivate(self):
|
||||
self.active = False
|
||||
|
||||
def activate(self):
|
||||
self.active = True
|
||||
self.play(self.start, delay=3000, play_once=True)
|
||||
self.words[0].unhide()
|
||||
self.play(self.speak)
|
||||
# self.get_game().platform.unpress()
|
||||
|
||||
def speak(self):
|
||||
for ii in range(self.words_index + 1):
|
||||
self.words[ii].move(0, 12)
|
||||
if ii == self.words_index and self.words[ii].location.bottom > self.get_display_surface().get_rect().bottom - 40:
|
||||
if self.words_index < len(self.words) - 1:
|
||||
self.words_index += 1
|
||||
self.words[self.words_index].unhide()
|
||||
self.get_audio().play_sfx("talk")
|
||||
|
||||
def start(self):
|
||||
self.advance_prompt.cancel_first_press()
|
||||
dialogue = self.get_game().dialogue
|
||||
dialogue.activate()
|
||||
dialogue.set_avatar(self.tony_avatar)
|
||||
dialogue.set_name("???")
|
||||
# dialogue.show_text(self.TEXT[0])
|
||||
dialogue.show_text(self.TEXT[2])
|
||||
self.text_index = 0
|
||||
# temporary dialogue skip
|
||||
dialogue.set_name("Tony")
|
||||
self.slime_bag.hide()
|
||||
self.halt(self.move_board)
|
||||
self.take_board()
|
||||
platform = self.get_game().platform
|
||||
platform.activate()
|
||||
platform.set_glowing(platform.get_buttons_from_edges(
|
||||
[self.TUTORIAL_MOVES[self.tutorial_index]]))
|
||||
self.get_game().chemtrails.activate()
|
||||
self.text_index = 2
|
||||
|
||||
def give_board(self):
|
||||
self.skateboard.location.center = self.SKATEBOARD_START
|
||||
self.skateboard_step = get_step(self.skateboard.location.center, self.slime_bag.location.center, 2)
|
||||
self.skateboard.unhide()
|
||||
self.play(self.move_board)
|
||||
|
||||
def move_board(self):
|
||||
self.skateboard.move(*self.skateboard_step)
|
||||
if self.skateboard.location.colliderect(self.slime_bag.location.inflate(-30, -30)):
|
||||
self.halt(self.move_board)
|
||||
self.play(self.take_board, delay=2000, play_once=True)
|
||||
self.get_audio().play_sfx("go")
|
||||
|
||||
def take_board(self):
|
||||
self.skateboard.hide()
|
||||
self.slime_bag.set_frameset("board")
|
||||
|
||||
def activate_boss(self):
|
||||
self.deactivate()
|
||||
self.get_game().boss.start_level(0)
|
||||
|
||||
def start_wipe(self):
|
||||
self.get_game().wipe.start(self.activate_boss)
|
||||
|
||||
def update(self):
|
||||
if self.active:
|
||||
Animation.update(self)
|
||||
# dialogue = self.get_game().dialogue
|
||||
wipe = self.get_game().wipe
|
||||
if not wipe.is_playing() and not self.is_playing(self.start) and not self.text_index == 2:
|
||||
if self.advance_prompt.check_first_press():
|
||||
self.advance_prompt.press_first()
|
||||
elif self.advance_prompt.check_second_press():
|
||||
if dialogue.is_playing():
|
||||
dialogue.show_all()
|
||||
else:
|
||||
if self.text_index < len(self.TEXT) - 1:
|
||||
self.text_index += 1
|
||||
if self.text_index == 1:
|
||||
dialogue.set_name("Tony")
|
||||
self.give_board()
|
||||
elif self.text_index == 2:
|
||||
self.slime_bag.hide()
|
||||
self.halt(self.move_board)
|
||||
self.take_board()
|
||||
platform = self.get_game().platform
|
||||
platform.activate()
|
||||
platform.set_glowing(platform.get_buttons_from_edges(
|
||||
[self.TUTORIAL_MOVES[self.tutorial_index]]))
|
||||
self.get_game().chemtrails.activate()
|
||||
dialogue.show_text(self.TEXT[self.text_index])
|
||||
else:
|
||||
self.start_wipe()
|
||||
# self.get_game().platform.unpress()
|
||||
self.advance_prompt.cancel_first_press()
|
||||
elif not wipe.is_playing() and self.text_index == 2:
|
||||
platform = self.get_game().platform
|
||||
if platform.get_edge_pressed() == self.TUTORIAL_MOVES[self.tutorial_index]:
|
||||
self.tutorial_index += 1
|
||||
self.get_audio().play_sfx("land_0")
|
||||
if self.tutorial_index == len(self.TUTORIAL_MOVES):
|
||||
# self.text_index += 1
|
||||
# self.advance_prompt.cancel_first_press()
|
||||
platform.set_glowing([])
|
||||
self.start_wipe()
|
||||
# dialogue.show_text(self.TEXT[self.text_index])
|
||||
else:
|
||||
platform.set_glowing(platform.get_buttons_from_edges(
|
||||
[self.TUTORIAL_MOVES[self.tutorial_index]]))
|
||||
self.get_game().tony.update()
|
||||
self.slime_bag.update()
|
||||
self.skateboard.update()
|
||||
for word in self.words:
|
||||
word.update()
|
||||
self.get_game().platform.update()
|
||||
# self.get_game().dialogue.update()
|
||||
# if not wipe.is_playing() and not self.is_playing(self.start) and \
|
||||
# not self.text_index == 2:
|
||||
# self.advance_prompt.update()
|
||||
if not wipe.is_playing() and not self.text_index == 2:
|
||||
self.skip_prompt.update()
|
||||
|
||||
|
||||
class SkipPrompt(GameChild):
|
||||
|
||||
def __init__(self, parent, callback):
|
||||
|
@ -1469,9 +1343,17 @@ class Boss(Animation):
|
|||
|
||||
def __init__(self, parent):
|
||||
Animation.__init__(self, parent)
|
||||
self.kool_man = RainbowSprite(self, load(self.get_resource("Kool_man_waah.png")).convert_alpha(), 30)
|
||||
self.visitor = RainbowSprite(self, load(self.get_resource("Visitor.png")).convert_alpha(), 30)
|
||||
self.spoopy = RainbowSprite(self, load(self.get_resource("Spoopy.png")).convert_alpha(), 30)
|
||||
if self.get_configuration("display", "effects"):
|
||||
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)
|
||||
else:
|
||||
self.kool_man = Sprite(self)
|
||||
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.load_from_path("Spoopy.png", True)
|
||||
for sprite in self.kool_man, self.visitor, self.spoopy:
|
||||
sprite.location.topleft = 100, 0
|
||||
self.health = Health(self)
|
||||
|
@ -1925,7 +1807,10 @@ class Sword(Animation):
|
|||
swords = self.swords = []
|
||||
for root in "Sword_kool_man/", "Sword_visitor/", "Sword_spoopy/":
|
||||
swords.append([[], [], [], [], [], []])
|
||||
for path in sorted(iglob(join(self.get_resource(root), "*.png"))):
|
||||
base_image_paths = sorted(iglob(join(self.get_resource(root), "*.png")))
|
||||
if not self.get_configuration("display", "effects"):
|
||||
base_image_paths = [base_image_paths[0]]
|
||||
for path in base_image_paths:
|
||||
base = load(self.get_resource(path)).convert_alpha()
|
||||
for position in range(6):
|
||||
if position == NS.N or position == NS.S:
|
||||
|
|
79
README
79
README
|
@ -1,5 +1,78 @@
|
|||
Requires pyserial (https://pypi.org/project/pyserial/)
|
||||
Scrapeboard is an arcade game in development by Frank DeMarco (@diskmem) and Blake Andrews (@snakesandrews)
|
||||
|
||||
If you have Python Package Installer, you can run
|
||||
It requires a custom pad and board to play. To learn more about the project visit https://scrape.nugget.fun
|
||||
|
||||
pip install pyserial
|
||||
This repository can be used to run either the full arcade version or the keyboard-only mode for testing
|
||||
|
||||
################
|
||||
# REQUIREMENTS #
|
||||
################
|
||||
|
||||
The game requires Python and Pygame. The Python version used for development is Python 3.9. The Pygame version
|
||||
is 1.9.6.
|
||||
|
||||
To install python with pip:
|
||||
|
||||
pip install pygame
|
||||
|
||||
Once Python and Pygame are installed, you should be able to run either:
|
||||
|
||||
./OPEN-GAME
|
||||
|
||||
or
|
||||
|
||||
./OPEN-GAME --no-serial
|
||||
|
||||
to start the game in either full arcade mode or keyboard only mode. See below for more about serial input and
|
||||
keyboard input modes.
|
||||
|
||||
##########
|
||||
# SERIAL #
|
||||
##########
|
||||
|
||||
To run the game using the custom skateboard and dance pads, the Arduino attached to the pads must be plugged
|
||||
into USB, and the pyserial package must be installed on this computer (https://pypi.org/project/pyserial/)
|
||||
|
||||
If you have Python Package Installer, you can run this to install pyserial:
|
||||
|
||||
pip install pyserial
|
||||
|
||||
The Arduino must be loaded with the program at serial/serial2/serial2.ino and connected to USB. The game
|
||||
will try to detect the Arduino, but to specify a specific port you can use the config file or command
|
||||
line.
|
||||
|
||||
If you don't have the board, pad and Arduino, you can test the game using keyboard-only mode.
|
||||
|
||||
########
|
||||
# KEYS #
|
||||
########
|
||||
|
||||
For testing, there is keyboard input. To run in keyboard only mode use:
|
||||
|
||||
./OPEN-GAME --no-serial
|
||||
|
||||
The O, P, L, and ; keys simulate the dance pads and your fingers simulate the board
|
||||
|
||||
___ ___
|
||||
| O| P| <-- These keyboard keys correspond to the floor pads
|
||||
|___|___| O = top left pad, P = top right pad, L = bottom left pad, ; = bottom right pad
|
||||
| L| ;|
|
||||
|___|___| or you can use arrow keys
|
||||
UP = top left pad, RIGHT = top right pad, DOWN = bottom left pad, LEFT = bottom right pad
|
||||
|
||||
Other keys:
|
||||
|
||||
The Z key is a shortcut for reset (F8 also resets).
|
||||
The A key force resets the connected Arduino (or does nothing if no Arduino is connected).
|
||||
|
||||
###########
|
||||
# OPTIONS #
|
||||
###########
|
||||
|
||||
The full list of configurable values is in the file called `config`. There are also command line flags that
|
||||
can override config values:
|
||||
|
||||
./OPEN-GAME -h
|
||||
|
||||
The --minimize-load-time flag can be useful when testing because it sacrifices some effects to load the game
|
||||
quickly.
|
||||
|
|
27
config
27
config
|
@ -1,7 +1,7 @@
|
|||
[setup]
|
||||
license = Public Domain
|
||||
title = Scrapeboard
|
||||
url = http://shampoo.ooo/games/esb
|
||||
url = https://scrape.nugget.fun
|
||||
version = 0.2.3
|
||||
init-script = OPEN-GAME
|
||||
additional-packages = lib
|
||||
|
@ -9,13 +9,18 @@ data-exclude = local/, *.pyc, .git*, README, build/, dist/, *.egg-info, *.py, MA
|
|||
|
||||
[display]
|
||||
caption = Scrapeboard
|
||||
show-framerate = False
|
||||
show-framerate = no
|
||||
dimensions = 640, 480
|
||||
fullscreen = False
|
||||
fullscreen = no
|
||||
attract-gif-alpha = 0.95
|
||||
effects = yes
|
||||
|
||||
[system]
|
||||
# will force set display->effects to off
|
||||
minimize-load-time = yes
|
||||
|
||||
[mouse]
|
||||
visible = False
|
||||
visible = no
|
||||
|
||||
[keys]
|
||||
quit = K_ESCAPE
|
||||
|
@ -23,12 +28,12 @@ up = K_u
|
|||
|
||||
[audio]
|
||||
sfx-volume = 0.8
|
||||
panel-enabled = True
|
||||
panel-enabled = yes
|
||||
volume = 1.0
|
||||
|
||||
[input]
|
||||
buffer = 0
|
||||
arduino-port = /dev/ttyACM1
|
||||
arduino-port = /dev/ttyACM0
|
||||
serial = True
|
||||
|
||||
[time]
|
||||
|
@ -40,11 +45,11 @@ attract-gif-length = 10000
|
|||
attract-board-length = 3600
|
||||
|
||||
[bgm]
|
||||
title = resource/bgm/title.ogg, 1.00
|
||||
level_0 = /home/frank/storage/audio/bgm/bat-tree-habitat-key/level-0.wav, 1.00
|
||||
level_1 = /home/frank/storage/audio/bgm/esp-hadouken/Cube-Levers.ogg, 1.00
|
||||
level_2 = /home/frank/storage/audio/bgm/esp-hadouken/Bog.ogg, 1.00
|
||||
end = /home/frank/storage/audio/bgm/phone-call-from-dark-magnet.wav, 1.00
|
||||
title = resource/bgm/title.ogg, .65
|
||||
level_0 = /home/frank/storage/audio/bgm/bat-tree-habitat-key/level-0.wav, .65
|
||||
level_1 = /home/frank/storage/audio/bgm/esp-hadouken/Cube-Levers.ogg, .65
|
||||
level_2 = /home/frank/storage/audio/bgm/esp-hadouken/Bog.ogg, .65
|
||||
end = /home/frank/storage/audio/bgm/phone-call-from-magnet.wav, .65
|
||||
|
||||
[pads]
|
||||
nw_color = #00FF88
|
||||
|
|
Loading…
Reference in New Issue