Merge branch 'master' of makar:/var/www/git/pgfw
This commit is contained in:
commit
316d354f07
108
pgfw/Audio.py
108
pgfw/Audio.py
|
@ -1,92 +1,50 @@
|
|||
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
|
||||
BASE_VOLUME = .8
|
||||
|
||||
def __init__(self, game):
|
||||
GameChild.__init__(self, game)
|
||||
self.delegate = self.get_delegate()
|
||||
self.load_fx()
|
||||
self.original_volumes = {}
|
||||
self.volume = self.BASE_VOLUME
|
||||
if self.check_command_line("-mute"):
|
||||
self.volume = 0
|
||||
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, 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):
|
||||
if self.delegate.compare(event, "mute"):
|
||||
self.mute()
|
||||
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)
|
||||
|
||||
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()
|
||||
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)
|
||||
|
|
|
@ -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)
|
||||
|
@ -114,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)
|
||||
|
@ -130,6 +133,7 @@ class Configuration(RawConfigParser):
|
|||
section = "audio"
|
||||
add_section(section)
|
||||
set_option(section, "sfx-path", "aud/fx/", False)
|
||||
set_option(section, "sfx-volume", "1.0", False)
|
||||
section = "interpolator-gui"
|
||||
add_section(section)
|
||||
set_option(section, "margin", "80", False)
|
||||
|
@ -295,10 +299,11 @@ class Configuration(RawConfigParser):
|
|||
exclude = []
|
||||
if self.has_option(section, option):
|
||||
exclude = self.get(section, option)
|
||||
exclude += [".git", ".gitignore", "README", "build/", "dist/",
|
||||
"setup.py", "MANIFEST", "PKG-INFO",
|
||||
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 +400,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",
|
||||
|
@ -409,7 +414,9 @@ class TypeDeclarations(dict):
|
|||
|
||||
"joy": {"int": ["advance", "pause", "select"]},
|
||||
|
||||
"audio": {"path": "sfx-path"},
|
||||
"audio": {"path": "sfx-path",
|
||||
|
||||
"float": "sfx-volume"},
|
||||
|
||||
"event": {"int": "command-id-offset"},
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ class Input(GameChild):
|
|||
self.post_any_command(event.button, cancel)
|
||||
|
||||
def translate_axis_motion(self, event):
|
||||
if not self.suppressed:
|
||||
if not self.suppressed and not self.check_command_line("-disable-joy-axis"):
|
||||
axis = event.axis
|
||||
value = event.value
|
||||
if -.01 < value < .01:
|
||||
|
@ -150,6 +150,11 @@ class Input(GameChild):
|
|||
post("mouse-double-click-left", pos=pos)
|
||||
last = get_secs()
|
||||
self.last_mouse_down_left = last
|
||||
if "mouse" not in self.any_press_ignored_keys:
|
||||
self.post_any_command(event.button)
|
||||
if event.type == MOUSEBUTTONUP:
|
||||
if "mouse" not in self.any_press_ignored_keys:
|
||||
self.post_any_command(event.button, True)
|
||||
|
||||
def get_axes(self):
|
||||
axes = {}
|
||||
|
|
|
@ -404,7 +404,7 @@ class GUI(Animation):
|
|||
def deactivate(self):
|
||||
self.active = False
|
||||
self.time_filter.open()
|
||||
self.audio.muted = self.saved_mute_state
|
||||
# self.audio.muted = self.saved_mute_state
|
||||
self.display.set_mouse_visibility(self.saved_mouse_state)
|
||||
|
||||
def respond_to_command(self, event):
|
||||
|
@ -427,8 +427,8 @@ class GUI(Animation):
|
|||
def activate(self):
|
||||
self.active = True
|
||||
self.time_filter.close()
|
||||
self.saved_mute_state = self.audio.muted
|
||||
self.audio.mute()
|
||||
# self.saved_mute_state = self.audio.muted
|
||||
# self.audio.mute()
|
||||
self.draw()
|
||||
self.saved_mouse_state = self.display.set_mouse_visibility(True)
|
||||
|
||||
|
|
18
pgfw/Note.py
18
pgfw/Note.py
|
@ -124,3 +124,21 @@ class Note(Samples):
|
|||
if channel and panning:
|
||||
channel.set_volume(*panning)
|
||||
return channel
|
||||
|
||||
|
||||
class Chord:
|
||||
|
||||
def __init__(self, *args):
|
||||
self.notes = args
|
||||
|
||||
def play(self, maxtime=0, fadeout=[None], panning=None, fade_in=[0]):
|
||||
if isinstance(fadeout, int):
|
||||
fadeout = [fadeout]
|
||||
if isinstance(fade_in, int):
|
||||
fade_in = [fade_in]
|
||||
for ii, note in enumerate(self.notes):
|
||||
note.play(maxtime, fadeout[ii % len(fadeout)], panning, fade_in[ii % len(fade_in)])
|
||||
|
||||
def stop(self):
|
||||
for note in self.notes:
|
||||
note.stop()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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
|
||||
|
@ -30,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):
|
||||
|
@ -49,13 +50,16 @@ class Setup:
|
|||
def remove_excluded(self, paths, root, exclude):
|
||||
removal = []
|
||||
for path in paths:
|
||||
for pattern in exclude:
|
||||
if fnmatch(normpath(join(root, path)), pattern):
|
||||
removal.append(path)
|
||||
if self.contains_path(join(root, path), exclude):
|
||||
removal.append(path)
|
||||
for path in removal:
|
||||
paths.remove(path)
|
||||
if path in paths:
|
||||
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"])
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
from os.path import exists
|
||||
from re import match
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
from Configuration import Configuration
|
||||
from Setup import Setup
|
||||
|
||||
class SetupOSX(Setup):
|
||||
|
||||
def __init__(self, launcher_path, data_file_paths,
|
||||
config_file_path="config"):
|
||||
Setup.__init__(self)
|
||||
self.launcher_path = launcher_path
|
||||
self.data_file_paths = data_file_paths
|
||||
self.config_file_path = config_file_path
|
||||
|
||||
def setup(self):
|
||||
config = Configuration()
|
||||
setup_obj = Setup()
|
||||
version = config.get_section("setup")["version"]
|
||||
name = setup_obj.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=self.launcher_path, plist=plist)],
|
||||
setup_requires=["py2app"],
|
||||
options=dict(py2app=dict(arch="i386",)),
|
||||
data_files=self.data_file_paths)
|
||||
config_path = "dist/%s.app/Contents/Resources/%s" % \
|
||||
(name, self.config_file_path)
|
||||
if exists(config_path):
|
||||
lines = open(config_path).readlines()
|
||||
fp = open(config_path, "w")
|
||||
for line in lines:
|
||||
if match("^\W*fullscreen\W*=\W*yes\W*", line):
|
||||
fp.write("fullscreen = no\n")
|
||||
else:
|
||||
fp.write(line)
|
|
@ -9,21 +9,25 @@ from pygame.transform import flip
|
|||
from pygame.locals import *
|
||||
|
||||
from Animation import Animation
|
||||
from Vector import Vector
|
||||
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
|
||||
self.alpha = 255
|
||||
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):
|
||||
|
@ -39,11 +43,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,
|
||||
|
@ -204,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:
|
||||
|
@ -249,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()
|
||||
|
||||
|
@ -269,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):
|
||||
|
||||
|
@ -427,3 +454,25 @@ 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()
|
||||
|
||||
|
||||
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))
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 "<dx=%.2f, dy=%.2f, m=%.2f, ang=%.2f>" % \
|
||||
(self.dx, self.dy, self.magnitude, self.angle)
|
||||
|
||||
def __nonzero__(self):
|
||||
return bool(self.magnitude)
|
||||
|
||||
def move(self):
|
||||
self += self.dx, self.dy
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from random import randint
|
||||
from math import sin, cos, atan2, radians, sqrt
|
||||
from random import randint, random
|
||||
from math import sin, cos, atan2, radians, sqrt, pi
|
||||
|
||||
from pygame import Surface, PixelArray
|
||||
from pygame import Surface, PixelArray, Color
|
||||
from pygame.mixer import get_num_channels, Channel
|
||||
from pygame.locals import *
|
||||
|
||||
|
@ -11,14 +11,21 @@ def get_step(start, end, speed):
|
|||
angle = atan2(x1 - x0, y1 - y0)
|
||||
return speed * sin(angle), speed * cos(angle)
|
||||
|
||||
def get_endpoint(start, angle, magnitude):
|
||||
def get_angle(start, end, transpose=False):
|
||||
angle = atan2(end[1] - start[1], end[0] - start[0])
|
||||
if transpose:
|
||||
angle = -angle - pi
|
||||
return angle
|
||||
|
||||
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):
|
||||
|
@ -104,6 +111,14 @@ def collide_line_with_rect(rect, p0, p1):
|
|||
if get_intersection(p0, p1, *line):
|
||||
return True
|
||||
|
||||
def get_random_number_in_range(start, end):
|
||||
return random() * (end - start) + start
|
||||
|
||||
def get_value_in_range(start, end, position, reverse=False):
|
||||
if reverse:
|
||||
position = 1 - position
|
||||
return (end - start) * position + start
|
||||
|
||||
def render_box(font, text, antialias, color, background=None, border=None,
|
||||
border_width=1, padding=0):
|
||||
surface = font.render(text, antialias, color, background)
|
||||
|
@ -142,3 +157,56 @@ 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 get_inverted_surface(base):
|
||||
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()):
|
||||
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() + abs(offset[0]),
|
||||
foreground.get_height() + abs(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
|
||||
|
||||
def get_hsla_color(hue, saturation=100, lightness=50, alpha=100):
|
||||
color = Color(0, 0, 0, 0)
|
||||
color.hsla = hue % 360, saturation, lightness, alpha
|
||||
return color
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
from pygame.gfxdraw import (aacircle, filled_circle, aatrigon, filled_trigon,
|
||||
aapolygon, filled_polygon)
|
||||
|
||||
def aa_filled_circle(surface, cx, cy, radius, color):
|
||||
aacircle(surface, cx, cy, radius, color)
|
||||
filled_circle(surface, cx, cy, radius, color)
|
||||
|
||||
def aa_filled_trigon(surface, x1, y1, x2, y2, x3, y3, color):
|
||||
aatrigon(surface, x1, y1, x2, y2, x3, y3, color)
|
||||
filled_trigon(surface, x1, y1, x2, y2, x3, y3, color)
|
||||
|
||||
def aa_filled_polygon(surface, points, color):
|
||||
aapolygon(surface, points, color)
|
||||
filled_polygon(surface, points, color)
|
Loading…
Reference in New Issue