score box

This commit is contained in:
Frank DeMarco 2015-07-21 17:44:07 -04:00
parent c5e62360a4
commit 539e61c054
28 changed files with 180 additions and 2915 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "lib/pgfw"]
path = lib/pgfw
url = makar:/var/www/git/pgfw

97
SIL.txt Normal file
View File

@ -0,0 +1,97 @@
Copyright (c) 2010 Dimitar Toshkov Zhekov,
with Reserved Font Name "Terminus Font".
Copyright (c) 2011 Tilman Blumenbach,
with Reserved Font Name "Terminus (TTF)".
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

1
config
View File

@ -15,6 +15,7 @@ caption = Electric Sieve
dimensions = 420, 700
score-font-path = font/Titan-One.ttf
title-font-path = font/Oxygen.ttf
scoreboard-font-path = font/terminus/Terminus.ttf
[mouse]
visible = no

View File

@ -9,9 +9,10 @@ from pygame.font import Font
from pygame.mixer import Sound
from pygame.locals import *
from electric_sieve.pgfw.Game import Game
from electric_sieve.pgfw.GameChild import GameChild
from electric_sieve.pgfw.Sprite import Sprite
from lib.pgfw.pgfw.Game import Game
from lib.pgfw.pgfw.GameChild import GameChild
from lib.pgfw.pgfw.Sprite import Sprite
from lib.pgfw.pgfw.extension import render_box
class ElectricSieve(Game):
@ -53,27 +54,27 @@ class Title(GameChild):
for y in xrange(0, surface.get_height(), 2):
for x in xrange(0, surface.get_width(), 2):
surface.blit(tile, (x, y))
font = Font(self.get_resource("display", "title-font-path"), 20)
font.set_italic(True)
font.set_bold(True)
self.captions = captions = Sprite(self), Sprite(self)
colors = (0, 68, 170), (255, 255, 255), (128, 128, 128), \
(220, 119, 41), (255, 80, 80), (0, 90, 110)
texts = ["", ""]
for ii, text in \
enumerate(self.get_configuration("display",
"caption").upper().split()):
texts[ii] += "" * (5 if ii else 3)
for ch in text:
texts[ii] += ch + " "
texts[ii] = texts[ii].strip() + "" * (5 if ii else 3)
for _ in xrange(25):
color = choice(colors)
captions[0].add_frame(font.render(texts[0], True, color, (220, 208, 255)))
captions[1].add_frame(font.render(texts[1], True, color, (220, 208, 255)))
cx = self.display_surface.get_rect().centerx
captions[0].location.center = cx, 301
captions[1].location.center = cx, 398
# font = Font(self.get_resource("display", "title-font-path"), 20)
# font.set_italic(True)
# font.set_bold(True)
# self.captions = captions = Sprite(self), Sprite(self)
# colors = (0, 68, 170), (255, 255, 255), (128, 128, 128), \
# (220, 119, 41), (255, 80, 80), (0, 90, 110)
# texts = ["", ""]
# for ii, text in \
# enumerate(self.get_configuration("display",
# "caption").upper().split()):
# texts[ii] += "•" * (5 if ii else 3)
# for ch in text:
# texts[ii] += ch + " "
# texts[ii] = texts[ii].strip() + "•" * (5 if ii else 3)
# for _ in xrange(25):
# color = choice(colors)
# captions[0].add_frame(font.render(texts[0], True, color, (220, 208, 255)))
# captions[1].add_frame(font.render(texts[1], True, color, (220, 208, 255)))
# cx = self.display_surface.get_rect().centerx
# captions[0].location.center = cx, 301
# captions[1].location.center = cx, 398
self.scoreboard = Scoreboard(self)
self.music = Sound(self.get_resource("audio", "title"))
self.advance = Sound(self.get_resource("audio", "title-advance"))
@ -99,8 +100,8 @@ class Title(GameChild):
def update(self):
if self.active:
self.display_surface.blit(self.background, (0, 0))
for caption in self.captions:
caption.update()
# for caption in self.captions:
# caption.update()
self.scoreboard.update()
@ -173,54 +174,70 @@ class Shift(GameChild):
return self.nodeset.get_y(self.time) * self.direction
class Scoreboard(GameChild, Surface):
class Scoreboard(GameChild):
BACKGROUND = 255, 255, 255
FOREGROUND = 27, 27, 27
NEW = 27, 27, 27
SPACING = 70
MARGIN = 30
BLINK_INTERVAL = 400
def __init__(self, parent):
GameChild.__init__(self, parent)
Surface.__init__(self, (380, 80))
ds = self.display_surface = self.get_display_surface()
self.scores_path = self.get_resource("score", "path")
self.display_surface = self.get_display_surface()
self.most_recent_score = None
self.fill((255, 255, 255))
self.rect = self.get_rect()
self.rect.center = self.display_surface.get_rect().centerx, 350
self.load()
def load(self):
scores = []
for line in file(self.scores_path, "r"):
fields = line.split()
scores.append((float(fields[0]), int(fields[1])))
scores.append((float(fields[0]), int(fields[1]), fields[2]))
self.sprites = sprites = []
font_path = self.get_resource("display", "score-font-path")
y = 0
font_path = self.get_resource("display", "scoreboard-font-path")
sizes = [14] * 5
for ii, score in enumerate(sorted(scores, key=lambda score: score[1],
reverse=True)[:3]):
font = Font(font_path, [40, 24, 16][ii])
sprites.append(Sprite(self, 250))
text = str(score[1])
color = (0, 0, 0) if not (score[1] == self.most_recent_score) else \
(255, 255, 255)
sprites[ii].add_frame(font.render(text, True, color,
(255, 255, 255)))
reverse=True)[:len(sizes)]):
font = Font(font_path, sizes[ii])
sprites.append((Sprite(self, self.BLINK_INTERVAL),
Sprite(self, self.BLINK_INTERVAL)))
score_text = str(score[1])
color = self.FOREGROUND if not (score[1] == self.most_recent_score) else \
self.BACKGROUND
score_plate = font.render(score_text, False, color, self.BACKGROUND)
rect = score_plate.get_rect()
surface = Surface(rect.inflate((2, 2)).size)
surface.fill(self.FOREGROUND)
rect.center = surface.get_rect().center
surface.blit(score_plate, rect)
sprites[ii][1].add_frame(render_box(font, score_text, False, color,
self.BACKGROUND, self.FOREGROUND, 1, 2))
sprites[ii][0].add_frame(render_box(font, score[2], False, color,
self.BACKGROUND, self.FOREGROUND, 1, 2))
if score[1] == self.most_recent_score:
sprites[ii].add_frame(font.render(text, True, (0, 255, 0),
(255, 255, 255)))
sprites[ii].location.midtop = self.rect.w / 2, y
y += sprites[ii].location.h
sprites[ii].display_surface = self
sprites[ii][1].add_frame(render_box(font, score_text, False, self.NEW,
self.BACKGROUND, self.FOREGROUND, 1, 2))
sprites[ii][0].add_frame(render_box(font, score[2], False, self.NEW,
self.BACKGROUND, self.FOREGROUND, 1, 2))
sprites[ii][0].location.left = self.MARGIN
sprites[ii][1].location.right = self.get_display_surface().get_rect().right - self.MARGIN
y = self.get_display_surface().get_rect().centery + self.SPACING * (ii - len(sizes) / 2)
for sprite in sprites[ii]:
sprite.location.centery = y
def write(self):
score = int(round(self.get_game().triangles.score))
file(self.scores_path, "a").write(str(time()) + " " + str(score) + "\n")
file(self.scores_path, "a").write(str(time()) + " " + str(score) + " " + "SIV" + "\n")
self.most_recent_score = score
self.load()
def update(self):
self.fill((255, 255, 255))
for sprite in self.sprites:
sprite.update()
self.display_surface.blit(self, self.rect)
for pair in self.sprites:
for sprite in pair:
sprite.update()
class Sieve(Strip):

View File

@ -1,134 +0,0 @@
from GameChild import GameChild
class Animation(GameChild):
def __init__(self, parent, method=None, interval=None, unfiltered=False):
GameChild.__init__(self, parent)
self.unfiltered = unfiltered
self.default_method = method or self.build_frame
self.accounts = {}
self.register(self.default_method, interval=interval)
self.current_elapsed = 0
self.last_update = 0
def build_frame(self):
pass
def register(self, *args, **kwargs):
interval = None
if kwargs.has_key("interval"):
interval = kwargs["interval"]
for method in args:
if method not in self.accounts:
self.accounts[method] = Account(interval, self)
else:
self.accounts[method].set_interval(interval)
def play(self, method=None, interval=None, delay=0, play_once=False,
**kwargs):
account = self.accounts[self.get_default(method)]
account.set_delay(delay)
account.set_args(kwargs)
account.set_play_once(play_once)
if interval:
account.set_interval(interval)
account.play()
def get_default(self, method):
if not method:
method = self.default_method
return method
def halt(self, method=None):
if not method:
for account in self.accounts.values():
account.halt()
else:
if self.accounts.has_key(method):
self.accounts[method].halt()
def is_playing(self, method=None, check_all=False, include_delay=False):
if check_all:
return any(self.is_account_playing(account, include_delay) for \
method, account in self.accounts.iteritems())
return self.is_account_playing(self.accounts[self.get_default(method)],
include_delay)
def is_account_playing(self, account, include_delay):
return account.playing and (not include_delay or not account.delay)
def update(self):
for method, account in self.accounts.iteritems():
if account.update():
method(**account.args)
class Account:
def __init__(self, interval, animation):
self.animation = animation
self.time_filter = animation.get_game().time_filter
self.set_interval(interval)
self.set_delay(0)
self.set_play_once(False)
self.interval_index = 0
self.last_frame = 0
self.halt()
def set_interval(self, interval):
if isinstance(interval, int) or isinstance(interval, str):
interval = [interval]
self.interval = interval
def set_delay(self, delay):
self.delay = delay
def set_play_once(self, play_once):
self.play_once = play_once
def set_args(self, args):
self.args = args
def play(self):
self.playing = True
def halt(self):
self.last_update = None
self.playing = False
def update(self):
if self.playing:
if self.animation.unfiltered:
ticks = self.time_filter.get_unfiltered_ticks()
else:
ticks = self.time_filter.get_ticks()
self.update_delay(ticks)
if not self.delay:
interval = self.interval
if interval:
if ticks - self.last_frame < self.get_current_interval():
return False
self.last_frame = ticks
self.increment_interval_index()
if self.play_once:
self.halt()
return True
def get_current_interval(self):
return self.interval[self.interval_index]
def increment_interval_index(self):
index = self.interval_index + 1
if index >= len(self.interval):
index = 0
self.interval_index = index
def update_delay(self, ticks):
delay = self.delay
if delay > 0:
last_update = self.last_update or ticks
delay -= ticks - last_update
if delay < 0:
delay = 0
self.last_update = ticks
self.delay = delay

