- fix include delay bug in Animation class
- multiple values for boolean true in config files - sprite wipe out animation - sprite children optionally drawn on parent surface - text wrapping function handles line breaks - blinds animation function for returning rects
This commit is contained in:
parent
0878ad6181
commit
301f547a25
|
@ -58,7 +58,7 @@ class Animation(GameChild):
|
|||
include_delay)
|
||||
|
||||
def is_account_playing(self, account, include_delay):
|
||||
return account.playing and (not include_delay or not account.delay)
|
||||
return account.playing and (include_delay or not account.delay)
|
||||
|
||||
def reset_timer(self, method=None):
|
||||
if not method:
|
||||
|
|
|
@ -8,19 +8,20 @@ from .Input import *
|
|||
from .Animation import *
|
||||
from .extension import *
|
||||
|
||||
class Audio(GameChild):
|
||||
class Audio(Animation):
|
||||
|
||||
UP, DOWN = .1, -.1
|
||||
BASE_VOLUME = 1.0
|
||||
CONFIG_SEPARATOR = ","
|
||||
|
||||
def __init__(self, game):
|
||||
GameChild.__init__(self, game)
|
||||
Animation.__init__(self, game)
|
||||
# self.original_volumes = {}
|
||||
self.current_bgm = None
|
||||
self.volume = self.BASE_VOLUME
|
||||
if self.check_command_line("-mute"):
|
||||
self.volume = 0
|
||||
self.register(self.play_sfx)
|
||||
self.audio_panel = AudioPanel(self)
|
||||
self.subscribe(self.respond)
|
||||
self.sfx = {}
|
||||
|
@ -106,6 +107,9 @@ class Audio(GameChild):
|
|||
return True
|
||||
return False
|
||||
|
||||
def play_sfx(self, name):
|
||||
self.sfx[name].play()
|
||||
|
||||
#
|
||||
# Loading BGM procedure
|
||||
#
|
||||
|
@ -180,13 +184,7 @@ class Audio(GameChild):
|
|||
return True
|
||||
|
||||
def update(self):
|
||||
# for ii in range(pygame.mixer.get_num_channels()):
|
||||
# channel = pygame.mixer.Channel(ii)
|
||||
# sound = channel.get_sound()
|
||||
# if sound is not None:
|
||||
# if sound not in self.original_volumes.keys():
|
||||
# self.original_volumes[sound] = sound.get_volume()
|
||||
# sound.set_volume(self.original_volumes[sound] * self.volume)
|
||||
Animation.update(self)
|
||||
self.audio_panel.update()
|
||||
|
||||
|
||||
|
@ -209,6 +207,9 @@ class BGM(GameChild):
|
|||
def get_volume(self):
|
||||
return self.volume
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.path == other.path
|
||||
|
||||
|
||||
class SoundEffect(GameChild, pygame.mixer.Sound):
|
||||
|
||||
|
@ -329,6 +330,7 @@ class AudioPanel(Animation):
|
|||
self.active = False
|
||||
if self.bgm_elapsed is not None:
|
||||
self.get_audio().play_bgm(start=self.bgm_elapsed)
|
||||
self.file_browser.hide()
|
||||
|
||||
def respond(self, event):
|
||||
if self.get_delegate().compare(event, "toggle-audio-panel") and self.get_audio().sfx:
|
||||
|
@ -444,7 +446,7 @@ class AudioPanelRow(BlinkingSprite):
|
|||
self.subscribe(self.respond, pygame.MOUSEBUTTONDOWN)
|
||||
|
||||
def respond(self, event):
|
||||
if event.button == 1:
|
||||
if self.parent.active and event.button == 1:
|
||||
if self.parent.file_browser.is_hidden() and self.location.collidepoint(event.pos):
|
||||
if not self.selected:
|
||||
self.parent.file_browser.visit(self.parent.file_browser.HOME)
|
||||
|
@ -530,6 +532,15 @@ class AudioPanelRow(BlinkingSprite):
|
|||
shutil.copyfile(config_path, backup_path)
|
||||
self.get_configuration().write(open(config_path, "w"))
|
||||
|
||||
def set_clickable(self, clickable=True):
|
||||
self.play_button.set_clickable(clickable)
|
||||
self.stop_button.set_clickable(clickable)
|
||||
self.volume_spinner.set_clickable(clickable)
|
||||
if not self.is_bgm:
|
||||
self.fade_out_spinner.set_clickable(clickable)
|
||||
self.loops_spinner.set_clickable(clickable)
|
||||
self.maxtime_spinner.set_clickable(clickable)
|
||||
|
||||
def update(self):
|
||||
self.play_button.location.midleft = self.location.move(5, 0).midright
|
||||
self.stop_button.location.midleft = self.play_button.location.midright
|
||||
|
@ -612,8 +623,7 @@ class AudioPanelFileBrowser(Sprite):
|
|||
for row in self.parent.rows:
|
||||
row.selected = False
|
||||
row.stop_blinking()
|
||||
row.play_button.set_clickable()
|
||||
row.stop_button.set_clickable()
|
||||
row.set_clickable(True)
|
||||
for row in self.rows:
|
||||
if row.has_child("button"):
|
||||
row.get_child("button").set_clickable(False)
|
||||
|
@ -623,8 +633,7 @@ class AudioPanelFileBrowser(Sprite):
|
|||
|
||||
def unhide(self):
|
||||
for row in self.parent.rows:
|
||||
row.play_button.set_clickable(False)
|
||||
row.stop_button.set_clickable(False)
|
||||
row.set_clickable(False)
|
||||
for row in self.rows:
|
||||
if row.has_child("button"):
|
||||
row.get_child("button").set_clickable()
|
||||
|
@ -762,6 +771,7 @@ class AudioPanelSpinner(Sprite):
|
|||
self.down_button.location.topleft = self.display.location.right - 1, \
|
||||
self.up_button.location.bottom - 1
|
||||
self.down_button.display_surface = self.get_current_frame()
|
||||
self.set_clickable()
|
||||
self.subscribe(self.respond, pygame.MOUSEBUTTONDOWN)
|
||||
|
||||
def unsubscribe(self, callback=None, kind=None):
|
||||
|
@ -788,7 +798,7 @@ class AudioPanelSpinner(Sprite):
|
|||
self.update_display()
|
||||
|
||||
def respond(self, event):
|
||||
if event.button == 1:
|
||||
if self.clickable and event.button == 1:
|
||||
relative_position = Vector(*event.pos).get_moved(
|
||||
-self.location.left, -self.location.top)
|
||||
up_collides = self.up_button.collide(relative_position)
|
||||
|
@ -800,6 +810,9 @@ class AudioPanelSpinner(Sprite):
|
|||
self.increment(False)
|
||||
self.parent.update_config()
|
||||
|
||||
def set_clickable(self, clickable=True):
|
||||
self.clickable = clickable
|
||||
|
||||
def update(self):
|
||||
self.get_current_frame().fill(self.background)
|
||||
self.label.update()
|
||||
|
@ -816,8 +829,8 @@ class AudioPanelButton(Sprite):
|
|||
self.callback = callback
|
||||
self.callback_kwargs = callback_kwargs
|
||||
self.containers = containers
|
||||
self.clickable = True
|
||||
self.pass_mods = pass_mods
|
||||
self.set_clickable()
|
||||
self.subscribe(self.respond, pygame.MOUSEBUTTONDOWN)
|
||||
|
||||
def unsubscribe(self, callback=None, kind=None):
|
||||
|
@ -827,7 +840,7 @@ class AudioPanelButton(Sprite):
|
|||
Sprite.unsubscribe(self, callback, kind)
|
||||
|
||||
def respond(self, event):
|
||||
if self.clickable and event.button == 1:
|
||||
if self.get_audio().audio_panel.active and self.clickable and event.button == 1:
|
||||
pos = Vector(*event.pos)
|
||||
for container in self.containers:
|
||||
pos.move(-container.location.left, -container.location.top)
|
||||
|
|
|
@ -67,7 +67,7 @@ class Configuration(RawConfigParser):
|
|||
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)
|
||||
set_option(section, "boolean-true-lowercase", "yes, true, t, 1", False)
|
||||
set_option(section, "osx-includes", "", False)
|
||||
section = "display"
|
||||
add_section(section)
|
||||
|
@ -275,9 +275,7 @@ class Configuration(RawConfigParser):
|
|||
# if type(value) == str or type(value) == unicode:
|
||||
if type(value) == str:
|
||||
if pair in types["bool"]:
|
||||
if value.lower() == self.get("setup", "lowercase-boolean-true"):
|
||||
return True
|
||||
return False
|
||||
return value.lower() in self.get("setup", "boolean-true-lowercase")
|
||||
elif pair in types["int"]:
|
||||
return int(value)
|
||||
elif pair in types["float"]:
|
||||
|
@ -422,7 +420,7 @@ class TypeDeclarations(dict):
|
|||
|
||||
"setup": {"list": ["classifiers", "resource-search-path",
|
||||
"requirements", "data-exclude",
|
||||
"additional-packages", "osx-includes"],
|
||||
"additional-packages", "osx-includes", "boolean-true-lowercase"],
|
||||
|
||||
"path": ["installation-dir", "changelog", "description-file",
|
||||
"main-object", "icon-path", "windows-dist-path",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import collections
|
||||
from os import listdir
|
||||
from os.path import isfile, join
|
||||
from sys import exc_info, stdout
|
||||
from glob import glob
|
||||
|
||||
from pygame import Color, Rect, Surface, PixelArray, mask
|
||||
|
@ -10,11 +10,11 @@ from pygame.locals import *
|
|||
|
||||
from .Animation import Animation
|
||||
from .Vector import Vector, EVector
|
||||
from .extension import get_hue_shifted_surface, get_step
|
||||
from .extension import get_hue_shifted_surface, get_step, load_frames, get_blinds_rects
|
||||
|
||||
class Sprite(Animation):
|
||||
|
||||
def __init__(self, parent, framerate=None, neighbors=[], mass=None):
|
||||
def __init__(self, parent, framerate=None, draw_children_on_frame=True):
|
||||
Animation.__init__(self, parent, self.shift_frame, framerate)
|
||||
self.frames = []
|
||||
self.mirrored = False
|
||||
|
@ -22,15 +22,20 @@ class Sprite(Animation):
|
|||
self.locations = []
|
||||
self.framesets = [Frameset(self, framerate=framerate)]
|
||||
self.frameset_index = 0
|
||||
self.neighbors = neighbors
|
||||
self.mass = mass
|
||||
self._step = EVector()
|
||||
self.children = {}
|
||||
self.children = collections.OrderedDict()
|
||||
self.draw_children_on_frame = draw_children_on_frame
|
||||
self.set_frameset(0)
|
||||
self.locations.append(Location(self))
|
||||
self.motion_overflow = Vector()
|
||||
self.display_surface = self.get_display_surface()
|
||||
self.register(self.toggle_hidden)
|
||||
self.wipe_blinds = []
|
||||
self.current_wipe_index = 0
|
||||
self.register(self.toggle_hidden, self.wipe_out)
|
||||
|
||||
def reset(self):
|
||||
self.halt(self.wipe_out)
|
||||
self.current_wipe_index = 0
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name in ("location", "rect"):
|
||||
|
@ -61,6 +66,7 @@ class Sprite(Animation):
|
|||
if self.get_current_frameset().length() > 1:
|
||||
self.play()
|
||||
self.get_current_frameset().reset()
|
||||
return self.get_current_frameset()
|
||||
|
||||
def register_interval(self):
|
||||
self.register(self.shift_frame,
|
||||
|
@ -81,25 +87,10 @@ class Sprite(Animation):
|
|||
|
||||
def load_from_path(self, path, transparency=False, ppa=True, key=None,
|
||||
query=None, omit=False):
|
||||
if isfile(path):
|
||||
paths = [path]
|
||||
else:
|
||||
if query:
|
||||
paths = sorted(glob(join(path, query)))
|
||||
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()
|
||||
for frame in load_frames(self.get_resource(path), transparency, ppa, key, query):
|
||||
self.add_frame(frame, omit)
|
||||
|
||||
def fill_colorkey(self, img, key=None):
|
||||
def fill_colorkey(img, key=None):
|
||||
if not key:
|
||||
key = (255, 0, 255)
|
||||
img = img.convert_alpha()
|
||||
|
@ -116,6 +107,8 @@ class Sprite(Animation):
|
|||
frameset = self.get_current_frameset()
|
||||
frameset.add_index(self.frames.index(frame))
|
||||
self.update_location_size()
|
||||
self.wipe_blinds = get_blinds_rects(*self.location.size)
|
||||
self.wipe_blinds.reverse()
|
||||
if frameset.length() > 1:
|
||||
self.play()
|
||||
|
||||
|
@ -205,14 +198,20 @@ class Sprite(Animation):
|
|||
def hide(self):
|
||||
for location in self.locations:
|
||||
location.hide()
|
||||
for child in self.children.values():
|
||||
child.hide()
|
||||
|
||||
def unhide(self):
|
||||
for location in self.locations:
|
||||
location.unhide()
|
||||
for child in self.children.values():
|
||||
child.unhide()
|
||||
|
||||
def toggle_hidden(self):
|
||||
for location in self.locations:
|
||||
location.toggle_hidden()
|
||||
for child in self.children.values():
|
||||
child.toggle_hidden()
|
||||
|
||||
def is_hidden(self):
|
||||
return all(location.is_hidden() for location in self.locations)
|
||||
|
@ -248,19 +247,41 @@ class Sprite(Animation):
|
|||
def has_child(self, name):
|
||||
return name in self.children
|
||||
|
||||
def remove_child(self, name):
|
||||
if self.has_child(name):
|
||||
self.children.pop(name)
|
||||
|
||||
def wipe_out(self):
|
||||
for child in self.children.values():
|
||||
if not child.is_playing(child.wipe_out):
|
||||
child.play(child.wipe_out)
|
||||
self.current_wipe_index += 1
|
||||
if self.current_wipe_index == len(self.wipe_blinds):
|
||||
self.current_wipe_index = 0
|
||||
self.halt(self.wipe_out)
|
||||
self.hide()
|
||||
|
||||
def get_current_blinds(self):
|
||||
return self.wipe_blinds[self.current_wipe_index]
|
||||
|
||||
def update(self, areas=None, substitute=None, flags=0):
|
||||
Animation.update(self)
|
||||
if self.is_stepping():
|
||||
self.move(self._step.dx, self._step.dy)
|
||||
for neighbor in self.neighbors:
|
||||
self.move(*get_step(self.location.center, neighbor.location.center,
|
||||
neighbor.mass))
|
||||
if self.get_current_frameset().length():
|
||||
if self.is_playing(self.wipe_out):
|
||||
areas = self.get_current_blinds()
|
||||
self.draw(areas, substitute, flags)
|
||||
for child in self.children.values():
|
||||
if self.draw_children_on_frame:
|
||||
child.display_surface = self.get_current_frame()
|
||||
else:
|
||||
child.display_surface = self.get_display_surface()
|
||||
save_child_topleft = child.location.topleft
|
||||
child.move(*self.location.topleft)
|
||||
child.update()
|
||||
# for location in self.locations:
|
||||
# location.update()
|
||||
if not self.draw_children_on_frame:
|
||||
child.location.topleft = save_child_topleft
|
||||
|
||||
def draw(self, areas=None, substitute=None, flags=0):
|
||||
for location in self.locations:
|
||||
|
@ -316,18 +337,6 @@ class Location(Rect):
|
|||
def is_hidden(self):
|
||||
return self.hidden
|
||||
|
||||
def update(self):
|
||||
pass
|
||||
# for neighbor in self.sprite.neighbors:
|
||||
# if neighbor.mass:
|
||||
# closest = neighbor.location
|
||||
# for location in neighbor.locations[1:]:
|
||||
# if get_distance(self.center, location.center) < \
|
||||
# get_distance(self.center, closest.center):
|
||||
# closest = location
|
||||
# self.move_ip(get_step(self.center, closest.center,
|
||||
# neighbor.mass))
|
||||
|
||||
|
||||
class Fader(Surface):
|
||||
|
||||
|
@ -493,6 +502,7 @@ class BlinkingSprite(Sprite):
|
|||
def __init__(self, parent, blink_rate, framerate=None):
|
||||
Sprite.__init__(self, parent, framerate)
|
||||
self.register(self.blink, interval=blink_rate)
|
||||
self.register(self.start_blinking, self.stop_blinking)
|
||||
self.play(self.blink)
|
||||
|
||||
def reset(self):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import itertools, random
|
||||
import itertools, random, os, glob
|
||||
from math import sin, cos, atan2, radians, sqrt, pi
|
||||
|
||||
import pygame
|
||||
from pygame import Surface, PixelArray, Color, Rect, draw, gfxdraw
|
||||
from pygame.mixer import get_num_channels, Channel
|
||||
from pygame.locals import *
|
||||
|
@ -119,6 +120,16 @@ def place_in_rect(rect, incoming, contain=True, *args):
|
|||
if not collides:
|
||||
break
|
||||
|
||||
def constrain_dimensions_2d(vector, container):
|
||||
dw = vector[0] - container[0]
|
||||
dh = vector[1] - container[1]
|
||||
if dw > 0 or dh > 0:
|
||||
if dw > dh:
|
||||
size = container[0], int(round(container[0] / vector[0] * vector[1]))
|
||||
else:
|
||||
size = int(round(container[1] / vector[1] * vector[0])), container[1]
|
||||
return size
|
||||
|
||||
# from http://www.realtimerendering.com/resources/GraphicsGems/gemsii/xlines.c
|
||||
def get_intersection(p0, p1, p2, p3):
|
||||
x0, y0 = p0
|
||||
|
@ -215,16 +226,21 @@ def render_box(font=None, text=None, antialias=True, color=(0, 0, 0), background
|
|||
surface.fill(background)
|
||||
return get_boxed_surface(surface, background, border, border_width, padding)
|
||||
|
||||
def get_wrapped_text_surface(font, text, width, antialias, color,
|
||||
def get_wrapped_text_surface(font, text, width, antialias=True, color=(0, 0, 0),
|
||||
background=None, border=None, border_width=1,
|
||||
padding=0):
|
||||
words = text.split()
|
||||
if words:
|
||||
padding=0, align="left"):
|
||||
lines = []
|
||||
height = 0
|
||||
for chunk in text.split("\n"):
|
||||
line_text = ""
|
||||
lines = []
|
||||
height = 0
|
||||
ii = 0
|
||||
finished = False
|
||||
if chunk.startswith("\*") and chunk.endswith("\*"):
|
||||
chunk = chunk.replace("\*", "*")
|
||||
elif chunk.startswith("*") and chunk.endswith("*"):
|
||||
chunk = chunk[1:-1]
|
||||
font.set_italic(True)
|
||||
words = chunk.split(" ")
|
||||
while not finished:
|
||||
line_width = font.size(line_text + " " + words[ii])[0]
|
||||
if line_width > width or ii == len(words) - 1:
|
||||
|
@ -233,25 +249,26 @@ def get_wrapped_text_surface(font, text, width, antialias, color,
|
|||
line_text += " "
|
||||
line_text += words[ii]
|
||||
finished = True
|
||||
line = font.render(line_text, antialias, color, background)
|
||||
line = font.render(line_text, antialias, color)
|
||||
height += line.get_height()
|
||||
lines.append(line)
|
||||
line_text = ""
|
||||
else:
|
||||
line_text += " " + words[ii]
|
||||
ii += 1
|
||||
top = 0
|
||||
surface = Surface((width, height), SRCALPHA)
|
||||
if background:
|
||||
surface.fill(background)
|
||||
rect = surface.get_rect()
|
||||
for line in lines:
|
||||
line_rect = line.get_rect()
|
||||
line_rect.midtop = rect.centerx, top
|
||||
surface.blit(line, line_rect)
|
||||
top += line_rect.h
|
||||
else:
|
||||
surface = Surface((0, 0), SRCALPHA)
|
||||
font.set_italic(False)
|
||||
top = 0
|
||||
surface = Surface((width, height), pygame.SRCALPHA)
|
||||
if background:
|
||||
surface.fill(background)
|
||||
rect = surface.get_rect()
|
||||
for line in lines:
|
||||
line_rect = line.get_rect()
|
||||
line_rect.top = top
|
||||
if align == "center":
|
||||
line_rect.centerx = rect.centerx
|
||||
surface.blit(line, line_rect)
|
||||
top += line_rect.h
|
||||
return get_boxed_surface(surface, background, border, border_width, padding)
|
||||
|
||||
def replace_color(surface, color, replacement):
|
||||
|
@ -305,6 +322,37 @@ def fill_tile(surface, tile, rect=None):
|
|||
for y in range(0, surface.get_height(), h):
|
||||
surface.blit(tile, (x, y))
|
||||
|
||||
def load_frames(path, transparency=False, ppa=True, key=None, query=None):
|
||||
if os.path.isfile(path):
|
||||
paths = [path]
|
||||
else:
|
||||
if query:
|
||||
paths = sorted(glob.glob(os.path.join(path, query)))
|
||||
else:
|
||||
paths = [os.path.join(path, name) for name in sorted(os.listdir(path))]
|
||||
frames = []
|
||||
for path in paths:
|
||||
img = pygame.image.load(path)
|
||||
if transparency:
|
||||
if ppa:
|
||||
frame = img.convert_alpha()
|
||||
else:
|
||||
frame = fill_colorkey(img, key)
|
||||
else:
|
||||
frame = img.convert()
|
||||
frames.append(frame)
|
||||
return frames
|
||||
|
||||
def fill_colorkey(img, key=None):
|
||||
if key is None:
|
||||
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 get_shadowed_text(text, font, offset, color, antialias=True, shadow_color=(0, 0, 0),
|
||||
colorkey=(255, 0, 255)):
|
||||
foreground = font.render(text, antialias, color)
|
||||
|
@ -321,6 +369,24 @@ def get_shadowed_text(text, font, offset, color, antialias=True, shadow_color=(0
|
|||
(abs(offset[1]) - offset[1]) / 2))
|
||||
return surface
|
||||
|
||||
def get_blinds_rects(w, h, step=.05, count=4):
|
||||
blinds = []
|
||||
blind_h = int(round(h / float(count)))
|
||||
for ii in range(1, count + 1):
|
||||
blinds.append(Rect(0, blind_h * ii, w, 0))
|
||||
inflate_h = int(round(blind_h * step))
|
||||
if inflate_h < 1:
|
||||
inflate_h = 1
|
||||
rects = []
|
||||
while blinds[0].h < blind_h:
|
||||
rects.append([])
|
||||
for blind in blinds:
|
||||
bottom = blind.bottom
|
||||
blind.inflate_ip(0, inflate_h)
|
||||
blind.bottom = bottom
|
||||
rects[-1].append(blind.copy())
|
||||
return rects
|
||||
|
||||
def get_blinds_frames(surface, step=.05, count=4, fill=(0, 0, 0, 0)):
|
||||
frames = []
|
||||
rects = []
|
||||
|
|
Loading…
Reference in New Issue