From 396d689932043b3a583ee261c5b7ff83c1949ef8 Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Sat, 11 Jul 2015 16:56:43 -0400 Subject: [PATCH 01/28] credit --- pgfw/extension.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pgfw/extension.py b/pgfw/extension.py index 41ed482..9408dfa 100644 --- a/pgfw/extension.py +++ b/pgfw/extension.py @@ -59,6 +59,7 @@ def place_in_rect(rect, incoming, contain=True, *args): if not collides: break +# from http://www.realtimerendering.com/resources/GraphicsGems/gemsii/xlines.c def get_intersection(p0, p1, p2, p3): x0, y0 = p0 x1, y1 = p1 From a0aba9a0bb527ec7f3d7269cdd522448560a99c3 Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Tue, 21 Jul 2015 17:43:42 -0400 Subject: [PATCH 02/28] render box --- pgfw/extension.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/pgfw/extension.py b/pgfw/extension.py index 9408dfa..a1a9e81 100644 --- a/pgfw/extension.py +++ b/pgfw/extension.py @@ -1,6 +1,9 @@ from random import randint from math import sin, cos, atan2, radians, sqrt +from pygame import Surface +from pygame.locals import * + def get_step(start, end, speed): x0, y0 = start x1, y1 = end @@ -99,3 +102,29 @@ def collide_line_with_rect(rect, p0, p1): (rect.bottomleft, rect.topleft)): if get_intersection(p0, p1, *line): return True + +def render_box(font, text, antialias, color, background=None, border=None, + border_width=1, padding=0): + surface = font.render(text, antialias, color, background) + if padding: + if isinstance(padding, int): + padding = [padding] * 2 + padding = [x * 2 for x in padding] + rect = surface.get_rect() + padded_surface = Surface(rect.inflate(padding).size, SRCALPHA) + if background is not None: + padded_surface.fill(background) + rect.center = padded_surface.get_rect().center + padded_surface.blit(surface, rect) + surface = padded_surface + if border is not None: + if isinstance(border_width, int): + border_width = [border_width] * 2 + border_width = [x * 2 for x in border_width] + rect = surface.get_rect() + bordered_surface = Surface(rect.inflate(border_width).size) + bordered_surface.fill(border) + rect.center = bordered_surface.get_rect().center + bordered_surface.blit(surface, rect) + surface = bordered_surface + return surface From 303df733a46c5043de5dbd08bf6c40373062f205 Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 23 Jul 2015 16:49:04 -0400 Subject: [PATCH 03/28] zero axis --- pgfw/Input.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pgfw/Input.py b/pgfw/Input.py index c238e2b..3d1acd2 100644 --- a/pgfw/Input.py +++ b/pgfw/Input.py @@ -94,7 +94,7 @@ class Input(GameChild): if not self.suppressed: axis = event.axis value = event.value - if not value: + if -.01 < value < .01: for command in "up", "right", "down", "left": self.post_command(command, cancel=True) if command not in self.any_press_ignored: From 1fcfbb32118f89b91ab54fb87982366d17170d1d Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Thu, 13 Aug 2015 05:17:53 -0400 Subject: [PATCH 04/28] surface color swap --- pgfw/extension.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pgfw/extension.py b/pgfw/extension.py index a1a9e81..f5be18a 100644 --- a/pgfw/extension.py +++ b/pgfw/extension.py @@ -1,7 +1,7 @@ from random import randint from math import sin, cos, atan2, radians, sqrt -from pygame import Surface +from pygame import Surface, PixelArray from pygame.locals import * def get_step(start, end, speed): @@ -128,3 +128,10 @@ def render_box(font, text, antialias, color, background=None, border=None, bordered_surface.blit(surface, rect) surface = bordered_surface return surface + +def get_color_swapped_surface(surface, current, replacement): + swapped = surface.copy() + pixels = PixelArray(swapped) + pixels.replace(current, replacement) + del pixels + return swapped From 3a937ddc963c44fd2395641c0cdead50d38c2cee Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Sat, 15 Aug 2015 03:36:56 -0400 Subject: [PATCH 05/28] busy channel count --- pgfw/extension.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pgfw/extension.py b/pgfw/extension.py index f5be18a..1eeed19 100644 --- a/pgfw/extension.py +++ b/pgfw/extension.py @@ -2,6 +2,7 @@ from random import randint from math import sin, cos, atan2, radians, sqrt from pygame import Surface, PixelArray +from pygame.mixer import get_num_channels, Channel from pygame.locals import * def get_step(start, end, speed): @@ -135,3 +136,9 @@ def get_color_swapped_surface(surface, current, replacement): pixels.replace(current, replacement) del pixels return swapped + +def get_busy_channel_count(): + count = 0 + for index in xrange(get_num_channels()): + count += Channel(index).get_busy() + return count From 55576d6073170404b109ebca6236bef579fc18fc Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Sun, 16 Aug 2015 19:12:24 -0400 Subject: [PATCH 06/28] exclude pattern --- pgfw/Setup.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pgfw/Setup.py b/pgfw/Setup.py index 04cf753..2bbfa56 100644 --- a/pgfw/Setup.py +++ b/pgfw/Setup.py @@ -6,6 +6,7 @@ from distutils.command.install import install from pprint import pprint from fileinput import FileInput from re import sub, match +from fnmatch import fnmatch from Configuration import * @@ -48,8 +49,9 @@ class Setup: def remove_excluded(self, paths, root, exclude): removal = [] for path in paths: - if normpath(join(root, path)) in exclude: - removal.append(path) + for pattern in exclude: + if fnmatch(normpath(join(root, path)), pattern): + removal.append(path) for path in removal: paths.remove(path) return paths From 29c715fcc0f298354a1efbeb6141b0063007c0d7 Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Thu, 20 Aug 2015 03:43:57 -0400 Subject: [PATCH 07/28] wasd --- pgfw/Configuration.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pgfw/Configuration.py b/pgfw/Configuration.py index 4d16b93..c0c83e0 100644 --- a/pgfw/Configuration.py +++ b/pgfw/Configuration.py @@ -106,10 +106,10 @@ class Configuration(RawConfigParser): 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, "up", "K_UP", False) + set_option(section, "right", "K_RIGHT", False) + set_option(section, "down", "K_DOWN", False) + set_option(section, "left", "K_LEFT", 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) From 69b8506069fdaa056748f0a7919740c15fabdf8c Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Sun, 23 Aug 2015 12:14:53 -0400 Subject: [PATCH 08/28] get angle --- pgfw/extension.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pgfw/extension.py b/pgfw/extension.py index 1eeed19..fa7e78c 100644 --- a/pgfw/extension.py +++ b/pgfw/extension.py @@ -6,11 +6,12 @@ from pygame.mixer import get_num_channels, Channel from pygame.locals import * def get_step(start, end, speed): - x0, y0 = start - x1, y1 = end - angle = atan2(x1 - x0, y1 - y0) + angle = get_angle(start, end) return speed * sin(angle), speed * cos(angle) +def get_angle(start, end): + return atan2(end[0] - start[0], end[1] - start[1]) + def get_endpoint(start, angle, magnitude): """clockwise, 0 is up""" x0, y0 = start From dd757dbe385a2e37fb835095723224af31b9b579 Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Mon, 24 Aug 2015 19:38:42 -0400 Subject: [PATCH 09/28] reset on switch frameset --- pgfw/Sprite.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pgfw/Sprite.py b/pgfw/Sprite.py index 5a3da70..5d51f93 100644 --- a/pgfw/Sprite.py +++ b/pgfw/Sprite.py @@ -20,6 +20,7 @@ class Sprite(Animation): self.alpha = 255 self.locations = [] self.framesets = [Frameset(self, framerate=framerate)] + self.frameset_index = 0 self.set_frameset(0) self.locations.append(Location(self)) self.motion_overflow = Vector() @@ -39,11 +40,13 @@ class Sprite(Animation): 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() + if self.frameset_index != identifier: + self.frameset_index = identifier + self.register_interval() + self.update_location_size() + if self.get_current_frameset().length() > 1: + self.play() + self.get_current_frameset().reset() def register_interval(self): self.register(self.shift_frame, From bf38844bbd1849d8d8944788d4c4ef2338dd049d Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 24 Aug 2015 21:25:52 -0400 Subject: [PATCH 10/28] excluded files check --- pgfw/Setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pgfw/Setup.py b/pgfw/Setup.py index 2bbfa56..c704fe0 100644 --- a/pgfw/Setup.py +++ b/pgfw/Setup.py @@ -53,7 +53,8 @@ class Setup: if fnmatch(normpath(join(root, path)), pattern): removal.append(path) for path in removal: - paths.remove(path) + if path in paths: + paths.remove(path) return paths def translate_title(self): From d8f3a3df1b4fd31e574261d3231bf1ec8a69772f Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Mon, 7 Sep 2015 12:19:51 -0400 Subject: [PATCH 11/28] hue shift; fill tile --- pgfw/extension.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pgfw/extension.py b/pgfw/extension.py index fa7e78c..f034826 100644 --- a/pgfw/extension.py +++ b/pgfw/extension.py @@ -143,3 +143,21 @@ def get_busy_channel_count(): for index in xrange(get_num_channels()): count += Channel(index).get_busy() return count + +def get_hue_shifted_surface(base, offset): + surface = base.copy() + pixels = PixelArray(surface) + color = Color(0, 0, 0) + for x in xrange(surface.get_width()): + for y in xrange(surface.get_height()): + h, s, l, a = Color(*surface.unmap_rgb(pixels[x][y])).hsla + if a: + color.hsla = (h + offset) % 360, s, l, a + pixels[x][y] = color + del pixels + return surface + +def fill_tile(surface, tile): + for x in xrange(0, surface.get_width(), tile.get_width()): + for y in xrange(0, surface.get_height(), tile.get_height()): + surface.blit(tile, (x, y)) From 6388584c22a4bf0fb3e450e453dbec62150c7e9a Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Wed, 9 Sep 2015 01:10:37 -0400 Subject: [PATCH 12/28] BlinkingSprite --- pgfw/Sprite.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pgfw/Sprite.py b/pgfw/Sprite.py index 5d51f93..29513d9 100644 --- a/pgfw/Sprite.py +++ b/pgfw/Sprite.py @@ -430,3 +430,17 @@ class Frameset: def reverse(self): self.reversed = not self.reversed + + +class BlinkingSprite(Sprite): + + def __init__(self, parent, blink_rate, framerate=None): + Sprite.__init__(self, parent, framerate) + self.register(self.blink, interval=blink_rate) + self.play(self.blink) + + def reset(self): + self.unhide() + + def blink(self): + self.toggle_hidden() From 7d46bf3719b19e1fada0fc74f39d7c6f58d79994 Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Mon, 14 Sep 2015 06:15:57 -0400 Subject: [PATCH 13/28] RainbowSprite, shadowed text --- pgfw/Sprite.py | 9 +++++++++ pgfw/extension.py | 16 ++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/pgfw/Sprite.py b/pgfw/Sprite.py index 29513d9..7167d4a 100644 --- a/pgfw/Sprite.py +++ b/pgfw/Sprite.py @@ -10,6 +10,7 @@ from pygame.locals import * from Animation import Animation from Vector import Vector +from extension import get_hue_shifted_surface class Sprite(Animation): @@ -444,3 +445,11 @@ class BlinkingSprite(Sprite): def blink(self): self.toggle_hidden() + + +class RainbowSprite(Sprite): + + def __init__(self, parent, image, hue_shift=8, framerate=None): + Sprite.__init__(self, parent, framerate) + for hue in xrange(0, 360, hue_shift): + self.add_frame(get_hue_shifted_surface(image, hue)) diff --git a/pgfw/extension.py b/pgfw/extension.py index f034826..b356220 100644 --- a/pgfw/extension.py +++ b/pgfw/extension.py @@ -161,3 +161,19 @@ def fill_tile(surface, tile): for x in xrange(0, surface.get_width(), tile.get_width()): for y in xrange(0, surface.get_height(), tile.get_height()): surface.blit(tile, (x, y)) + +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) + background = font.render(text, antialias, shadow_color) + alpha = SRCALPHA if antialias else 0 + surface = Surface((foreground.get_width() + offset[0], + foreground.get_height() + offset[1]), alpha) + if not antialias: + surface.set_colorkey(colorkey) + surface.fill(colorkey) + surface.blit(background, ((abs(offset[0]) + offset[0]) / 2, + (abs(offset[1]) + offset[1]) / 2)) + surface.blit(foreground, ((abs(offset[0]) - offset[0]) / 2, + (abs(offset[1]) - offset[1]) / 2)) + return surface From 97425e702b4b2093cd91accab2b4fbad0005e4c2 Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Tue, 15 Sep 2015 21:02:54 -0400 Subject: [PATCH 14/28] reset ticks --- pgfw/TimeFilter.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pgfw/TimeFilter.py b/pgfw/TimeFilter.py index e57e3c1..d819a16 100644 --- a/pgfw/TimeFilter.py +++ b/pgfw/TimeFilter.py @@ -6,9 +6,12 @@ class TimeFilter(GameChild): def __init__(self, parent): GameChild.__init__(self, parent) - self.ticks = self.unfiltered_ticks = self.last_ticks = get_ticks() + self.reset_ticks() self.open() + def reset_ticks(self): + self.ticks = self.unfiltered_ticks = self.last_ticks = get_ticks() + def close(self): self.closed = True From 4ed3f9cec7359a8ef1ec9fadc70eeb0cc0dcd69e Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Wed, 16 Sep 2015 12:22:03 -0400 Subject: [PATCH 15/28] hsla color --- pgfw/extension.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pgfw/extension.py b/pgfw/extension.py index b356220..022e9df 100644 --- a/pgfw/extension.py +++ b/pgfw/extension.py @@ -1,7 +1,7 @@ from random import randint from math import sin, cos, atan2, radians, sqrt -from pygame import Surface, PixelArray +from pygame import Surface, PixelArray, Color from pygame.mixer import get_num_channels, Channel from pygame.locals import * @@ -177,3 +177,8 @@ def get_shadowed_text(text, font, offset, color, antialias=True, shadow_color=(0 surface.blit(foreground, ((abs(offset[0]) - offset[0]) / 2, (abs(offset[1]) - offset[1]) / 2)) return surface + +def get_hsla_color(hue, saturation=100, lightness=50, alpha=100): + color = Color(0, 0, 0, 0) + color.hsla = hue, saturation, lightness, alpha + return color From c9066cf69124d193a27c3bdee2686964599a80a9 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 24 Oct 2015 20:40:20 -0400 Subject: [PATCH 16/28] fnmatch exclude, module check --- pgfw/Configuration.py | 2 +- pgfw/Setup.py | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/pgfw/Configuration.py b/pgfw/Configuration.py index 4d16b93..ef11841 100644 --- a/pgfw/Configuration.py +++ b/pgfw/Configuration.py @@ -296,7 +296,7 @@ class Configuration(RawConfigParser): if self.has_option(section, option): exclude = self.get(section, option) exclude += [".git", ".gitignore", "README", "build/", "dist/", - "setup.py", "MANIFEST", "PKG-INFO", + "setup.py", "MANIFEST", "PKG-INFO", "*.pyc", self.get("setup", "changelog"), self.get("setup", "package-root")] for location in self.get("setup", "additional-packages"): diff --git a/pgfw/Setup.py b/pgfw/Setup.py index 04cf753..3f9f25b 100644 --- a/pgfw/Setup.py +++ b/pgfw/Setup.py @@ -1,11 +1,12 @@ from os import walk, remove -from os.path import sep, join, exists, normpath +from os.path import sep, join, exists, normpath, basename 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 fnmatch import fnmatch from Configuration import * @@ -29,7 +30,8 @@ class Setup: for location in locations: if exists(location): for root, dirs, files in walk(location, followlinks=True): - packages.append(root.replace(sep, ".")) + if exists(join(root, "__init__.py")): + packages.append(root.replace(sep, ".")) return packages def build_data_map(self): @@ -48,12 +50,15 @@ class Setup: def remove_excluded(self, paths, root, exclude): removal = [] for path in paths: - if normpath(join(root, path)) in exclude: + if self.contains_path(join(root, path), exclude): removal.append(path) for path in removal: paths.remove(path) return paths + def contains_path(self, path, container): + return any(fnmatch(path, rule) or fnmatch(basename(path), rule) for rule in container) + def translate_title(self): config = self.config.get_section("setup") title = config["title"].replace(" ", config["whitespace-placeholder"]) From 65584c30ca1479019b7f3b43404c2752fdcb9100 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 24 Oct 2015 21:09:20 -0400 Subject: [PATCH 17/28] .git exclude wildcard --- pgfw/Configuration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pgfw/Configuration.py b/pgfw/Configuration.py index d332b76..11eeb1b 100644 --- a/pgfw/Configuration.py +++ b/pgfw/Configuration.py @@ -295,7 +295,7 @@ class Configuration(RawConfigParser): exclude = [] if self.has_option(section, option): exclude = self.get(section, option) - exclude += [".git", ".gitignore", "README", "build/", "dist/", + exclude += [".git*", "README", "build/", "dist/", "setup.py", "MANIFEST", "PKG-INFO", "*.pyc", self.get("setup", "changelog"), self.get("setup", "package-root")] From 42f6fcb9a28c5297cfedbe35cb0785e10917112b Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 25 Oct 2015 07:05:42 -0400 Subject: [PATCH 18/28] os x --- pgfw/Configuration.py | 10 ++++++---- pgfw/SetupOSX.py | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 pgfw/SetupOSX.py diff --git a/pgfw/Configuration.py b/pgfw/Configuration.py index 11eeb1b..fc8b175 100644 --- a/pgfw/Configuration.py +++ b/pgfw/Configuration.py @@ -65,6 +65,7 @@ class Configuration(RawConfigParser): 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, "osx-includes", "", False) section = "display" add_section(section) set_option(section, "dimensions", "480, 360", False) @@ -295,10 +296,11 @@ class Configuration(RawConfigParser): exclude = [] if self.has_option(section, option): exclude = self.get(section, option) - exclude += [".git*", "README", "build/", "dist/", - "setup.py", "MANIFEST", "PKG-INFO", "*.pyc", + exclude += [".git*", "README", "build/", "dist/", "*.egg-info", + "*.py", "MANIFEST*", "PKG-INFO", "*.pyc", "*.swp", self.get("setup", "changelog"), - self.get("setup", "package-root")] + self.get("setup", "package-root"), + self.get("setup", "init-script")] for location in self.get("setup", "additional-packages"): exclude.append(location) self.set(section, option, exclude, False) @@ -395,7 +397,7 @@ class TypeDeclarations(dict): "setup": {"list": ["classifiers", "resource-search-path", "requirements", "data-exclude", - "additional-packages"], + "additional-packages", "osx-includes"], "path": ["installation-dir", "changelog", "description-file", "main-object", "icon-path", "windows-dist-path", diff --git a/pgfw/SetupOSX.py b/pgfw/SetupOSX.py new file mode 100644 index 0000000..9ef004c --- /dev/null +++ b/pgfw/SetupOSX.py @@ -0,0 +1,27 @@ +from setuptools import setup, find_packages +from Configuration import Configuration +from Setup import Setup + +class SetupOSX(Setup): + + def __init__(self): + Setup.__init__(self) + + def setup(self): + config = Configuration() + setup_section = config.get_section("setup") + version = setup_section["version"] + name = self.translate_title() + plist = dict( + CFBundleIconFile=name, + CFBundleName=name, + CFBundleShortVersionString=version, + CFBundleGetInfoString=' '.join([name, version]), + CFBundleExecutable=name, + CFBundleIdentifier='org.' + name.lower()) + setup(name=name, + version=version, + app=[dict(script=setup_section["init-script"], plist=plist)], + setup_requires=["py2app"], + options=dict(py2app=dict(arch="i386",)), + data_files=setup_section["osx-includes"]) From bc7d3b9cfbd86ef9076c011223dbc3744808514d Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Thu, 12 Nov 2015 17:02:14 -0500 Subject: [PATCH 19/28] counterclockwise note --- pgfw/Configuration.py | 2 +- pgfw/extension.py | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/pgfw/Configuration.py b/pgfw/Configuration.py index fc8b175..708bc58 100644 --- a/pgfw/Configuration.py +++ b/pgfw/Configuration.py @@ -297,7 +297,7 @@ class Configuration(RawConfigParser): if self.has_option(section, option): exclude = self.get(section, option) exclude += [".git*", "README", "build/", "dist/", "*.egg-info", - "*.py", "MANIFEST*", "PKG-INFO", "*.pyc", "*.swp", + "*.py", "MANIFEST*", "PKG-INFO", "*.pyc", "*.swp", "*~", self.get("setup", "changelog"), self.get("setup", "package-root"), self.get("setup", "init-script")] diff --git a/pgfw/extension.py b/pgfw/extension.py index 022e9df..7f6ba90 100644 --- a/pgfw/extension.py +++ b/pgfw/extension.py @@ -10,16 +10,18 @@ def get_step(start, end, speed): return speed * sin(angle), speed * cos(angle) def get_angle(start, end): + """counterclockwise, 0 is down""" return atan2(end[0] - start[0], end[1] - start[1]) -def get_endpoint(start, angle, magnitude): +def get_endpoint(start, angle, magnitude, translate_angle=True): """clockwise, 0 is up""" x0, y0 = start - dx, dy = get_delta(angle, magnitude) + dx, dy = get_delta(angle, magnitude, translate_angle) return x0 + dx, y0 + dy -def get_delta(angle, magnitude): - angle = radians(angle) +def get_delta(angle, magnitude, translate_angle=True): + if translate_angle: + angle = radians(angle) return sin(angle) * magnitude, -cos(angle) * magnitude def rotate_2d(point, center, angle, translate_angle=True): From e253306cb15354f3f0fd8f843ab8c54509fe4f27 Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Sat, 28 Nov 2015 17:37:48 -0500 Subject: [PATCH 20/28] evector; sprite neighbor, step --- pgfw/Sprite.py | 47 ++++++++++++++++++++++++++++---------- pgfw/Vector.py | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 12 deletions(-) diff --git a/pgfw/Sprite.py b/pgfw/Sprite.py index 7167d4a..b7cebce 100644 --- a/pgfw/Sprite.py +++ b/pgfw/Sprite.py @@ -9,12 +9,12 @@ from pygame.transform import flip from pygame.locals import * from Animation import Animation -from Vector import Vector -from extension import get_hue_shifted_surface +from Vector import Vector, EVector +from extension import get_hue_shifted_surface, get_step class Sprite(Animation): - def __init__(self, parent, framerate=None): + def __init__(self, parent, framerate=None, neighbors=[], mass=None): Animation.__init__(self, parent, self.shift_frame, framerate) self.frames = [] self.mirrored = False @@ -22,10 +22,12 @@ 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.set_frameset(0) self.locations.append(Location(self)) self.motion_overflow = Vector() - self.stop() self.display_surface = self.get_display_surface() def __getattr__(self, name): @@ -208,21 +210,26 @@ class Sprite(Animation): for frameset in self.framesets: frameset.reverse() - def go(self, dx=0, dy=0): - self.go_vector = Vector(dx, dy) + def set_step(self, dx=0, dy=0, magnitude=None, angle=0): + self.step.set_step(dx, dy, magnitude, angle) - def stop(self): - self.go_vector = Vector() + def cancel_step(self): + self.step.set_step(0, 0) - def is_going(self): - return self.go_vector != [0, 0] + def is_stepping(self): + return bool(self.step) def update(self, areas=None, substitute=None): Animation.update(self) - if self.is_going(): - self.move(*self.go_vector) + 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(): self.draw(areas, substitute) + # for location in self.locations: + # location.update() def draw(self, areas=None, substitute=None): for location in self.locations: @@ -253,6 +260,10 @@ class Location(Rect): overflow[1] -= int(overflow[1]) return excess + def move_to(self, x, y, base=None): + ox, oy = self.apply_motion_overflow(base) + self.move_ip(x - ox, y - oy) + def reset_motion_overflow(self): self.motion_overflow.place_at_origin() @@ -273,6 +284,18 @@ 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): diff --git a/pgfw/Vector.py b/pgfw/Vector.py index 819e847..f14c807 100644 --- a/pgfw/Vector.py +++ b/pgfw/Vector.py @@ -1,8 +1,18 @@ +from math import pi, degrees + +from extension import get_delta, get_distance, get_angle + class Vector(list): def __init__(self, x=0, y=0): list.__init__(self, (x, y)) + def __repr__(self): + message = "<%f" % self[0] + for value in self[1:]: + message += ", %f" % value + return message + ">" + def __getattr__(self, name): if name == "x": return self[0] @@ -48,6 +58,24 @@ class Vector(list): self.y *= other return self + def __eq__(self, other): + for sv, ov in zip(self, other): + if value != other[ii]: + return False + return True + + def __ne__(self, other): + for sv, ov in zip(self, other): + if value == other[ii]: + return False + return True + + def __nonzero__(self): + for value in self: + if bool(value): + return True + return False + def apply_to_components(self, function): self.x = function(self.x) self.y = function(self.y) @@ -67,3 +95,37 @@ class Vector(list): def place_at_origin(self): self.x = 0 self.y = 0 + + +class EVector(Vector): + + def __init__(self, x=0, y=0, dx=0, dy=0, magnitude=None, angle=0): + Vector.__init__(self, x, y) + self.set_step(dx, dy, magnitude, angle) + + def set_step(self, dx=0, dy=0, magnitude=None, angle=0): + """specify angle in radians, counter-clockwise, 0 is up""" + if magnitude is not None: + self.magnitude = magnitude + self.angle = angle + self.dx, self.dy = get_delta(angle, magnitude, False) + else: + self.dx = dx + self.dy = dy + if dx == 0 and dy == 0: + self.magnitude = 0 + self.angle = 0 + else: + end = self.x + dx, self.y + dy + self.magnitude = get_distance(self, end) + self.angle = -get_angle(self, end) - pi + + def __repr__(self): + return "" % \ + (self.dx, self.dy, self.magnitude, self.angle) + + def __nonzero__(self): + return bool(self.magnitude) + + def move(self): + self += self.dx, self.dy From ec2263596f400e34af2c93b7c807d48885291c8c Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Sun, 29 Nov 2015 00:27:48 -0500 Subject: [PATCH 21/28] transpose --- pgfw/extension.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/pgfw/extension.py b/pgfw/extension.py index 7f6ba90..ff54799 100644 --- a/pgfw/extension.py +++ b/pgfw/extension.py @@ -1,5 +1,5 @@ from random import randint -from math import sin, cos, atan2, radians, sqrt +from math import sin, cos, atan2, radians, sqrt, pi from pygame import Surface, PixelArray, Color from pygame.mixer import get_num_channels, Channel @@ -9,9 +9,12 @@ def get_step(start, end, speed): angle = get_angle(start, end) return speed * sin(angle), speed * cos(angle) -def get_angle(start, end): +def get_angle(start, end, transpose=False): """counterclockwise, 0 is down""" - return atan2(end[0] - start[0], end[1] - start[1]) + angle = atan2(end[0] - start[0], end[1] - start[1]) + if transpose: + return -angle - pi + return angle def get_endpoint(start, angle, magnitude, translate_angle=True): """clockwise, 0 is up""" From 732a00d079727413c42dce6d941313f40939bbfa Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Wed, 9 Dec 2015 15:58:27 -0500 Subject: [PATCH 22/28] volume --- pgfw/Audio.py | 102 +++++++++++------------------------------- pgfw/Configuration.py | 4 +- pgfw/extension.py | 2 +- 3 files changed, 30 insertions(+), 78 deletions(-) diff --git a/pgfw/Audio.py b/pgfw/Audio.py index 2c230e9..e2f8344 100644 --- a/pgfw/Audio.py +++ b/pgfw/Audio.py @@ -1,92 +1,42 @@ from os import listdir from os.path import join -from pygame.mixer import Channel, Sound, music, find_channel +from pygame.mixer import Channel, Sound, music, find_channel, get_num_channels from GameChild import * from Input import * class Audio(GameChild): - current_channel = None - paused = False - muted = False + UP, DOWN = .1, -.1 def __init__(self, game): GameChild.__init__(self, game) - self.delegate = self.get_delegate() - self.load_fx() + if self.check_command_line("-mute"): + self.set_volume(mute=True) 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 set_volume(self, volume=None, increment=None, channels=None, mute=False): + if not channels: + channels = (Channel(ii) for ii in xrange(get_num_channels())) + elif isinstance(channels, Channel): + channels = [channels] + for channel in channels: + if mute: + volume = 0 + elif increment: + volume = channel.get_volume() + increment + if volume > 1: + volume = 1.0 + elif volume < 0: + volume = 0 + channel.set_volume(volume) 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() + compare = self.get_game().delegate.compare + if compare(event, "volume-mute"): + self.set_volume(mute=True) + elif compare(event, "volume-up"): + self.set_volume(increment=self.UP) + elif compare(event, "volume-down"): + self.set_volume(increment=self.DOWN) diff --git a/pgfw/Configuration.py b/pgfw/Configuration.py index 708bc58..df1d279 100644 --- a/pgfw/Configuration.py +++ b/pgfw/Configuration.py @@ -115,7 +115,9 @@ class Configuration(RawConfigParser): 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, "volume-down", "K_F1", False) + set_option(section, "volume-up", "K_F2", False) + set_option(section, "volume-mute", "K_F3", False) set_option(section, "toggle-interpolator", "K_F7", False) section = "joy" add_section(section) diff --git a/pgfw/extension.py b/pgfw/extension.py index ff54799..f966123 100644 --- a/pgfw/extension.py +++ b/pgfw/extension.py @@ -185,5 +185,5 @@ def get_shadowed_text(text, font, offset, color, antialias=True, shadow_color=(0 def get_hsla_color(hue, saturation=100, lightness=50, alpha=100): color = Color(0, 0, 0, 0) - color.hsla = hue, saturation, lightness, alpha + color.hsla = hue % 360, saturation, lightness, alpha return color From a65355bf9f8e0564e2a103fe451f3b2eb92437d2 Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Thu, 10 Dec 2015 12:26:55 -0500 Subject: [PATCH 23/28] volume modifier --- pgfw/Audio.py | 40 ++++++++++++++++++++++++---------------- pgfw/Game.py | 1 + 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/pgfw/Audio.py b/pgfw/Audio.py index e2f8344..6598f3f 100644 --- a/pgfw/Audio.py +++ b/pgfw/Audio.py @@ -9,28 +9,27 @@ from Input import * class Audio(GameChild): UP, DOWN = .1, -.1 + BASE_VOLUME = .8 def __init__(self, game): GameChild.__init__(self, game) + self.original_volumes = {} + self.volume = self.BASE_VOLUME if self.check_command_line("-mute"): - self.set_volume(mute=True) + self.volume = self.BASE_VOLUME self.subscribe(self.respond) - def set_volume(self, volume=None, increment=None, channels=None, mute=False): - if not channels: - channels = (Channel(ii) for ii in xrange(get_num_channels())) - elif isinstance(channels, Channel): - channels = [channels] - for channel in channels: - if mute: - volume = 0 - elif increment: - volume = channel.get_volume() + increment - if volume > 1: - volume = 1.0 - elif volume < 0: - volume = 0 - channel.set_volume(volume) + def set_volume(self, volume=None, increment=None, mute=False): + if mute: + self.volume = 0 + elif increment: + self.volume += increment + if self.volume > 1: + self.volume = 1.0 + elif self.volume < 0: + self.volume = 0 + else: + self.volume = volume def respond(self, event): compare = self.get_game().delegate.compare @@ -40,3 +39,12 @@ class Audio(GameChild): self.set_volume(increment=self.UP) elif compare(event, "volume-down"): self.set_volume(increment=self.DOWN) + + def update(self): + for ii in xrange(get_num_channels()): + channel = 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) diff --git a/pgfw/Game.py b/pgfw/Game.py index b1402cc..ae7f98b 100644 --- a/pgfw/Game.py +++ b/pgfw/Game.py @@ -54,6 +54,7 @@ class Game(GameChild): self.update() else: self.interpolator.gui.update() + self.audio.update() if self.video_recorder.requested: self.video_recorder.update() From e36a232a3ee4faa665e1dbffcfef308224867f15 Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Mon, 15 Feb 2016 19:32:18 -0500 Subject: [PATCH 24/28] check dict for command --- pgfw/Delegate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pgfw/Delegate.py b/pgfw/Delegate.py index bf9c65b..8b49587 100644 --- a/pgfw/Delegate.py +++ b/pgfw/Delegate.py @@ -79,7 +79,7 @@ class Delegate(GameChild): return self.get_command_attribute(evt) in commands def get_command_attribute(self, evt): - return evt.dict[self.command_key] + return evt.dict.has_key(self.command_key) and evt.dict[self.command_key] def post(self, command=None, cancel=False, **attributes): attributes[self.command_key] = command From 90747f5b5e4c8b9e78e46cee6e5790cbf51c7ae4 Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Wed, 17 Feb 2016 15:14:29 -0500 Subject: [PATCH 25/28] volume 0 --- pgfw/Audio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pgfw/Audio.py b/pgfw/Audio.py index 6598f3f..8e2bcbd 100644 --- a/pgfw/Audio.py +++ b/pgfw/Audio.py @@ -16,7 +16,7 @@ class Audio(GameChild): self.original_volumes = {} self.volume = self.BASE_VOLUME if self.check_command_line("-mute"): - self.volume = self.BASE_VOLUME + self.volume = 0 self.subscribe(self.respond) def set_volume(self, volume=None, increment=None, mute=False): From 6155bdcd7d4e5fcff40a2c76051f7b35a70d8a8e Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Thu, 25 Feb 2016 15:28:28 -0500 Subject: [PATCH 26/28] negative shadow offset --- pgfw/extension.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pgfw/extension.py b/pgfw/extension.py index f966123..b1354aa 100644 --- a/pgfw/extension.py +++ b/pgfw/extension.py @@ -172,8 +172,8 @@ def get_shadowed_text(text, font, offset, color, antialias=True, shadow_color=(0 foreground = font.render(text, antialias, color) background = font.render(text, antialias, shadow_color) alpha = SRCALPHA if antialias else 0 - surface = Surface((foreground.get_width() + offset[0], - foreground.get_height() + offset[1]), alpha) + surface = Surface((foreground.get_width() + abs(offset[0]), + foreground.get_height() + abs(offset[1])), alpha) if not antialias: surface.set_colorkey(colorkey) surface.fill(colorkey) From 838184cb3f86120f5830855427528d3fc78c5eaf Mon Sep 17 00:00:00 2001 From: Frank DeMarco Date: Fri, 11 Mar 2016 23:38:46 -0500 Subject: [PATCH 27/28] inverted surface --- pgfw/extension.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pgfw/extension.py b/pgfw/extension.py index 7f6ba90..127e5a0 100644 --- a/pgfw/extension.py +++ b/pgfw/extension.py @@ -159,6 +159,9 @@ def get_hue_shifted_surface(base, offset): del pixels return surface +def get_inverted_surface(base): + return get_hue_shifted_surface(base, 180) + def fill_tile(surface, tile): for x in xrange(0, surface.get_width(), tile.get_width()): for y in xrange(0, surface.get_height(), tile.get_height()): From 1f4b3384edd02ee9eec2b80c1f8ce2513decb54e Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 12 Mar 2016 00:13:01 -0500 Subject: [PATCH 28/28] color component difference --- pgfw/extension.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pgfw/extension.py b/pgfw/extension.py index 3dd470e..b665a62 100644 --- a/pgfw/extension.py +++ b/pgfw/extension.py @@ -163,7 +163,18 @@ def get_hue_shifted_surface(base, offset): return surface def get_inverted_surface(base): - return get_hue_shifted_surface(base, 180) + surface = base.copy() + pixels = PixelArray(surface) + for x in xrange(surface.get_width()): + for y in xrange(surface.get_height()): + color = Color(*surface.unmap_rgb(pixels[x][y])) + if color.hsla[3]: + color.r = 255 - color.r + color.g = 255 - color.g + color.b = 255 - color.b + pixels[x][y] = color + del pixels + return surface def fill_tile(surface, tile): for x in xrange(0, surface.get_width(), tile.get_width()):