View File

@ -1,92 +0,0 @@
from os import listdir
from os.path import join
from pygame.mixer import Channel, Sound, music, find_channel
from GameChild import *
from Input import *
class Audio(GameChild):
current_channel = None
paused = False
muted = False
def __init__(self, game):
GameChild.__init__(self, game)
self.delegate = self.get_delegate()
self.load_fx()
self.subscribe(self.respond)
def load_fx(self):
fx = {}
if self.get_configuration().has_option("audio", "sfx-path"):
root = self.get_resource("audio", "sfx-path")
if root:
for name in listdir(root):
fx[name.split(".")[0]] = Sound(join(root, name))
self.fx = fx
def respond(self, event):
if self.delegate.compare(event, "mute"):
self.mute()
def mute(self):
self.muted = True
self.set_volume()
def unmute(self):
self.muted = False
self.set_volume()
def set_volume(self):
volume = int(not self.muted)
music.set_volume(volume)
if self.current_channel:
self.current_channel.set_volume(volume)
def play_bgm(self, path, stream=False):
self.stop_current_channel()
if stream:
music.load(path)
music.play(-1)
else:
self.current_channel = Sound(path).play(-1)
self.set_volume()
def stop_current_channel(self):
music.stop()
if self.current_channel:
self.current_channel.stop()
self.current_channel = None
self.paused = False
def play_fx(self, name, panning=.5):
if not self.muted:
channel = find_channel(True)
if panning != .5:
offset = 1 - abs(panning - .5) * 2
if panning < .5:
channel.set_volume(1, offset)
else:
channel.set_volume(offset, 1)
channel.play(self.fx[name])
def pause(self):
channel = self.current_channel
paused = self.paused
if paused:
music.unpause()
if channel:
channel.unpause()
else:
music.pause()
if channel:
channel.pause()
self.paused = not paused
def is_bgm_playing(self):
current = self.current_channel
if current and current.get_sound():
return True
return music.get_busy()

View File

@ -1,442 +0,0 @@
from os import sep, getcwd
from os.path import join, exists, basename, dirname, expanduser
from sys import argv
from re import match
from pprint import pformat
from ConfigParser import RawConfigParser
class Configuration(RawConfigParser):
default_project_file_rel_path = "config"
default_resource_paths = [".", "resource"]
def __init__(self, project_file_rel_path=None, resource_path=None,
type_declarations=None):
RawConfigParser.__init__(self)
self.project_file_rel_path = project_file_rel_path
self.resource_path = resource_path
self.modifiable = {}
self.order = []
self.set_type_declarations(type_declarations)
self.set_defaults()
self.read_project_config_file()
self.modify_defaults()
self.print_debug(self)
def set_type_declarations(self, type_declarations):
if type_declarations is None:
type_declarations = TypeDeclarations()
self.type_declarations = type_declarations
def translate_path(self, path):
new = ""
if path and path[0] == sep:
new += sep
return expanduser("{0}{1}".format(new, join(*path.split(sep))))
def set_defaults(self):
add_section = self.add_section
set_option = self.set
section = "setup"
add_section(section)
set_option(section, "package-root", basename(getcwd()), False)
set_option(section, "additional-packages", "", False)
set_option(section, "title", "", False)
set_option(section, "classifiers", "", False)
set_option(section, "resource-search-path", "./, resource/", False)
set_option(section, "installation-dir", "/usr/local/share/games/",
False)
set_option(section, "changelog", "changelog", False)
set_option(section, "description-file", "", False)
set_option(section, "init-script", "", False)
set_option(section, "version", "", False)
set_option(section, "summary", "", False)
set_option(section, "license", "", False)
set_option(section, "platforms", "", False)
set_option(section, "contact-name", "", False)
set_option(section, "contact-email", "", False)
set_option(section, "url", "", False)
set_option(section, "requirements", "", False)
set_option(section, "main-object", "pgfw/Game.py", False)
set_option(section, "resource-path-identifier", "resource_path", False)
set_option(section, "special-char-placeholder", "_", False)
set_option(section, "whitespace-placeholder", "-", False)
set_option(section, "windows-dist-path", "dist/win/", False)
set_option(section, "windows-icon-path", "", False)
set_option(section, "lowercase-boolean-true", "yes", False)
section = "display"
add_section(section)
set_option(section, "dimensions", "480, 360", False)
set_option(section, "frame-duration", "40", False)
set_option(section, "wait-duration", "2", False)
set_option(section, "caption", "", False)
set_option(section, "centered", "yes", False)
set_option(section, "icon-path", "", False)
set_option(section, "skip-frames", "no", False)
set_option(section, "fullscreen", "no", False)
set_option(section, "windowed-flag", "wi", False)
set_option(section, "show-framerate", "no", False)
set_option(section, "framerate-display-flag", "fr", False)
set_option(section, "framerate-text-size", "16", False)
set_option(section, "framerate-text-color", "0, 0, 0", False)
set_option(section, "framerate-text-background", "255, 255, 255", False)
section = "input"
add_section(section)
set_option(section, "release-suffix", "-release", False)
section = "sprite"
add_section(section)
set_option(section, "transparent-color", "magenta", False)
section = "screen-captures"
add_section(section)
set_option(section, "rel-path", "caps", False)
set_option(section, "file-name-format", "%Y%m%d%H%M%S", False)
set_option(section, "file-extension", "png", False)
section = "video-recordings"
add_section(section)
set_option(section, "rel-path", "vids", False)
set_option(section, "directory-name-format", "%Y%m%d%H%M%S", False)
set_option(section, "file-extension", "png", False)
set_option(section, "frame-format", "RGB", False)
set_option(section, "framerate", "100", False)
section = "mouse"
add_section(section)
set_option(section, "visible", "yes", False)
set_option(section, "double-click-time-limit", ".5", False)
section = "keys"
add_section(section)
set_option(section, "up", "K_UP, K_w", False)
set_option(section, "right", "K_RIGHT, K_d", False)
set_option(section, "down", "K_DOWN, K_s", False)
set_option(section, "left", "K_LEFT, K_a", False)
set_option(section, "capture-screen", "K_F9", False)
set_option(section, "toggle-fullscreen", "K_F11", False)
set_option(section, "reset-game", "K_F8", False)
set_option(section, "record-video", "K_F10", False)
set_option(section, "mute", "K_F12", False)
set_option(section, "toggle-interpolator", "K_F7", False)
section = "joy"
add_section(section)
set_option(section, "advance", "7", False)
set_option(section, "pause", "7", False)
set_option(section, "select", "6", False)
section = "event"
add_section(section)
set_option(section, "user-event-id", "USEREVENT", False)
set_option(section, "command-id-offset", "1", False)
set_option(section, "command-key", "command", False)
set_option(section, "cancel-flag-key", "cancel", False)
section = "audio"
add_section(section)
set_option(section, "sfx-path", "aud/fx/", False)
section = "interpolator-gui"
add_section(section)
set_option(section, "margin", "80", False)
set_option(section, "marker-color", "255, 0, 0", False)
set_option(section, "marker-size", "11", False)
set_option(section, "curve-color", "0, 255, 0", False)
set_option(section, "label-size", "16", False)
set_option(section, "label-precision", "2", False)
set_option(section, "axis-label-count", "8", False)
set_option(section, "prompt-size", "380, 60", False)
set_option(section, "prompt-border-color", "255, 0, 0", False)
set_option(section, "prompt-border-width", "3", False)
set_option(section, "prompt-character-limit", "21", False)
set_option(section, "prompt-text-size", "42", False)
set_option(section, "template-nodeset", "L 0 0, 1000 1", False)
set_option(section, "template-nodeset-name", "template", False)
set_option(section, "flat-y-range", "1", False)
def add_section(self, name):
if name not in self.order:
self.order.append(name)
RawConfigParser.add_section(self, name)
def set(self, section, option, value, modifiable=True):
if modifiable:
if section not in self.order:
self.order.append(section)
if section not in self.modifiable:
self.modifiable[section] = []
if option not in self.modifiable[section]:
self.modifiable[section].append(option)
RawConfigParser.set(self, section, option, value)
def read_project_config_file(self):
path = self.locate_project_config_file()
if path:
fp = open(path)
self.set_modifiable(fp)
fp.seek(0)
self.readfp(fp)
fp.seek(0)
self.set_order(fp)
fp.close()
else:
self.print_debug("No configuration file found")
def locate_project_config_file(self):
rel_path = self.project_file_rel_path
if not rel_path:
rel_path = self.default_project_file_rel_path
if exists(rel_path) and not self.is_shared_mode():
return rel_path
if self.resource_path:
installed_path = join(self.resource_path, rel_path)
if exists(installed_path):
return installed_path
def set_order(self, fp):
self.order = order = []
for line in file(self.locate_project_config_file()):
result = match("^\s*\[(.*)\]\s*$", line)
if result:
order.append(result.group(1))
def set_modifiable(self, fp):
config = RawConfigParser()
config.readfp(fp)
modifiable = self.modifiable
for section in config._sections:
if section not in modifiable:
modifiable[section] = []
for option in config._sections[section]:
if option != "__name__" and option not in modifiable[section]:
modifiable[section].append(option)
def is_shared_mode(self):
return "-s" in argv
def print_debug(self, statement):
if self.is_debug_mode():
print statement
def is_debug_mode(self):
return "-d" in argv
def modify_defaults(self):
self.set_installation_path()
self.set_resource_search_path()
self.set_screen_captures_path()
self.set_video_recordings_path()
self.set_data_exclusion_list()
self.set_requirements()
def set_installation_path(self):
self.set("setup", "installation-path",
join(self.get("setup", "installation-dir"),
self.get("setup", "package-root")), False)
def set_resource_search_path(self):
section, option = "setup", "resource-search-path"
search_path = self.get(section, option)
if self.resource_path:
search_path.append(self.resource_path)
else:
search_path.append(self.get("setup", "installation-path"))
self.set(section, option, search_path, False)
def get(self, section, option):
value = RawConfigParser.get(self, section, option)
if value is None:
value = self.get_substitute(section, option)
return self.cast_value(section, option, value)
def get_substitute(self, section, option):
if section == "display":
if option == "caption":
return self.get("setup", "title")
def cast_value(self, section, option, value):
pair = section, option
types = self.type_declarations
if type(value) == str:
if pair in types["bool"]:
if value.lower() == self.get("setup", "lowercase-boolean-true"):
return True
return False
elif pair in types["int"]:
return int(value)
elif pair in types["float"]:
return float(value)
elif pair in types["path"]:
return self.translate_path(value)
elif pair in types["list"]:
if value == "":
return []
else:
return map(str.strip, value.split(types.list_member_sep))
elif pair in types["int-list"]:
return map(int, value.split(types.list_member_sep))
elif pair in types["float-list"]:
return map(float, value.split(types.list_member_sep))
return value
def set_screen_captures_path(self):
section, option = "screen-captures", "path"
if not self.has_option(section, option):
self.set(section, option, join(self.build_home_path(),
self.get(section, "rel-path")),
False)
def build_home_path(self):
return join("~", "." + self.get("setup", "package-root"))
def set_video_recordings_path(self):
section, option = "video-recordings", "path"
if not self.has_option(section, option):
self.set(section, option, join(self.build_home_path(),
self.get(section, "rel-path")),
False)
def set_data_exclusion_list(self):
section, option = "setup", "data-exclude"
exclude = []
if self.has_option(section, option):
exclude = self.get(section, option)
exclude += [".git", ".gitignore", "README", "build/", "dist/",
"setup.py", "MANIFEST", "PKG-INFO",
self.get("setup", "changelog"),
self.get("setup", "package-root")]
for location in self.get("setup", "additional-packages"):
exclude.append(location)
self.set(section, option, exclude, False)
def set_requirements(self):
section, option = "setup", "requirements"
requirements = []
if self.has_option(section, option):
requirements = self.get(section, option)
if "pygame" not in requirements:
requirements.append("pygame")
self.set(section, option, requirements, False)
def get_section(self, section):
assignments = {}
for option in self.options(section):
assignments[option] = self.get(section, option)
return assignments
def __repr__(self):
config = {}
for section in self.sections():
config[section] = self.get_section(section)
return pformat(config, 2, 1)
def items(self, section):
items = []
for option in self.options(section):
items.append((option, self.get(section, option)))
return items
def write(self, fp=None):
modifiable = self.modifiable
use_main = fp is None
if use_main:
path = self.locate_project_config_file()
if not path:
path = join(self.resource_path or "",
self.default_project_file_rel_path)
fp = open(path, "w")
break_line = False
for section in self.order:
if section in modifiable:
break_line and fp.write("\n")
fp.write("[%s]\n" % section)
for option in modifiable[section]:
if self.has_option(section, option):
value = self.get(section, option)
fp.write("%s = %s\n" % (option,
self.get_raw_value(value)))
break_line = True
if use_main:
fp.close()
def get_raw_value(self, value):
if isinstance(value, list):
raw = ""
for ii, value in enumerate(value):
if ii:
raw += ", "
raw += str(value)
else:
raw = str(value)
return raw
def clear_section(self, section):
if self.has_section(section):
for option in self.options(section):
self.remove_option(section, option)
class TypeDeclarations(dict):
list_member_sep = ','
defaults = {
"display": {"int": ["frame-duration", "wait-duration",
"framerate-text-size"],
"bool": ["centered", "skip-frames", "fullscreen",
"show-framerate"],
"int-list": ["dimensions", "framerate-text-color",
"framerate-text-background"]},
"screen-captures": {"path": ["rel-path", "path"]},
"video-recordings": {"path": ["rel-path", "path"],
"int": "framerate"},
"setup": {"list": ["classifiers", "resource-search-path",
"requirements", "data-exclude",
"additional-packages"],
"path": ["installation-dir", "changelog", "description-file",
"main-object", "icon-path", "windows-dist-path",
"package-root"]},
"mouse": {"float": "double-click-time-limit",
"bool": "visible"},
"keys": {"list": ["up", "right", "down", "left"]},
"joy": {"int": ["advance", "pause", "select"]},
"audio": {"path": "sfx-path"},
"event": {"int": "command-id-offset"},
"interpolator-gui": {"int": ["margin", "marker-size", "label-size",
"axis-label-count", "label-precision",
"prompt-border-width",
"prompt-character-limit",
"prompt-text-size", "flat-y-range"],
"int-list": ["marker-color", "curve-color",
"prompt-size",
"prompt-border-color"]},
}
additional_defaults = {}
def __init__(self):
dict.__init__(self, {"bool": [], "int": [], "float": [], "path": [],
"list": [], "int-list": [], "float-list": []})
self.add_chart(self.defaults)
self.add_chart(self.additional_defaults)
def add(self, cast, section, option):
self[cast].append((section, option))
def add_chart(self, chart):
for section, declarations in chart.iteritems():
for cast, options in declarations.iteritems():
if type(options) != list:
options = [options]
for option in options:
self.add(cast, section, option)

