January 28, 2014♦
☀
E
F
F
L
U
E
N
C
E
☀
from math import ceil
from collections import deque
from pygame import Surface
from pygame.draw import polygon
from pygame.locals import *
from lib.pgfw.pgfw.Sprite import Sprite
class ExitArrow(Sprite):
def __init__(self, parent):
Sprite.__init__(self, parent)
self.load_configuration()
self.set_mask()
self.set_hues()
self.set_frames()
self.reset()
self.set_framerate(self.interval)
self.set_alpha(self.alpha)
def load_configuration(self):
config = self.get_configuration("exit-arrow")
self.width = config["width"]
self.height = config["height"]
self.overlap = config["overlap"]
self.arrow_count = config["arrow-count"]
self.hue = config["hue"]
self.frame_count = config["frame-count"]
self.interval = config["interval"]
self.saturation = config["saturation"]
self.offset = config["offset"]
self.fade_in_length = config["fade-in"]
self.fade_out_length = config["fade-out"]
self.alpha = config["alpha"]
def set_mask(self):
surface = Surface(self.get_size())
surface.set_colorkey((0, 0, 0))
rect = surface.get_rect()
width = self.width
x = 0
for ii in xrange(self.arrow_count):
points = (x, rect.centery), (x + width, 0), (x + width, rect.bottom)
polygon(surface, (255, 255, 255), points)
x += width - self.overlap
self.mask = surface
def get_size(self):
count = self.arrow_count
return self.width * count - self.overlap * (count - 1), self.height
def set_hues(self):
start, end = self.hue
step = float(end - start) / (self.frame_count - 1)
hues = deque([start])
while start < end:
start += step
hues.append(start)
hues.append(end)
self.hues = hues
def set_frames(self):
for _ in xrange(self.frame_count):
self.append_frame()
def append_frame(self):
width, height = self.get_size()
gradient = Surface((width, height))
gradient.set_colorkey((0, 0, 0))
hues = self.hues
step = float(width) / self.arrow_count / len(hues)
x = 0
color = Color(0, 0, 0)
while x < width:
for hue in hues:
color.hsla = hue, self.saturation, 50, 100
gradient.fill(color, (int(x), 0, ceil(step), height))
x += step
hues.rotate(-1)
mask = self.mask.convert()
gradient.blit(mask, (0, 0), None, BLEND_RGBA_MIN)
self.add_frame(gradient)
def reset(self):
location = self.location
base = self.parent.door.background.location
location.left = base.centerx + self.offset
location.centery = base.centery
self.fade(0, out=True)
def fade(self, length=None, out=None):
if length is None:
length = self.fade_out_length if out else self.fade_in_length
Sprite.fade(self, length, out)
def update(self):
self.move(-self.parent.velocity[0])
Sprite.update(self)
from os.path import join
from math import tan, radians
from pygame import Rect, Surface, Color
from pygame.image import load
from pygame.draw import polygon, ellipse, circle
from pygame.mask import from_surface, Mask
from pygame.locals import *
from lib.pgfw.pgfw.GameChild import GameChild
from lib.pgfw.pgfw.Sprite import Sprite
class Food(Sprite):
def __init__(self, parent):
Sprite.__init__(self, parent)
self.compare = self.get_delegate().compare
self.time_filter = self.get_game().time_filter
self.mouth = Mouth(self)
self.scope = Scope(self)
self.load_configuration()
self.load_nodesets()
self.set_frames()
self.set_frameset("cursed")
self.subscribe(self.respond)
self.register(self.unfreeze)
self.set_mask()
self.reset()
self.set_base()
def load_configuration(self):
config = self.get_configuration("food")
self.root = config["path"]
self.offset = config["offset"]
self.dx = config["dx"]
self.angle_range = config["angle-range"]
self.crouch_offset = config["crouch"]
self.drop_velocity = config["drop-velocity"]
self.dx_boost = config["dx-boost"]
self.blink_rate = config["blink-rate"]
self.freeze_length = config["freeze-length"]
def load_nodesets(self):
interpolator = self.get_game().interpolator
self.charge_nodeset = interpolator.get_nodeset("charge")
self.jump_width_nodeset = interpolator.get_nodeset("jump-width");
self.jump_height_nodeset = interpolator.get_nodeset("jump-height");
def set_frames(self):
root = self.get_resource(join(self.root, str(self.parent.index)))
self.load_from_path(root, True, omit=True)
self.add_frameset(0, name="cursed")
self.add_frameset(1, name="uncursed")
self.add_frameset([0, 1], name="transforming")
self.set_crouched()
self.set_frozen()
def set_crouched(self):
cursed = self.frames[0]
cursed_rect = cursed.get_rect()
offset = self.crouch_offset
surface = Surface((cursed_rect.w, cursed_rect.h - offset), SRCALPHA)
destination = Rect(0, 0, cursed_rect.w, cursed_rect.h / 2 + 1)
area = destination.move(0, 0)
destination.bottom = surface.get_rect().bottom
area.bottom = cursed_rect.bottom
surface.blit(cursed, destination, area)
destination.top = 0
surface.blit(cursed, destination, destination)
self.add_frame(surface, omit=True)
self.add_frameset(2, name="crouched")
def set_frozen(self):
surface = Surface(self.location.size)
surface.set_colorkey((0, 0, 0))
self.add_frame(surface, omit=True)
self.add_frameset([0, 3], self.blink_rate, "frozen")
def respond(self, event):
parent = self.parent
if parent.active:
if self.compare(event, "any") and not self.charging() and \
not self.frozen:
self.activate_charge(event.id)
elif self.compare(event, "any", cancel=True):
if event.id == self.charge_key:
if not self.jumping and parent.is_going():
parent.exit_available = False
parent.exit_arrow.fade(out=True)
self.jump()
self.cancel_charge()
def activate_charge(self, key):
self.charge_key = key
self.set_frameset("crouched")
self.move(0, self.crouch_offset)
self.parent.siphon.contract()
def jump(self):
self.jumping = True
self.submitted_charge = self.charge
rect = self.jump_rect = Rect((0, 0), self.get_jump_size())
rect.bottomleft = self.location.center
def get_jump_size(self):
charge = self.submitted_charge
return int(round(self.jump_width_nodeset.get_y(charge))), \
int(round(self.jump_height_nodeset.get_y(charge)))
def cancel_charge(self):
self.set_frameset("cursed")
self.move(0, -self.crouch_offset)
self.charge_key = None
self.charge_length = 0
self.charge = 0
self.parent.siphon.release()
def set_mask(self):
self.mask = from_surface(self.get_current_frame())
def reset(self):
self.ground = self.parent.platforms[0].rect.top
self.falling = False
self.dropping = False
self.submitted_charge = 0
self.cancel_jump()
self.cancel_charge()
self.place_at_start()
self.unfreeze()
self.scope.reset()
def place_at_start(self):
self.rect.bottomleft = self.offset, self.ground
def cancel_jump(self, offset=None):
self.location.bottom = self.ground
if offset:
self.location.right -= offset
self.jumping = False
self.gravity_effect = 0
self.previous_location = None
self.last_jump_x = 0
def set_base(self):
rect = self.rect
yy = rect.h - 2
start = None
for xx in xrange(rect.w):
visible = self.mask.get_at((xx, yy))
if start is None:
if visible:
start = xx
else:
if not visible:
break
width = xx - start
self.base = Rect(start, yy, width, 3)
def freeze(self):
if not self.frozen:
self.frozen = True
if self.charging():
self.cancel_charge()
self.set_frameset("frozen")
self.play(self.unfreeze, delay=self.freeze_length, play_once=True)
def unfreeze(self):
self.frozen = False
self.set_frameset("cursed")
def update(self):
if self.parent.active:
if self.jumping:
self.propell()
if not self.falling and self.rect.bottom >= self.ground and \
self.last_jump_x > 0:
collide = self.collide_with_platform()
if collide:
self.cancel_jump(collide)
else:
self.falling = True
elif self.rect.top > self.display_surface.get_height():
self.parent.queue_reset()
elif self.parent.is_going():
self.move(-self.parent.velocity[0])
if self.falling:
index = self.location.collidelist(self.parent.platforms)
if index > -1:
platform = self.parent.platforms[index].location
intersection = self.location.clip(platform)
if platform.left > self.location.left:
self.location.right = platform.left
else:
self.location.left = platform.right
self.dropping = True
self.update_charge()
self.scope.place()
Sprite.update(self)
if self.charging():
self.mouth.update()
self.scope.update()
def propell(self):
self.previous_location = Rect(self.location)
if not self.dropping:
rect = self.jump_rect
w, h = rect.size = self.get_jump_size()
x = self.dx + (self.parent.velocity[0] - 1) * self.dx_boost + \
self.last_jump_x
if w == 0:
w = .00000000001
y = (-2 * h / (.5 * w ** 2)) * x ** 2 + (4 * h / w) * x
self.location.center = rect.move(int(round(x)),
int(round(-y))).bottomleft
self.last_jump_x = x
else:
self.move(*self.drop_velocity)
def collide_with_platform(self):
base = self.base
previous = base.move(*self.previous_location.topleft)
current = base.move(*self.location.topleft)
box = Rect(previous.topleft, (current.right - previous.left,
current.bottom - previous.top))
platform_index = box.collidelist(self.parent.platforms)
if platform_index > -1:
stripe = Surface(box.size)
stripe.set_colorkey((0, 0, 0))
polygon(stripe, (255, 255, 255),
((0, 0), (base.w, 0), box.size, (box.w - base.w, box.h)))
stripe_mask = from_surface(stripe)
platform = self.parent.platforms[platform_index]
platform_mask = from_surface(Surface((platform.location.w, 3)))
offset = platform.location.left - box.left, \
platform.location.top - 1 - box.top
overlap = stripe_mask.overlap(platform_mask, offset)
if overlap:
for x in xrange(stripe_mask.get_size()[0]):
if stripe_mask.get_at((x, overlap[1] + 1)):
break
return box.w - base.w - x
def update_charge(self):
if self.charging():
self.charge_length += self.time_filter.get_last_frame_duration()
self.charge = self.charge_nodeset.get_y(self.charge_length)
def charging(self):
return self.charge_key is not None
class Mouth(Surface, GameChild):
transparent_color = (255, 0, 255)
def __init__(self, parent):
GameChild.__init__(self, parent)
self.set_images()
self.init_surface()
self.set_background()
self.load_configuration()
def set_images(self):
get = self.get_resource
self.lower_jaw = load(get("food", "lower-jaw-path")).convert_alpha()
self.lower_jaw_rect = self.lower_jaw.get_rect()
self.upper_jaw = load(get("food", "upper-jaw-path")).convert_alpha()
self.upper_jaw_rect = self.upper_jaw.get_rect()
def init_surface(self):
Surface.__init__(self, self.get_configuration("food", "mouth-size"),
SRCALPHA)
def set_background(self):
surface = Surface(self.get_size())
key = self.transparent_color
surface.fill(key)
surface.set_colorkey(key)
surface.set_alpha(self.get_configuration("food", "mouth-bg-alpha"))
self.background = surface
def load_configuration(self):
config = self.get_configuration("food")
self.offset = config["mouth-offset"]
self.background_shrink = config["mouth-bg-shrink"]
self.gap = config["mouth-gap"]
def update(self):
self.display_surface = self.parent.display_surface
self.init_surface()
self.clear_background()
self.rect = self.get_position(self.parent.location)
self.draw_jaws()
mask = self.draw_mask()
self.draw_background(mask, self.rect)
self.display_surface.blit(self, self.rect)
if self.parent.scope.active:
scope_rect = self.get_position(self.parent.scope.extra_location)
self.draw_background(mask, scope_rect)
self.display_surface.blit(self, scope_rect)
def clear_background(self):
self.background.fill(self.transparent_color)
def get_position(self, base):
offset = self.offset
rect = self.get_rect()
rect.center = base.left + offset[0], base.bottom - offset[1]
return rect
def draw_jaws(self):
rect = self.rect
center = rect.h / 2
offset = max(self.gap, int(round(self.parent.charge * center)))
lower_rect = self.lower_jaw_rect
lower_rect.bottom = center + offset
self.blit(self.lower_jaw, lower_rect)
upper_rect = self.upper_jaw_rect
upper_rect.top = center - offset
self.blit(self.upper_jaw, upper_rect)
def draw_mask(self):
surface = Surface(self.get_size(), SRCALPHA)
width = self.rect.w
height = int(round(self.rect.h * self.parent.charge))
rect = Rect(0, 0, width, height)
rect.centery = self.rect.h / 2
ellipse(surface, (255, 255, 255), rect)
self.blit(surface, (0, 0), None, BLEND_RGBA_MIN)
return rect
def draw_background(self, ellipse_rect, rect):
shrink = self.background_shrink
if ellipse_rect.h >= -shrink[0]:
ellipse(self.background, (0, 0, 0), ellipse_rect.inflate(*shrink))
self.display_surface.blit(self.background, rect)
class LowerJaw(Sprite):
def __init__(self, parent):
Sprite.__init__(self, parent)
self.load_from_path(self.get_resource("food", "lower-jaw-path"), True)
class UpperJaw(Sprite):
def __init__(self, parent):
Sprite.__init__(self, parent)
self.load_from_path(self.get_resource("food", "upper-jaw-path"), True)
class Scope(Sprite):
def __init__(self, parent):
Sprite.__init__(self, parent)
self.active = False
self.limit = 400
self.reset()
def offset_points(self, points):
offset = []
for point in points:
offset.append((point[0], point[1] + 2))
return offset
def reset(self):
if self.active:
self.parent.remove_locations(self.extra_location)
self.active = False
def place(self):
if self.parent.parent.is_going():
if not self.active and self.parent.location.right <= 0:
self.active = True
self.extra_location = self.parent.add_location()
if self.active:
if self.parent.location.right > 0:
self.reset()
else:
if self.parent.location.right <= -self.limit:
self.parent.parent.queue_reset()
self.set_frame()
location = self.location
location.centery = self.parent.location.centery
self.extra_location.reset_motion_overflow()
self.extra_location.midright = location.right - 15, \
location.centery
def set_frame(self):
surface = Surface((76, 60))
rect = surface.get_rect()
key = (255, 0, 255)
surface.fill(key)
surface.set_colorkey(key)
background = (128, 128, 128)
distance = self.parent.location.right
if distance < -self.limit:
distance = -self.limit
foreground = Color(0, 0, 0)
limit = self.limit
foreground.hsla = int(120 * (limit + distance) / limit), 95, 55, 100
points = (0, rect.h / 2 - 1), (8, rect.h / 2 - 11), (8, rect.h / 2 + 9)
polygon(surface, background, self.offset_points(points))
polygon(surface, foreground, points)
square = Rect(8, rect.h / 2 - 6, 10, 10)
surface.fill(background, square.move(0, 2))
surface.fill(foreground, square)
center = 46, rect.h / 2 - 1
radius = 29
circle(surface, background, (center[0], center[1] + 2), radius, 10)
area = circle(surface, foreground, center, radius, 10)
ellipse(surface, foreground, area.inflate(-1, 0), 9)
ellipse(surface, foreground, area.inflate(0, -1), 9)
ellipse(surface, foreground, area.inflate(-2, -1), 8)
ellipse(surface, foreground, area.inflate(-1, -2), 8)
self.clear_frames()
self.add_frame(surface)
def update(self):
if self.parent.parent.is_going() and self.active:
Sprite.update(self)