View File

@ -1,87 +0,0 @@
from pygame.event import get, pump, Event, post
from pygame.locals import *
from GameChild import GameChild
from Input import Input
class Delegate(GameChild):
def __init__(self, game):
GameChild.__init__(self, game)
self.subscribers = dict()
self.load_configuration()
self.disable()
def load_configuration(self):
config = self.get_configuration("event")
self.cancel_flag_key = config["cancel-flag-key"]
self.command_key = config["command-key"]
self.command_event_id = config["command-id-offset"] + \
globals()[config["user-event-id"]]
def disable(self):
self.enabled = False
def enable(self):
self.enabled = True
self.interpolator = self.get_game().interpolator
def dispatch(self):
if self.enabled:
subscribers = self.subscribers
for evt in get():
kind = evt.type
if kind in subscribers:
for subscriber in subscribers[kind]:
if not self.interpolator.is_gui_active() or \
hasattr(subscriber, "im_class") and \
(subscriber.im_class == Input or \
subscriber.im_class == \
self.interpolator.gui.__class__):
self.print_debug("Passing %s to %s" % (evt,
subscriber))
subscriber(evt)
else:
pump()
def add_subscriber(self, callback, kind=None):
self.print_debug("Subscribing %s to %s" % (callback, kind))
if kind is None:
kind = self.command_event_id
subscribers = self.subscribers
if kind not in subscribers:
subscribers[kind] = list()
subscribers[kind].append(callback)
def is_command(self, event):
return event.type == self.command_event_id
def remove_subscriber(self, callback, kind=None):
if kind is None:
kind = self.command_event_id
self.subscribers[kind].remove(callback)
def compare(self, evt, commands=None, cancel=False, **attributes):
if evt.type == self.command_event_id:
self.add_cancel_flag_to_attributes(attributes, cancel)
if commands is not None and not isinstance(commands, list):
commands = [commands]
if commands is not None:
if not self.command_in_list(evt, commands):
return False
return all(key in evt.dict and evt.dict[key] == value for \
key, value in attributes.iteritems())
def add_cancel_flag_to_attributes(self, attributes, cancel):
attributes[self.cancel_flag_key] = cancel
def command_in_list(self, evt, commands):
return self.get_command_attribute(evt) in commands
def get_command_attribute(self, evt):
return evt.dict[self.command_key]
def post(self, command=None, cancel=False, **attributes):
attributes[self.command_key] = command
self.add_cancel_flag_to_attributes(attributes, cancel)
post(Event(self.command_event_id, attributes))

View File

@ -1,81 +0,0 @@
from os import environ
from pygame import display, image, mouse
from pygame.locals import *
from GameChild import *
class Display(GameChild):
def __init__(self, game):
GameChild.__init__(self, game)
self.delegate = self.get_delegate()
self.load_configuration()
self.align_window()
self.init_screen()
self.set_caption()
self.set_icon()
self.set_mouse_visibility()
self.subscribe(self.toggle_fullscreen)
def load_configuration(self):
config = self.get_configuration("display")
self.centered = config["centered"]
self.fullscreen_enabled = config["fullscreen"]
self.caption = config["caption"]
self.windowed_flag = config["windowed-flag"]
self.icon_path = self.get_resource("display", "icon-path")
self.mouse_visibility = self.get_configuration("mouse", "visible")
def align_window(self):
if self.centered:
environ["SDL_VIDEO_CENTERED"] = "1"
def init_screen(self):
flags = 0
if self.fullscreen_requested():
flags = FULLSCREEN
self.set_screen(flags)
def fullscreen_requested(self):
return not self.check_command_line(self.windowed_flag) and \
self.fullscreen_enabled
def set_screen(self, flags=0, dimensions=None):
self.dimensions_changed = dimensions is not None
if dimensions is None:
if display.get_surface():
dimensions = display.get_surface().get_size()
else:
dimensions = self.get_configuration("display", "dimensions")
self.screen = display.set_mode(dimensions, flags)
if self.dimensions_changed:
interpolator = self.get_game().interpolator
if interpolator.gui_enabled:
interpolator.gui.rearrange()
def set_caption(self):
display.set_caption(self.caption)
def set_icon(self):
if self.icon_path:
print self.icon_path
display.set_icon(image.load(self.icon_path).convert_alpha())
def set_mouse_visibility(self, visibility=None):
if visibility is None:
visibility = self.mouse_visibility
return mouse.set_visible(visibility)
def get_screen(self):
return self.screen
def get_size(self):
return self.screen.get_size()
def toggle_fullscreen(self, event):
if self.delegate.compare(event, "toggle-fullscreen"):
screen = self.screen
cpy = screen.convert()
self.set_screen(self.screen.get_flags() ^ FULLSCREEN)
screen.blit(cpy, (0, 0))

View File

@ -1,74 +0,0 @@
import pygame
from pygame.locals import *
from GameChild import GameChild
from Mainloop import Mainloop
from Audio import Audio
from Display import Display
from Configuration import Configuration
from Delegate import Delegate
from Input import Input
from ScreenGrabber import ScreenGrabber
from Profile import Profile
from VideoRecorder import VideoRecorder
from Interpolator import Interpolator
from TimeFilter import TimeFilter
class Game(GameChild):
resource_path = None
def __init__(self, config_rel_path=None, type_declarations=None):
self.profile = Profile(self)
GameChild.__init__(self)
self.print_debug(pygame.version.ver)
self.config_rel_path = config_rel_path
self.type_declarations = type_declarations
self.set_configuration()
pygame.init()
self.set_children()
self.subscribe(self.end, QUIT)
self.subscribe(self.end)
self.delegate.enable()
def set_configuration(self):
self.configuration = Configuration(self.config_rel_path,
self.resource_path,
self.type_declarations)
def set_children(self):
self.time_filter = TimeFilter(self)
self.delegate = Delegate(self)
self.display = Display(self)
self.mainloop = Mainloop(self)
self.input = Input(self)
self.audio = Audio(self)
self.screen_grabber = ScreenGrabber(self)
self.video_recorder = VideoRecorder(self)
self.interpolator = Interpolator(self)
def frame(self):
self.time_filter.update()
self.delegate.dispatch()
if not self.interpolator.is_gui_active():
self.update()
else:
self.interpolator.gui.update()
self.video_recorder.update()
def run(self):
self.mainloop.run()
def update(self):
pass
def blit(self, source, destination, area=None, special_flags=0):
self.get_screen().blit(source, destination, area, special_flags)
def get_rect(self):
return self.get_screen().get_rect()
def end(self, evt):
if evt.type == QUIT or self.delegate.compare(evt, "quit"):
self.mainloop.stop()
self.profile.end()

View File

@ -1,85 +0,0 @@
from os.path import exists, join, basename, normpath, abspath
from sys import argv
from pygame import mixer, event, time
from pygame.locals import *
import Game
class GameChild:
def __init__(self, parent=None):
self.parent = parent
self.game = self.get_game()
def get_game(self):
current = self
while not isinstance(current, Game.Game):
current = current.parent
return current
def get_configuration(self, section=None, option=None):
config = self.game.configuration
if option and section:
return config.get(section, option)
if section:
return config.get_section(section)
return config
def get_input(self):
return self.game.input
def get_screen(self):
return self.game.display.get_screen()
def get_display_surface(self):
current = self
attribute = "display_surface"
while not isinstance(current, Game.Game):
if hasattr(current, attribute):
return getattr(current, attribute)
current = current.parent
return current.display.get_screen()
def get_audio(self):
return self.game.audio
def get_delegate(self):
return self.game.delegate
def get_resource(self, path_or_section, option=None):
config = self.get_configuration()
rel_path = path_or_section
if option is not None:
rel_path = config.get(path_or_section, option)
if rel_path:
for root in config.get("setup", "resource-search-path"):
if self.is_shared_mode() and not self.is_absolute_path(root):
continue
path = join(root, rel_path)
if exists(path):
return path
self.print_debug("Couldn't find resource: {0} {1}".\
format(path_or_section, option))
def is_shared_mode(self):
return self.check_command_line("s")
def check_command_line(self, flag):
return "-" + flag in argv
def print_debug(self, statement):
if self.is_debug_mode():
print statement
def is_debug_mode(self):
return self.check_command_line("d")
def is_absolute_path(self, path):
return normpath(path) == abspath(path)
def subscribe(self, callback, kind=None):
self.game.delegate.add_subscriber(callback, kind)
def unsubscribe(self, callback, kind=None):
self.game.delegate.remove_subscriber(callback, kind)

View File

@ -1,204 +0,0 @@
from time import time as get_secs
from pygame import joystick as joy
from pygame.key import get_pressed
from pygame.locals import *
from GameChild import *
class Input(GameChild):
def __init__(self, game):
GameChild.__init__(self, game)
self.last_mouse_down_left = None
self.joystick = Joystick()
self.delegate = self.get_delegate()
self.load_configuration()
self.set_any_press_ignore_list()
self.unsuppress()
self.subscribe_to_events()
self.build_key_map()
self.build_joy_button_map()
def load_configuration(self):
self.release_suffix = self.get_configuration("input", "release-suffix")
self.key_commands = self.get_configuration().items("keys")
self.double_click_time_limit = self.get_configuration(
"mouse", "double-click-time-limit")
def set_any_press_ignore_list(self):
self.any_press_ignored = set(["capture-screen", "toggle-fullscreen",
"reset-game", "record-video", "quit",
"mute", "toggle-interpolator"])
self.any_press_ignored_keys = set()
def unsuppress(self):
self.suppressed = False
def subscribe_to_events(self):
self.subscribe(self.translate_key, KEYDOWN)
self.subscribe(self.translate_key, KEYUP)
self.subscribe(self.translate_joy_button, JOYBUTTONDOWN)
self.subscribe(self.translate_joy_button, JOYBUTTONUP)
self.subscribe(self.translate_axis_motion, JOYAXISMOTION)
self.subscribe(self.translate_mouse_input, MOUSEBUTTONDOWN)
self.subscribe(self.translate_mouse_input, MOUSEBUTTONUP)
def build_key_map(self):
key_map = {}
for command, keys in self.key_commands:
key_map[command] = []
if type(keys) == str:
keys = [keys]
for key in keys:
key_map[command].append(globals()[key])
self.key_map = key_map
def build_joy_button_map(self):
self.joy_button_map = self.get_configuration("joy")
def suppress(self):
self.suppressed = True
def translate_key(self, event):
if not self.suppressed:
cancel = event.type == KEYUP
posted = None
key = event.key
for cmd, keys in self.key_map.iteritems():
if key in keys:
self.post_command(cmd, cancel=cancel)
posted = cmd
if (not posted or posted not in self.any_press_ignored) and \
key not in self.any_press_ignored_keys:
self.post_any_command(key, cancel)
def post_command(self, cmd, **attributes):
self.delegate.post(cmd, **attributes)
def post_any_command(self, id, cancel=False):
self.post_command("any", id=id, cancel=cancel)
def translate_joy_button(self, event):
if not self.suppressed:
cancel = event.type == JOYBUTTONUP
posted = None
for command, button in self.joy_button_map.iteritems():
if button == event.button:
self.post_command(command, cancel=cancel)
posted = command
if not posted or posted not in self.any_press_ignored:
self.post_any_command(event.button, cancel)
def translate_axis_motion(self, event):
if not self.suppressed:
axis = event.axis
value = event.value
if not value:
for command in "up", "right", "down", "left":
self.post_command(command, cancel=True)
if command not in self.any_press_ignored:
self.post_any_command(command, True)
else:
if axis == 1:
if value < 0:
command = "up"
elif value > 0:
command = "down"
else:
if value > 0:
command = "right"
elif value < 0:
command = "left"
self.post_command(command)
if command not in self.any_press_ignored:
self.post_any_command(command)
def is_command_active(self, command):
if not self.suppressed:
if self.is_key_pressed(command):
return True
joystick = self.joystick
joy_map = self.joy_button_map
if command in joy_map and joystick.get_button(joy_map[command]):
return True
if command == "up":
return joystick.is_direction_pressed(Joystick.up)
elif command == "right":
return joystick.is_direction_pressed(Joystick.right)
elif command == "down":
return joystick.is_direction_pressed(Joystick.down)
elif command == "left":
return joystick.is_direction_pressed(Joystick.left)
def is_key_pressed(self, command):
poll = get_pressed()
for key in self.key_map[command]:
if poll[key]:
return True
def translate_mouse_input(self, event):
button = event.button
pos = event.pos
post = self.post_command
if event.type == MOUSEBUTTONDOWN:
if button == 1:
last = self.last_mouse_down_left
if last:
limit = self.double_click_time_limit
if get_secs() - last < limit:
post("mouse-double-click-left", pos=pos)
last = get_secs()
self.last_mouse_down_left = last
def get_axes(self):
axes = {}
for direction in "up", "right", "down", "left":
axes[direction] = self.is_command_active(direction)
return axes
def register_any_press_ignore(self, *args, **attributes):
self.any_press_ignored.update(args)
self.any_press_ignored_keys.update(self.extract_keys(attributes))
def extract_keys(self, attributes):
keys = []
if "keys" in attributes:
keys = attributes["keys"]
if type(keys) == int:
keys = [keys]
return keys
def unregister_any_press_ignore(self, *args, **attributes):
self.any_press_ignored.difference_update(args)
self.any_press_ignored_keys.difference_update(
self.extract_keys(attributes))
class Joystick:
(up, right, down, left) = range(4)
def __init__(self):
js = None
if joy.get_count() > 0:
js = joy.Joystick(0)
js.init()
self.js = js
def is_direction_pressed(self, direction):
js = self.js
if not js or direction > 4:
return False
if direction == 0:
return js.get_axis(1) < 0
elif direction == 1:
return js.get_axis(0) > 0
elif direction == 2:
return js.get_axis(1) > 0
elif direction == 3:
return js.get_axis(0) < 0
def get_button(self, id):
if self.js:
return self.js.get_button(id)

View File

@ -1,733 +0,0 @@
from re import match
from os.path import join
from tempfile import gettempdir
from pygame import Surface
from pygame.font import Font
from pygame.draw import aaline
from pygame.locals import *
from GameChild import GameChild
from Sprite import Sprite
from Animation import Animation
class Interpolator(list, GameChild):
def __init__(self, parent):
GameChild.__init__(self, parent)
self.set_nodesets()
self.gui_enabled = self.check_command_line("-interpolator")
if self.gui_enabled:
self.gui = GUI(self)
def set_nodesets(self):
config = self.get_configuration()
if config.has_section("interpolate"):
for name, value in config.get_section("interpolate").iteritems():
self.add_nodeset(name, value)
def add_nodeset(self, name, value, method=None):
self.append(Nodeset(name, value, method))
return len(self) - 1
def is_gui_active(self):
return self.gui_enabled and self.gui.active
def get_nodeset(self, name):
for nodeset in self:
if nodeset.name == name:
return nodeset
def remove(self, outgoing):
for ii, nodeset in enumerate(self):
if nodeset.name == outgoing.name:
self.pop(ii)
break
class Nodeset(list):
LINEAR, CUBIC = range(2)
def __init__(self, name, nodes, method=None):
list.__init__(self, [])
self.name = name
if isinstance(nodes, str):
self.parse_raw(nodes)
else:
self.interpolation_method = method
self.parse_list(nodes)
self.set_splines()
def parse_raw(self, raw):
raw = raw.strip()
if raw[0].upper() == "L":
self.set_interpolation_method(self.LINEAR, False)
else:
self.set_interpolation_method(self.CUBIC, False)
for node in raw[1:].strip().split(","):
self.add_node(map(float, node.strip().split()), False)
def set_interpolation_method(self, method, refresh=True):
self.interpolation_method = method
if refresh:
self.set_splines()
def add_node(self, coordinates, refresh=True):
x = coordinates[0]
inserted = False
index = 0
for ii, node in enumerate(self):
if x < node.x:
self.insert(ii, Node(coordinates))
inserted = True
index = ii
break
elif x == node.x:
return None
if not inserted:
self.append(Node(coordinates))
index = len(self) - 1
if refresh:
self.set_splines()
return index
def parse_list(self, nodes):
for node in nodes:
self.add_node(node)
def set_splines(self):
if self.interpolation_method == self.LINEAR:
self.set_linear_splines()
else:
self.set_cubic_splines()
def set_linear_splines(self):
self.splines = splines = []
for ii in xrange(len(self) - 1):
x1, y1, x2, y2 = self[ii] + self[ii + 1]
m = float(y2 - y1) / (x2 - x1)
splines.append(LinearSpline(x1, y1, m))
def set_cubic_splines(self):
n = len(self) - 1
a = [node.y for node in self]
b = [None] * n
d = [None] * n
h = [self[ii + 1].x - self[ii].x for ii in xrange(n)]
alpha = [None] + [(3.0 / h[ii]) * (a[ii + 1] - a[ii]) - \
(3.0 / h[ii - 1]) * (a[ii] - a[ii - 1]) \
for ii in xrange(1, n)]
c = [None] * (n + 1)
l = [None] * (n + 1)
u = [None] * (n + 1)
z = [None] * (n + 1)
l[0] = 1
u[0] = z[0] = 0
for ii in xrange(1, n):
l[ii] = 2 * (self[ii + 1].x - self[ii - 1].x) - \
h[ii - 1] * u[ii - 1]
u[ii] = h[ii] / l[ii]
z[ii] = (alpha[ii] - h[ii - 1] * z[ii - 1]) / l[ii]
l[n] = 1
z[n] = c[n] = 0
for jj in xrange(n - 1, -1, -1):
c[jj] = z[jj] - u[jj] * c[jj + 1]
b[jj] = (a[jj + 1] - a[jj]) / h[jj] - \
(h[jj] * (c[jj + 1] + 2 * c[jj])) / 3
d[jj] = (c[jj + 1] - c[jj]) / (3 * h[jj])
self.splines = [CubicSpline(self[ii].x, a[ii], b[ii], c[ii],
d[ii]) for ii in xrange(n)]
def get_y(self, t, loop=False, reverse=False, natural=False):
if loop or reverse:
if reverse and int(t) / int(self[-1].x) % 2:
t = self[-1].x - t
t %= self[-1].x
elif not natural:
if t < self[0].x:
t = self[0].x
elif t > self[-1].x:
t = self[-1].x
splines = self.splines
for ii in xrange(len(splines) - 1):
if t < splines[ii + 1].x:
return splines[ii].get_y(t)
return splines[-1].get_y(t)
def remove(self, node, refresh=True):
list.remove(self, node)
if refresh:
self.set_splines()
def resize(self, left, length, refresh=True):
old_left = self[0].x
old_length = self.get_length()
for node in self:
node.x = left + length * (node.x - old_left) / old_length
if refresh:
self.set_splines()
def get_length(self):
return self[-1].x - self[0].x
class Node(list):
def __init__(self, coordinates):
list.__init__(self, coordinates)
def __getattr__(self, name):
if name == "x":
return self[0]
elif name == "y":
return self[1]
return list.__get__(self, name)
def __setattr__(self, name, value):
if name == "x":
list.__setitem__(self, 0, value)
elif name == "y":
list.__setitem__(self, 1, value)
else:
list.__setattr__(self, name, value)
class Spline:
def __init__(self, x):
self.x = x
class CubicSpline(Spline):
def __init__(self, x, a, b, c, d):
Spline.__init__(self, x)
self.a = a
self.b = b
self.c = c
self.d = d
def get_y(self, t):
x = self.x
return self.a + self.b * (t - x) + self.c * (t - x) ** 2 + self.d * \
(t - x) ** 3
class LinearSpline(Spline):
def __init__(self, x, y, m):
Spline.__init__(self, x)
self.y = y
self.m = m
def get_y(self, t):
return self.m * (t - self.x) + self.y
class GUI(Animation):
B_DUPLICATE, B_WRITE, B_DELETE, B_LINEAR, B_CUBIC, B_SPLIT = range(6)
S_NONE, S_LEFT, S_RIGHT = range(3)
def __init__(self, parent):
Animation.__init__(self, parent, unfiltered=True)
self.audio = self.get_audio()
self.display = self.get_game().display
self.display_surface = self.get_display_surface()
self.time_filter = self.get_game().time_filter
self.delegate = self.get_delegate()
self.split = self.S_NONE
self.success_indicator_active = True
self.success_indicator_blink_count = 0
self.load_configuration()
self.font = Font(None, self.label_size)
self.prompt = Prompt(self)
self.set_temporary_file()
self.set_background()
self.set_success_indicator()
self.set_plot_rect()
self.set_marker_frame()
self.set_buttons()
self.active = False
self.set_nodeset_index()
self.set_y_range()
self.set_markers()
self.subscribe(self.respond_to_command)
self.subscribe(self.respond_to_mouse_down, MOUSEBUTTONDOWN)
self.subscribe(self.respond_to_key, KEYDOWN)
self.register(self.show_success_indicator, interval=100)
self.register(self.save_temporary_file, interval=10000)
self.play(self.save_temporary_file)
def load_configuration(self):
config = self.get_configuration("interpolator-gui")
self.label_size = config["label-size"]
self.axis_label_count = config["axis-label-count"]
self.margin = config["margin"]
self.curve_color = config["curve-color"]
self.marker_size = config["marker-size"]
self.marker_color = config["marker-color"]
self.label_precision = config["label-precision"]
self.template_nodeset = config["template-nodeset"]
self.template_nodeset_name = config["template-nodeset-name"]
self.flat_y_range = config["flat-y-range"]
def set_temporary_file(self):
self.temporary_file = open(join(gettempdir(), "pgfw-config"), "w")
def set_background(self):
surface = Surface(self.display_surface.get_size())
surface.fill((0, 0, 0))
self.background = surface
def set_success_indicator(self):
surface = Surface((10, 10))
surface.fill((0, 255, 0))
rect = surface.get_rect()
rect.topleft = self.display_surface.get_rect().topleft
self.success_indicator, self.success_indicator_rect = surface, rect
def set_plot_rect(self):
margin = self.margin
self.plot_rect = self.display_surface.get_rect().inflate(-margin,
-margin)
def set_marker_frame(self):
size = self.marker_size
surface = Surface((size, size))
transparent_color = (255, 0, 255)
surface.fill(transparent_color)
surface.set_colorkey(transparent_color)
line_color = self.marker_color
aaline(surface, line_color, (0, 0), (size - 1, size - 1))
aaline(surface, line_color, (0, size - 1), (size - 1, 0))
self.marker_frame = surface
def set_buttons(self):
self.buttons = buttons = []
text = "Duplicate", "Write", "Delete", "Linear", "Cubic", "Split: No"
x = 0
for instruction in text:
buttons.append(Button(self, instruction, x))
x += buttons[-1].location.w + 10
def set_nodeset_index(self, increment=None, index=None):
parent = self.parent
if index is None:
if not increment:
index = 0
else:
index = self.nodeset_index + increment
limit = len(parent) - 1
if index > limit:
index = 0
elif index < 0:
index = limit
self.nodeset_index = index
self.set_nodeset_label()
def set_nodeset_label(self):
surface = self.font.render(self.get_nodeset().name, True, (0, 0, 0),
(255, 255, 255))
rect = surface.get_rect()
rect.bottomright = self.display_surface.get_rect().bottomright
self.nodeset_label, self.nodeset_label_rect = surface, rect
def get_nodeset(self):
if not len(self.parent):
self.parent.add_nodeset(self.template_nodeset_name,
self.template_nodeset)
self.set_nodeset_index(0)
return self.parent[self.nodeset_index]
def set_y_range(self):
width = self.plot_rect.w
nodeset = self.get_nodeset()
self.y_range = y_range = [nodeset[0].y, nodeset[-1].y]
x = 0
while x < width:
y = nodeset.get_y(self.get_function_coordinates(x)[0])
if y < y_range[0]:
y_range[0] = y
elif y > y_range[1]:
y_range[1] = y
x += width * .01
if y_range[1] - y_range[0] == 0:
y_range[1] += self.flat_y_range
if self.split:
self.adjust_for_split(y_range, nodeset)
self.set_axis_labels()
def get_function_coordinates(self, xp=0, yp=0):
nodeset = self.get_nodeset()
x_min, x_max, (y_min, y_max) = nodeset[0].x, nodeset[-1].x, self.y_range
rect = self.plot_rect
x = float(xp) / (rect.right - rect.left) * (x_max - x_min) + x_min
y = float(yp) / (rect.bottom - rect.top) * (y_min - y_max) + y_max
return x, y
def adjust_for_split(self, y_range, nodeset):
middle = nodeset[0].y if self.split == self.S_LEFT else nodeset[-1].y
below, above = middle - y_range[0], y_range[1] - middle
if below > above:
y_range[1] += below - above
else:
y_range[0] -= above - below
def set_axis_labels(self):
self.axis_labels = labels = []
nodeset, formatted, render, rect, yr = (self.get_nodeset(),
self.get_formatted_measure,
self.font.render,
self.plot_rect, self.y_range)
for ii, node in enumerate(nodeset[0::len(nodeset) - 1]):
xs = render(formatted(node.x), True, (0, 0, 0), (255, 255, 255))
xsr = xs.get_rect()
xsr.top = rect.bottom
if not ii:
xsr.left = rect.left
else:
xsr.right = rect.right
ys = render(formatted(yr[ii]), True, (0, 0, 0), (255, 255, 255))
ysr = ys.get_rect()
ysr.right = rect.left
if not ii:
ysr.bottom = rect.bottom
else:
ysr.top = rect.top
labels.append(((xs, xsr), (ys, ysr)))
def get_formatted_measure(self, measure):
return "%s" % float(("%." + str(self.label_precision) + "g") % measure)
def deactivate(self):
self.active = False
self.time_filter.open()
self.audio.muted = self.saved_mute_state
self.display.set_mouse_visibility(self.saved_mouse_state)
def respond_to_command(self, event):
compare = self.delegate.compare
if compare(event, "toggle-interpolator"):
self.toggle()
elif self.active:
if compare(event, "reset-game"):
self.deactivate()
elif compare(event, "quit"):
self.get_game().end(event)
def toggle(self):
if self.active:
self.deactivate()
else:
self.activate()
def activate(self):
self.active = True
self.time_filter.close()
self.saved_mute_state = self.audio.muted
self.audio.mute()
self.draw()
self.saved_mouse_state = self.display.set_mouse_visibility(True)
def respond_to_mouse_down(self, event):
redraw = False
if self.active and not self.prompt.active:
nodeset_rect = self.nodeset_label_rect
plot_rect = self.plot_rect
if event.button == 1:
pos = event.pos
if nodeset_rect.collidepoint(pos):
self.set_nodeset_index(1)
redraw = True
elif self.axis_labels[0][0][1].collidepoint(pos):
text = "{0} {1}".format(*map(self.get_formatted_measure,
self.get_nodeset()[0]))
self.prompt.activate(text, self.resize_nodeset, 0)
elif self.axis_labels[1][0][1].collidepoint(pos):
text = "{0} {1}".format(*map(self.get_formatted_measure,
self.get_nodeset()[-1]))
self.prompt.activate(text, self.resize_nodeset, -1)
else:
bi = self.collide_buttons(pos)
if bi is not None:
if bi == self.B_WRITE:
self.get_configuration().write()
self.play(self.show_success_indicator)
elif bi in (self.B_LINEAR, self.B_CUBIC):
nodeset = self.get_nodeset()
if bi == self.B_LINEAR:
nodeset.set_interpolation_method(Nodeset.LINEAR)
else:
nodeset.set_interpolation_method(Nodeset.CUBIC)
self.store_in_configuration()
redraw = True
elif bi == self.B_DUPLICATE:
self.prompt.activate("", self.add_nodeset)
elif bi == self.B_DELETE and len(self.parent) > 1:
self.parent.remove(self.get_nodeset())
self.set_nodeset_index(1)
self.store_in_configuration()
redraw = True
elif bi == self.B_SPLIT:
self.toggle_split()
redraw = True
elif plot_rect.collidepoint(pos) and \
not self.collide_markers(pos):
xp, yp = pos[0] - plot_rect.left, pos[1] - plot_rect.top
self.get_nodeset().add_node(
self.get_function_coordinates(xp, yp))
self.store_in_configuration()
redraw = True
elif event.button == 3:
pos = event.pos
if nodeset_rect.collidepoint(pos):
self.set_nodeset_index(-1)
redraw = True
elif plot_rect.collidepoint(pos):
marker = self.collide_markers(pos)
if marker:
self.get_nodeset().remove(marker.node)
self.store_in_configuration()
redraw = True
elif self.active and self.prompt.active and \
not self.prompt.rect.collidepoint(event.pos):
self.prompt.deactivate()
redraw = True
if redraw:
self.set_y_range()
self.set_markers()
self.draw()
def resize_nodeset(self, text, index):
result = match("^\s*(-{,1}\d*\.{,1}\d*)\s+(-{,1}\d*\.{,1}\d*)\s*$",
text)
if result:
try:
nodeset = self.get_nodeset()
x, y = map(float, result.group(1, 2))
if (index == -1 and x > nodeset[0].x) or \
(index == 0 and x < nodeset[-1].x):
nodeset[index].y = y
if index == -1:
nodeset.resize(nodeset[0].x, x - nodeset[0].x)
else:
nodeset.resize(x, nodeset[-1].x - x)
self.store_in_configuration()
self.set_y_range()
self.set_axis_labels()
self.set_markers()
self.draw()
return True
except ValueError:
return False
def collide_buttons(self, pos):
for ii, button in enumerate(self.buttons):
if button.location.collidepoint(pos):
return ii
def store_in_configuration(self):
config = self.get_configuration()
section = "interpolate"
config.clear_section(section)
for nodeset in self.parent:
code = "L" if nodeset.interpolation_method == Nodeset.LINEAR else \
"C"
for ii, node in enumerate(nodeset):
if ii > 0:
code += ","
code += " {0} {1}".format(*map(self.get_formatted_measure,
node))
if not config.has_section(section):
config.add_section(section)
config.set(section, nodeset.name, code)
def toggle_split(self):
self.split += 1
if self.split > self.S_RIGHT:
self.split = self.S_NONE
self.buttons[self.B_SPLIT].set_frame(["Split: No", "Split: L",
"Split: R"][self.split])
def add_nodeset(self, name):
nodeset = self.get_nodeset()
self.set_nodeset_index(index=self.parent.add_nodeset(\
name, nodeset, nodeset.interpolation_method))
self.store_in_configuration()
self.draw()
return True
def collide_markers(self, pos):
for marker in self.markers:
if marker.location.collidepoint(pos):
return marker
def set_markers(self):
self.markers = markers = []
for node in self.get_nodeset()[1:-1]:
markers.append(Marker(self, node))
markers[-1].location.center = self.get_plot_coordinates(*node)
def get_plot_coordinates(self, x=0, y=0):
nodeset = self.get_nodeset()
x_min, x_max, (y_min, y_max) = nodeset[0].x, nodeset[-1].x, self.y_range
x_ratio = float(x - x_min) / (x_max - x_min)
rect = self.plot_rect
xp = x_ratio * (rect.right - rect.left) + rect.left
y_ratio = float(y - y_min) / (y_max - y_min)
yp = rect.bottom - y_ratio * (rect.bottom - rect.top)
return xp, yp
def draw(self):
display_surface = self.display_surface
display_surface.blit(self.background, (0, 0))
display_surface.blit(self.nodeset_label, self.nodeset_label_rect)
self.draw_axes()
self.draw_function()
self.draw_markers()
self.draw_buttons()
def draw_axes(self):
display_surface = self.display_surface
for xl, yl in self.axis_labels:
display_surface.blit(*xl)
display_surface.blit(*yl)
def draw_function(self):
rect = self.plot_rect
surface = self.display_surface
nodeset = self.get_nodeset()
step = 1
for x in xrange(rect.left, rect.right + step, step):
ii = x - rect.left
fx = nodeset.get_y(self.get_function_coordinates(ii)[0])
y = self.get_plot_coordinates(y=fx)[1]
if ii > 0:
aaline(surface, self.curve_color, (x - step, last_y), (x, y))
last_y = y
def draw_markers(self):
for marker in self.markers:
marker.update()
def draw_buttons(self):
for button in self.buttons:
button.update()
def respond_to_key(self, event):
if self.prompt.active:
prompt = self.prompt
if event.key == K_RETURN:
if prompt.callback[0](prompt.text, *prompt.callback[1]):
prompt.deactivate()
elif event.key == K_BACKSPACE:
prompt.text = prompt.text[:-1]
prompt.update()
prompt.draw_text()
elif (event.unicode.isalnum() or event.unicode.isspace() or \
event.unicode in (".", "-", "_")) and len(prompt.text) < \
prompt.character_limit:
prompt.text += event.unicode
prompt.update()
prompt.draw_text()
def show_success_indicator(self):
self.draw()
if self.success_indicator_blink_count > 1:
self.success_indicator_blink_count = 0
self.halt(self.show_success_indicator)
else:
if self.success_indicator_active:
self.display_surface.blit(self.success_indicator,
self.success_indicator_rect)
if self.success_indicator_active:
self.success_indicator_blink_count += 1
self.success_indicator_active = not self.success_indicator_active
def save_temporary_file(self):
fp = self.temporary_file
fp.seek(0)
fp.truncate()
self.get_configuration().write(fp)
def rearrange(self):
self.set_background()
self.set_success_indicator()
self.set_plot_rect()
self.set_markers()
self.set_nodeset_label()
self.set_axis_labels()
self.set_buttons()
self.prompt.reset()
class Marker(Sprite):
def __init__(self, parent, node):
Sprite.__init__(self, parent)
self.add_frame(parent.marker_frame)
self.node = node
class Button(Sprite):
def __init__(self, parent, text, left):
Sprite.__init__(self, parent)
self.set_frame(text)
self.location.bottomleft = left, \
self.get_display_surface().get_rect().bottom
def set_frame(self, text):
self.clear_frames()
self.add_frame(self.parent.font.render(text, True, (0, 0, 0),
(255, 255, 255)))
class Prompt(Sprite):
def __init__(self, parent):
Sprite.__init__(self, parent)
self.load_configuration()
self.font = Font(None, self.text_size)
self.reset()
self.deactivate()
def deactivate(self):
self.active = False
def load_configuration(self):
config = self.get_configuration("interpolator-gui")
self.size = config["prompt-size"]
self.border_color = config["prompt-border-color"]
self.border_width = config["prompt-border-width"]
self.character_limit = config["prompt-character-limit"]
self.text_size = config["prompt-text-size"]
def reset(self):
self.set_frame()
self.place()
def set_frame(self):
self.clear_frames()
surface = Surface(self.size)
self.add_frame(surface)
surface.fill(self.border_color)
width = self.border_width * 2
surface.fill((0, 0, 0), surface.get_rect().inflate(-width, -width))
def place(self):
self.location.center = self.display_surface.get_rect().center
def activate(self, text, callback, *args):
self.active = True
self.text = str(text)
self.callback = callback, args
self.update()
self.draw_text()
def draw_text(self):
surface = self.font.render(self.text, True, (255, 255, 255), (0, 0, 0))
rect = surface.get_rect()
rect.center = self.location.center
self.display_surface.blit(surface, rect)

View File

@ -1,108 +0,0 @@
from pygame import display
from pygame.font import Font
from pygame.time import get_ticks, wait
from GameChild import GameChild
class Mainloop(GameChild):
def __init__(self, parent):
GameChild.__init__(self, parent)
self.overflow = 0
self.frame_count = 1
self.actual_frame_duration = 0
self.frames_this_second = 0
self.last_framerate_display = 0
self.load_configuration()
self.init_framerate_display()
self.last_ticks = get_ticks()
self.stopping = False
def load_configuration(self):
config = self.get_configuration("display")
self.target_frame_duration = config["frame-duration"]
self.wait_duration = config["wait-duration"]
self.skip_frames = config["skip-frames"]
self.show_framerate = config["show-framerate"]
self.framerate_text_size = config["framerate-text-size"]
self.framerate_text_color = config["framerate-text-color"]
self.framerate_text_background = config["framerate-text-background"]
self.framerate_display_flag = config["framerate-display-flag"]
def init_framerate_display(self):
if self.framerate_display_active():
screen = self.get_screen()
self.last_framerate_count = 0
self.framerate_topright = screen.get_rect().topright
self.display_surface = screen
self.font = Font(None, self.framerate_text_size)
self.font.set_bold(True)
self.render_framerate()
def framerate_display_active(self):
return self.check_command_line(self.framerate_display_flag) or \
self.show_framerate
def render_framerate(self):
text = self.font.render(str(self.last_framerate_count), False,
self.framerate_text_color,
self.framerate_text_background)
rect = text.get_rect()
rect.topright = self.framerate_topright
self.framerate_text = text
self.framerate_text_rect = rect
def run(self):
while not self.stopping:
self.advance_frame()
self.update_frame_duration()
self.update_overflow()
self.stopping = False
def advance_frame(self):
refresh = False
while self.frame_count > 0:
refresh = True
self.parent.frame()
if self.framerate_display_active():
self.update_framerate()
self.frame_count -= 1
if not self.skip_frames:
break
if refresh:
display.update()
def update_frame_duration(self):
last_ticks = self.last_ticks
actual_frame_duration = get_ticks() - last_ticks
last_ticks = get_ticks()
while actual_frame_duration < self.target_frame_duration:
wait(self.wait_duration)
actual_frame_duration += get_ticks() - last_ticks
last_ticks = get_ticks()
self.actual_frame_duration = actual_frame_duration
self.last_ticks = last_ticks
def update_overflow(self):
self.frame_count = 1
target_frame_duration = self.target_frame_duration
overflow = self.overflow
overflow += self.actual_frame_duration - target_frame_duration
while overflow > target_frame_duration:
self.frame_count += 1
overflow -= target_frame_duration
overflow = self.overflow
def update_framerate(self):
count = self.frames_this_second + 1
if get_ticks() - self.last_framerate_display > 1000:
if count != self.last_framerate_count:
self.last_framerate_count = count
self.render_framerate()
self.last_framerate_display = get_ticks()
count = 0
self.display_surface.blit(self.framerate_text, self.framerate_text_rect)
self.frames_this_second = count
def stop(self):
self.stopping = True

View File

@ -1,26 +0,0 @@
import cProfile
from time import strftime
from os import mkdir
from os.path import join, exists
from GameChild import GameChild
class Profile(cProfile.Profile, GameChild):
def __init__(self, parent):
GameChild.__init__(self, parent)
cProfile.Profile.__init__(self)
if self.requested():
self.enable()
def requested(self):
return self.check_command_line("p")
def end(self):
if self.requested():
root = "stat/"
if not exists(root):
mkdir(root)
self.disable()
self.create_stats()
self.dump_stats(join(root, strftime("%Y%m%d-%H%M_%S.stat")))

View File

@ -1,41 +0,0 @@
from os import makedirs
from os.path import exists, join
from sys import exc_info
from time import strftime
from pygame import image
from GameChild import *
from Input import *
class ScreenGrabber(GameChild):
def __init__(self, game):
GameChild.__init__(self, game)
self.delegate = self.get_delegate()
self.load_configuration()
self.subscribe(self.save_display)
def load_configuration(self):
config = self.get_configuration("screen-captures")
self.save_path = config["path"]
self.file_name_format = config["file-name-format"]
self.file_extension = config["file-extension"]
def save_display(self, event):
if self.delegate.compare(event, "capture-screen"):
directory = self.save_path
try:
if not exists(directory):
makedirs(directory)
name = self.build_name()
path = join(directory, name)
capture = image.save(self.get_screen(), path)
self.print_debug("Saved screen capture to %s" % (path))
except:
self.print_debug("Couldn't save screen capture to %s, %s" %\
(directory, exc_info()[1]))
def build_name(self):
return "{0}.{1}".format(strftime(self.file_name_format),
self.file_extension)

View File

@ -1,131 +0,0 @@
from os import walk, remove
from os.path import sep, join, exists, normpath
from re import findall, sub
from distutils.core import setup
from distutils.command.install import install
from pprint import pprint
from fileinput import FileInput
from re import sub, match
from Configuration import *
class Setup:
config = Configuration()
manifest_path = "MANIFEST"
def __init__(self):
pass
def remove_old_mainfest(self):
path = self.manifest_path
if exists(path):
remove(path)
def build_package_list(self):
packages = []
config = self.config.get_section("setup")
locations = [config["package-root"]] + config["additional-packages"]
for location in locations:
if exists(location):
for root, dirs, files in walk(location, followlinks=True):
packages.append(root.replace(sep, "."))
return packages
def build_data_map(self):
include = []
config = self.config.get_section("setup")
exclude = map(normpath, config["data-exclude"])
for root, dirs, files in walk("."):
dirs = self.remove_excluded(dirs, root, exclude)
files = [join(root, f) for f in self.remove_excluded(files, root,
exclude)]
if files:
include.append((normpath(join(config["installation-path"],
root)), files))
return include
def remove_excluded(self, paths, root, exclude):
removal = []
for path in paths:
if normpath(join(root, path)) in exclude:
removal.append(path)
for path in removal:
paths.remove(path)
return paths
def translate_title(self):
config = self.config.get_section("setup")
title = config["title"].replace(" ", config["whitespace-placeholder"])
return sub("[^\w-]", config["special-char-placeholder"], title)
def build_description(self):
description = ""
path = self.config.get("setup", "description-file")
if exists(path):
description = "\n%s\n%s\n%s" % (file(path).read(),
"Changelog\n=========",
self.translate_changelog())
return description
def translate_changelog(self):
translation = ""
path = self.config.get("setup", "changelog")
if exists(path):
lines = file(path).readlines()
package_name = lines[0].split()[0]
for line in lines:
line = line.strip()
if line.startswith(package_name):
version = findall("\((.*)\)", line)[0]
translation += "\n%s\n%s\n" % (version, "-" * len(version))
elif line and not line.startswith("--"):
if line.startswith("*"):
translation += line + "\n"
else:
translation += " " + line + "\n"
return translation
def setup(self, windows=[], options={}):
print "running setup..."
self.remove_old_mainfest()
config = self.config.get_section("setup")
scripts = []
if config["init-script"]:
scripts.append(config["init-script"])
setup(cmdclass={"install": insert_resource_path},
name=self.translate_title(),
packages=self.build_package_list(),
scripts=scripts,
data_files=self.build_data_map(),
requires=config["requirements"],
version=config["version"],
description=config["summary"],
classifiers=config["classifiers"],
long_description=self.build_description(),
license=config["license"],
platforms=config["platforms"],
author=config["contact-name"],
author_email=config["contact-email"],
url=config["url"],
windows=windows,
options=options)
class insert_resource_path(install):
def run(self):
install.run(self)
self.edit_game_object_file()
def edit_game_object_file(self):
config = Configuration().get_section("setup")
for path in self.get_outputs():
if path.endswith(config["main-object"]):
for line in FileInput(path, inplace=True):
pattern = "^ *{0} *=.*".\
format(config["resource-path-identifier"])
if match(pattern, line):
line = sub("=.*$", "= \"{0}\"".\
format(config["installation-path"]), line)
print line.strip("\n")

View File

@ -1,69 +0,0 @@
from os import makedirs, walk, sep, remove
from os.path import join, dirname, basename, exists
from shutil import rmtree, copy, rmtree
from itertools import chain
from zipfile import ZipFile
import py2exe
from Setup import Setup
class SetupWin(Setup):
def __init__(self):
Setup.__init__(self)
self.replace_isSystemDLL()
def replace_isSystemDLL(self):
origIsSystemDLL = py2exe.build_exe.isSystemDLL
def isSystemDLL(pathname):
if basename(pathname).lower() in ("libogg-0.dll", "sdl_ttf.dll"):
return 0
return origIsSystemDLL(pathname)
py2exe.build_exe.isSystemDLL = isSystemDLL
def setup(self):
config = self.config.get_section("setup")
windows = [{}]
if config["init-script"]:
windows[0]["script"] = config["init-script"]
if config["windows-icon-path"]:
windows[0]["icon-resources"] = [(1, config["windows-icon-path"])]
Setup.setup(self, windows,
{"py2exe": {"packages": self.build_package_list(),
"dist_dir": config["windows-dist-path"]}})
rmtree("build")
self.copy_data_files()
self.create_archive()
def copy_data_files(self):
root = self.config.get("setup", "windows-dist-path")
for path in chain(*zip(*self.build_data_map())[1]):
dest = join(root, dirname(path))
if not exists(dest):
makedirs(dest)
copy(path, dest)
self.include_readme(root)
def include_readme(self, root):
name = "README"
if exists(name):
readme = open(name, "r")
reformatted = open(join(root, name + ".txt"), "w")
for line in open(name, "r"):
reformatted.write(line.rstrip() + "\r\n")
def create_archive(self):
config = self.config.get_section("setup")
title = self.translate_title() + "-" + config["version"] + "-win"
archive_name = title + ".zip"
archive = ZipFile(archive_name, "w")
destination = config["windows-dist-path"]
for root, dirs, names in walk(destination):
for name in names:
path = join(root, name)
archive.write(path, path.replace(destination, title + sep))
archive.close()
copy(archive_name, "dist")
remove(archive_name)
rmtree(destination)

View File

@ -1,359 +0,0 @@
from os import listdir
from os.path import isfile, join
from sys import exc_info, stdout
from glob import glob
from traceback import print_exc, print_stack
from pygame import Color, Rect, Surface
from pygame.image import load
from pygame.transform import flip
from pygame.locals import *
from Animation import Animation
from Vector import Vector
class Sprite(Animation):
def __init__(self, parent, framerate=None):
Animation.__init__(self, parent, self.shift_frame, framerate)
self.frames = []
self.mirrored = False
self.hidden = False
self.alpha = 255
self.locations = [Location(self)]
self.framesets = [Frameset(self, framerate=framerate)]
self.set_frameset(0)
self.motion_overflow = Vector()
self.display_surface = self.get_display_surface()
def __getattr__(self, name):
if name in ("location", "rect"):
return self.locations[0]
if hasattr(Animation, "__getattr__"):
return Animation.__getattr__(self, name)
raise AttributeError, name
def set_frameset(self, identifier):
if isinstance(identifier, str):
for ii, frameset in enumerate(self.framesets):
if frameset.name == identifier:
identifier = ii
break
self.frameset_index = identifier
self.register_interval()
self.update_location_size()
if self.get_current_frameset().length() > 1:
self.play()
def register_interval(self):
self.register(self.shift_frame,
interval=self.get_current_frameset().framerate)
def get_current_frameset(self):
return self.framesets[self.frameset_index]
def update_location_size(self):
size = self.get_current_frameset().rect.size
for location in self.locations:
location.size = size
location.fader.init_surface()
def set_framerate(self, framerate):
self.get_current_frameset().set_framerate(framerate)
self.register_interval()
def load_from_path(self, path, transparency=False, ppa=True, key=None,
extension=None, omit=False):
if isfile(path):
paths = [path]
else:
if extension:
paths = sorted(glob(join(path, "*." + extension)))
else:
paths = [join(path, name) for name in sorted(listdir(path))]
for path in paths:
img = load(path)
if transparency:
if ppa:
frame = img.convert_alpha()
else:
frame = self.fill_colorkey(img, key)
else:
frame = img.convert()
self.add_frame(frame, omit)
def fill_colorkey(self, img, key=None):
if not key:
key = (255, 0, 255)
img = img.convert_alpha()
frame = Surface(img.get_size())
frame.fill(key)
frame.set_colorkey(key)
frame.blit(img, (0, 0))
return frame
def add_frame(self, frame, omit=False):
self.frames.append(frame)
frame.set_alpha(self.alpha)
if not omit:
frameset = self.get_current_frameset()
frameset.add_index(self.frames.index(frame))
self.update_location_size()
if frameset.length() > 1:
self.play()
def shift_frame(self):
self.get_current_frameset().shift()
def get_current_frame(self):
return self.frames[self.get_current_frameset().get_current_id()]
def move(self, dx=0, dy=0):
for location in self.locations:
location.move_ip(dx, dy)
def reset_motion_overflow(self):
for location in self.locations:
location.reset_motion_overflow()
def collide(self, other):
if not isinstance(other, Rect):
other = other.rect
for location in self.locations:
if location.colliderect(other):
return location
def mirror(self):
frames = self.frames
for ii, frame in enumerate(frames):
frames[ii] = flip(frame, True, False)
self.mirrored = not self.mirrored
def clear_frames(self):
self.frames = []
for frameset in self.framesets:
frameset.order = []
frameset.reset()
frameset.measure_rect()
def add_location(self, topleft=None, offset=(0, 0), count=1, base=0):
if topleft is not None:
for ii in xrange(count):
self.locations.append(Location(
self, Rect(topleft, self.locations[0].size)))
else:
base = self.locations[base]
current_offset = list(offset)
for ii in xrange(count):
self.locations.append(Location(self,
base.move(*current_offset)))
current_offset[0] += offset[0]
current_offset[1] += offset[1]
return self.locations[-1]
def fade(self, length=0, out=None, index=None):
if index is None:
for location in self.locations:
location.fader.start(length, out)
else:
self.locations[index].fader.start(length, out)
def set_alpha(self, alpha):
self.alpha = alpha
for frame in self.frames:
frame.set_alpha(alpha)
for location in self.locations:
location.fader.set_alpha()
def add_frameset(self, order, framerate=None, name=None):
frameset = Frameset(self, order, framerate, name)
self.framesets.append(frameset)
return frameset
def hide(self):
self.hidden = True
def unhide(self):
self.hidden = False
def remove_locations(self, location=None):
if location:
self.locations.remove(location)
else:
self.locations = self.locations[:1]
def reverse(self, frameset=None):
if frameset:
frameset.reverse()
else:
for frameset in self.framesets:
frameset.reverse()
def update(self, flags=0):
Animation.update(self)
self.draw(flags)
def draw(self, flags=0):
for location in self.locations:
location.fader.draw(flags)
class Location(Rect):
def __init__(self, sprite, rect=(0, 0, 0, 0)):
self.sprite = sprite
Rect.__init__(self, rect)
self.motion_overflow = Vector()
self.fader = Fader(self)
def move_ip(self, dx, dy):
if isinstance(dx, float) or isinstance(dy, float):
excess = self.update_motion_overflow(dx, dy)
Rect.move_ip(self, int(dx) + excess[0], int(dy) + excess[1])
else:
Rect.move_ip(self, dx, dy)
def update_motion_overflow(self, dx, dy):
overflow = self.motion_overflow
overflow.move(dx - int(dx), dy - int(dy))
excess = map(int, overflow)
overflow[0] -= int(overflow[0])
overflow[1] -= int(overflow[1])
return excess
def reset_motion_overflow(self):
self.motion_overflow.place_at_origin()
class Fader(Surface):
def __init__(self, location):
self.location = location
self.time_filter = location.sprite.get_game().time_filter
self.reset()
def reset(self):
self.init_surface()
self.fade_remaining = None
def init_surface(self):
Surface.__init__(self, self.location.size)
if self.location.sprite.frames:
background = Surface(self.get_size())
sprite = self.location.sprite
key = sprite.get_current_frame().get_colorkey() or (255, 0, 255)
self.set_colorkey(key)
background.fill(key)
self.background = background
self.set_alpha()
def set_alpha(self, alpha=None):
if alpha is None:
alpha = self.location.sprite.alpha
Surface.set_alpha(self, alpha)
def start(self, length, out=None):
if self.fade_remaining <= 0:
alpha = self.get_alpha()
maximum = self.location.sprite.alpha
if out is None:
out = alpha == maximum
if out and alpha > 0 or not out and alpha < maximum:
self.fade_length = self.fade_remaining = length
self.start_time = self.time_filter.get_ticks()
self.fading_out = out
def draw(self, flags):
sprite = self.location.sprite
if self.fade_remaining >= 0:
self.update_alpha()
self.clear()
frame = sprite.get_current_frame()
frame.set_alpha(255)
self.blit(frame, (0, 0))
frame.set_alpha(sprite.alpha)
if not sprite.hidden:
self.blit_to_display(self, flags)
elif self.fade_remaining is None or self.get_alpha() >= sprite.alpha:
if self.fade_remaining >= 0:
self.update_alpha()
if not sprite.hidden:
self.blit_to_display(sprite.get_current_frame(), flags)
def blit_to_display(self, frame, flags):
self.location.sprite.display_surface.blit(frame, self.location, None,
flags)
def update_alpha(self):
remaining = self.fade_remaining = self.fade_length - \
(self.time_filter.get_ticks() - self.start_time)
ratio = self.fade_length and float(remaining) / self.fade_length
if not self.fading_out:
ratio = 1 - ratio
maximum = self.location.sprite.alpha
alpha = int(ratio * maximum)
if alpha > maximum:
alpha = maximum
elif alpha < 0:
alpha = 0
self.set_alpha(alpha)
def clear(self):
self.blit(self.background, (0, 0))
class Frameset():
def __init__(self, sprite, order=[], framerate=None, name=None):
self.sprite = sprite
self.name = name
self.reversed = False
self.order = []
self.rect = Rect(0, 0, 0, 0)
self.add_index(order)
self.set_framerate(framerate)
self.reset()
def add_index(self, order):
if isinstance(order, int):
order = [order]
self.order += order
self.measure_rect()
def set_framerate(self, framerate):
self.framerate = framerate
def reset(self):
self.current_index = 0
def get_current_id(self):
return self.order[self.current_index]
def measure_rect(self):
max_width, max_height = 0, 0
frames = self.sprite.frames
for index in self.order:
frame = frames[index]
width, height = frame.get_size()
max_width = max(width, max_width)
max_height = max(height, max_height)
self.rect.size = max_width, max_height
def shift(self):
if len(self.order) > 1:
self.increment_index()
def increment_index(self):
increment = 1 if not self.reversed else -1
index = self.current_index + increment
if index < 0:
index = self.length() - 1
elif index >= self.length():
index = 0
self.current_index = index
def length(self):
return len(self.order)
def reverse(self):
self.reversed = not self.reversed

View File

@ -1,36 +0,0 @@
from pygame.time import get_ticks
from GameChild import GameChild
class TimeFilter(GameChild):
def __init__(self, parent):
GameChild.__init__(self, parent)
self.ticks = self.unfiltered_ticks = self.last_ticks = get_ticks()
self.open()
def close(self):
self.closed = True
def open(self):
self.closed = False
def get_ticks(self):
return self.ticks
def get_unfiltered_ticks(self):
return self.unfiltered_ticks
def get_last_ticks(self):
return self.last_ticks
def get_last_frame_duration(self):
return self.last_frame_duration
def update(self):
ticks = get_ticks()
self.last_frame_duration = duration = ticks - self.last_ticks
if not self.closed:
self.ticks += duration
self.unfiltered_ticks += duration
self.last_ticks = ticks

View File

@ -1,69 +0,0 @@
class Vector(list):
def __init__(self, x=0, y=0):
list.__init__(self, (x, y))
def __getattr__(self, name):
if name == "x":
return self[0]
elif name == "y":
return self[1]
def __setattr__(self, name, value):
if name == "x":
self[0] = value
elif name == "y":
self[1] = value
else:
list.__setattr__(self, name, value)
def __add__(self, other):
return Vector(self.x + other[0], self.y + other[1])
__radd__ = __add__
def __iadd__(self, other):
self.x += other[0]
self.y += other[1]
return self
def __sub__(self, other):
return Vector(self.x - other[0], self.y - other[1])
def __rsub__(self, other):
return Vector(other[0] - self.x, other[1] - self.y)
def __isub__(self, other):
self.x -= other[0]
self.y -= other[1]
return self
def __mul__(self, other):
return Vector(self.x * other, self.y * other)
__rmul__ = __mul__
def __imul__(self, other):
self.x *= other
self.y *= other
return self
def apply_to_components(self, function):
self.x = function(self.x)
self.y = function(self.y)
def place(self, x=None, y=None):
if x is not None:
self.x = x
if y is not None:
self.y = y
def move(self, dx=0, dy=0):
if dx:
self.x += dx
if dy:
self.y += dy
def place_at_origin(self):
self.x = 0
self.y = 0

View File

@ -1,71 +0,0 @@
from os import makedirs
from os.path import exists, join
from tempfile import TemporaryFile
from time import strftime
from pygame.image import tostring, frombuffer, save
from pygame.time import get_ticks
from GameChild import GameChild
class VideoRecorder(GameChild):
def __init__(self, parent):
GameChild.__init__(self, parent)
self.display_surface = self.get_display_surface()
self.delegate = self.get_delegate()
self.load_configuration()
self.reset()
self.subscribe(self.respond)
def load_configuration(self):
config = self.get_configuration("video-recordings")
self.root = config["path"]
self.directory_name_format = config["directory-name-format"]
self.file_extension = config["file-extension"]
self.frame_format = config["frame-format"]
self.framerate = config["framerate"]
def reset(self):
self.recording = False
self.frame_length = None
self.frames = None
self.last_frame = 0
def respond(self, event):
compare = self.delegate.compare
if compare(event, "record-video"):
self.toggle_record()
elif compare(event, "reset-game"):
self.reset()
def toggle_record(self):
recording = not self.recording
if recording:
self.frame_length = len(self.get_string())
self.frames = TemporaryFile()
else:
self.write_frames()
self.recording = recording
def get_string(self):
return tostring(self.display_surface, self.frame_format)
def write_frames(self):
root = join(self.root, strftime(self.directory_name_format))
if not exists(root):
makedirs(root)
size = self.display_surface.get_size()
frames = self.frames
frames.seek(0)
for ii, frame in enumerate(iter(lambda: frames.read(self.frame_length),
"")):
path = join(root, "%04i.png" % ii)
save(frombuffer(frame, size, self.frame_format), path)
print "wrote video frames to " + root
def update(self):
ticks = get_ticks()
if self.recording and ticks - self.last_frame >= self.framerate:
self.frames.write(self.get_string())
self.last_frame = ticks

1
lib/pgfw Submodule

@ -0,0 +1 @@
Subproject commit a0aba9a0bb527ec7f3d7269cdd522448560a99c3

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,20 +1,8 @@
1398631170.296798 200
1398631170.296798 100
1398631170.296798 40
1398635621.7 158
1398635792.99 154
1398636058.07 180
1398636195.37 232
1398636310.09 131
1398636404.1 120
1398636488.41 165
1398636581.89 173
1398636667.8 186
1398647055.97 78
1398647195.17 187
1398647939.59 155
1398648230.57 88
1436645313.22 196
1436645428.32 246
1436645528.27 193
1437504178.89 165
1398631170.296798 100 SIV
1398631170.296798 70 SIV
1398631170.296798 45 SIV
1398635621.7 25 SIV
1398635792.99 10 SIV
1437514837.26 206 SIV
1437514932.23 22 SIV
1437514988.25 88 SIV