import os
delattr(os, "link")

from shaken_and_spit_out.pgfw.Setup import Setup

if __name__ == "__main__":
    Setup().setup()
from shaken_and_spit_out.pgfw.SetupWin import SetupWin

if __name__ == "__main__":
    SetupWin().setup()
from os import listdir
from glob import glob
from random import choice
from collections import deque

from pygame import cursors, PixelArray, Surface, Color
from pygame.mouse import set_cursor, get_pos
from pygame.font import Font
from pygame.image import load
from pygame.draw import polygon, aalines
from pygame.locals import *

from shaken_and_spit_out.pgfw.Game import Game
from shaken_and_spit_out.pgfw.GameChild import GameChild
from shaken_and_spit_out.pgfw.Sprite import Sprite
from shaken_and_spit_out.pgfw.Animation import Animation

class SSO(Game):

    def __init__(self):
        Game.__init__(self)
        set_cursor(*cursors.tri_left)
        # string = u"\u2250\u2254\u2258"
        # font = Font(self.get_resource("display", "font"), 24)
        # self.message = font.render(string, True, (0, 255, 0))
        self.backgrounds = [load(path).convert() for path in \
                            glob(self.get_resource("image", "background") + \
                                 "*.png")]
        self.used_backgrounds = []
        self.set_random_background()
        self.subscribe(self.respond)
        self.title.activate()

    def set_children(self):
        Game.set_children(self)
        self.floor = Floor(self)
        self.title = Title(self)
        self.cloud = Cloud(self)

    def set_random_background(self):
        index = choice(list(set(range(len(self.backgrounds))).\
                            difference(self.used_backgrounds)))
        self.used_backgrounds.append(index)
        if len(self.used_backgrounds) > 3:
            self.used_backgrounds.pop(0)
        self.background = self.backgrounds[index]

    def respond(self, event):
        if self.delegate.compare(event, "reset-game"):
            self.set_random_background()

    def update(self):
        self.get_screen().blit(self.background, (0, 0))
        self.cloud.update()
        self.title.update()
        self.floor.update()
        # self.get_screen().fill((0, 0, 0))
        # self.get_screen().blit(self.message, (100, 100))


class Title(GameChild):

    def __init__(self, parent):
        GameChild.__init__(self, parent)
        self.delegate = self.get_delegate()
        self.preface = Preface(self)
        self.preamble = Preamble(self)
        self.initializer = Initializer(self)
        self.subscribe(self.respond)
        self.subscribe(self.respond, MOUSEBUTTONDOWN)
        self.deactivate()

    def respond(self, event):
        if self.delegate.is_command(event) and \
               self.delegate.compare(event, "reset-game"):
            self.activate()

    def deactivate(self):
        self.active = True

    def activate(self):
        self.active = True
        self.preface.reset()
        self.preamble.reset()

    def update(self):
        if self.active:
            self.preface.update()
            self.preamble.update()
            self.initializer.update()


class Initializer(Sprite):

    def __init__(self, parent):
        Sprite.__init__(self, parent)
        self.load_from_path(self.get_resource("image", "initializer"),
                            query="[0-9]*.png", omit=True)
        self.add_frameset(0, name="idle")
        self.add_frameset(1, name="pressed")
        self.add_frameset((0, 2), (340, 40), "blinking")
        self.set_frameset("idle")
        self.location.center = 380, 500
        self.subscribe(self.respond, MOUSEBUTTONDOWN)
        self.subscribe(self.respond, MOUSEBUTTONUP)

    def respond(self, event):
        if self.parent.active:
            if event.type == MOUSEBUTTONDOWN and self.collides_mouse():
                self.set_frameset("pressed")
            elif event.type == MOUSEBUTTONUP:
                self.set_frameset("idle")

    def collides_mouse(self):
        return self.location.collidepoint(get_pos())

    def update(self):
        if self.parent.active:
            name = self.get_current_frameset().name
            if name == "idle" and self.collides_mouse():
                self.set_frameset("blinking")
            elif name == "blinking" and not self.collides_mouse():
                self.set_frameset("idle")
        Sprite.update(self)



class Preface(GameChild, Surface):

    def __init__(self, parent):
        GameChild.__init__(self, parent)
        ds = self.ds = self.get_display_surface()
        w, h = ds.get_width(), int(round(ds.get_width() / 3))
        Surface.__init__(self, (w, h), SRCALPHA)
        self.background = Surface((w, h))
        self.background.fill((0, 0, 0))
        mask = self.mask = Surface((w, h), SRCALPHA)
        pixels = PixelArray(mask)
        for y in xrange(h):
            alpha = int(round(255 - (float(y) / h) * 255))
            for x in xrange(w):
                pixels[x][y] = Color(255, 255, 255, alpha)
        del pixels
        self.set_text()
        self.reset()

    def set_text(self):
        lines = self.get_configuration("text", "preface",
                                       False).decode("unicode-escape").upper().\
                                       split("/")
        cc = 0
        for line in lines:
            if len(line) > cc:
                cc = len(line)
        cw = int(round((self.get_width() - 80) / float(cc)))
        font = Font(self.get_resource("display", "font"), 12)
        font.set_bold(True)
        ch = font.metrics(lines[0][0])[0][3]
        margin = 24
        surface = Surface((cw * cc,
                           ch * len(lines) + margin * (len(lines) - 1)),
                          SRCALPHA)
        text = self.text = Sprite(self, 200)
        text.display_surface = self
        magic_word = u"PS\u27A2;' P\u2591T"
        magic_colors = deque(((255, 128, 128), (255, 255, 128), (128, 255, 128),
                              (128, 255, 255), (128, 128, 255),
                              (255, 128, 255)))
        box_rect = Rect(0, 0, cw, ch)
        for _ in xrange(len(magic_word)):
            frame = surface.copy()
            box_rect.top = 0
            for line in lines:
                box_rect.left = 0
                extra = cc - len(line)
                space_count = 0
                for char in line:
                    if char == " ":
                        space_count += 1
                if space_count:
                    space_widths = [1 + extra / space_count] * space_count
                    for ii in xrange(len(space_widths)):
                        if ii >= (extra % space_count):
                            break
                        space_widths[ii] += 1
                magic_word_ii = 0
                for ii in xrange(len(line)):
                    if line != lines[-1] and line[ii] == " ":
                        box_rect.left += cw * space_widths.pop(-1)
                    else:
                        if (magic_word_ii and \
                            magic_word_ii < len(magic_word)) \
                               or line[ii:ii + len(magic_word)] == magic_word:
                            color = magic_colors[0]
                            magic_colors.rotate(-1)
                            magic_word_ii += 1
                        else:
                            color = (255, 255, 255)
                        left = font.render(line[ii], True, (255, 0, 0))
                        frame.blit(left, self.get_glyph_rect(left, box_rect, 0))
                        right = font.render(line[ii], True, (0, 0, 255))
                        frame.blit(right, self.get_glyph_rect(right, box_rect,
                                                              4))
                        glyph = font.render(line[ii], True, color)
                        frame.blit(glyph, self.get_glyph_rect(glyph, box_rect,
                                                              2))
                        box_rect.left += cw
                box_rect.top += ch + margin
            text.add_frame(frame)
            magic_colors.rotate(-1)
        text.location.centerx = self.get_width() / 2

    def get_glyph_rect(self, glyph, box_rect, offset):
        gr = glyph.get_rect()
        gr.center = box_rect.center
        gr.left += offset
        return gr

    def reset(self):
        self.text.location.top = self.get_height()

    def update(self):
        self.text.move(dy=-.5)
        if self.text.location.bottom < 0:
            self.reset()
        self.blit(self.background, (0, 0))
        self.text.update()
        self.blit(self.mask, (0, 0), None, BLEND_RGBA_MIN)
        self.ds.blit(self, (0, 0))


class Preamble(Animation):

    def __init__(self, parent):
        Animation.__init__(self, parent, self.increment_plate_index, 4000)
        plates = self.plates = []
        font = Font(self.get_resource("display", "font"), 12)
        font.set_bold(True)
        for line in self.get_configuration("text", "preamble",
                                           False).upper().split("/"):
            plates.append([])
            spaced = str(line[0])
            for character in line[1:]:
                spaced += " " + character
            for ii, color in enumerate(((0, 255, 255), (0, 255, 255),
                                        (255, 12, 64))):
                text = Sprite(self)
                text.add_frame(font.render(spaced, True, color))
                fr = self.get_game().floor.location
                text.location.midtop = fr.centerx + (-1, 1, 0)[ii], \
                                       fr.bottom + 10
                plates[-1].append(text)
        self.reset()
        self.play()

    def increment_plate_index(self):
        index = self.plate_index + 1
        if index >= len(self.plates):
            index = 0
        self.plate_index = index

    def reset(self):
        self.plate_index = 0

    def update(self):
        Animation.update(self)
        for text in self.plates[self.plate_index]:
            text.update()


class Arrow(Sprite):

    def __init__(self, parent):
        Sprite.__init__(self, parent, 360)
        w, h = 56, 39
        surface = Surface((w, h), SRCALPHA)
        for color in ((255, 255, 0, 200), (0, 255, 255, 200), (255, 0, 255, 200)):
            frame = surface.copy()
            for offset in (0, 5):
                points = [[int(round(val)) for val in coordinate] for
                          coordinate in self.get_coordinates(w - 10, h, offset)]
                if offset == 5:
                    color = Color(*color)
                    hue, s, l, a = color.hsla
                    color.hsla = (hue + 180) % 360, 50, 100, 100
                polygon(frame, color, points)
            self.add_frame(frame)
        floor = self.get_game().floor.location
        self.location.midbottom = int(floor.w * .75), floor.top - 8

    def get_coordinates(self, w, h, offset):
        return (w * .25 + offset, 0), (w * .75 + offset, 0), \
                   (w * .75 + offset, h * .62), (w - 1 + offset, h * .62), \
                   (w * .5 + offset, h - 1), (0 + offset, h * .62), \
                   (w * .25 + offset, h * .62)


class Floor(Sprite):

    transparent_color = 255, 0, 255

    def __init__(self, parent):
        Sprite.__init__(self, parent, (520, 80))
        base = load(self.get_resource("image", "brick")).convert()
        ds = self.ds = self.get_display_surface()
        surface = Surface((ds.get_width(), 17))
        surface.set_colorkey(self.transparent_color)
        for swap in False, True:
            frame = surface.copy()
            tile = base.copy()
            if swap:
                pixels = PixelArray(tile)
                foreground, background = pixels[1][1], pixels[0][0]
                for x in xrange(len(pixels)):
                    for y in xrange(len(pixels[0])):
                        if pixels[x][y] == foreground:
                            pixels[x][y] = background
                        else:
                            pixels[x][y] = foreground
                del pixels
            for x in xrange(0, frame.get_width(), tile.get_width()):
                for y in xrange(0, frame.get_height(), tile.get_height()):
                    frame.blit(tile, (x, y))
            self.add_frame(frame)
        self.location.bottom = self.ds.get_height() - 34
        hole = self.hole = Sprite(self)

    def explode(self, x):
        pass


class Cloud(GameChild):

    def __init__(self, parent):
        GameChild.__init__(self, parent)
        self.ds = self.get_display_surface()
        layers = self.layers = []
        base = load(self.get_resource("image", "cloud")).convert_alpha()
        for ii in xrange(3):
            layer = Sprite(self)
            frame = base.copy()
            pixels = PixelArray(frame)
            for x in xrange(len(pixels)):
                for y in xrange(len(pixels[0])):
                    color = Color(*base.unmap_rgb(pixels[x][y]))
                    h, s, l, a = color.hsla
                    color.hsla = int((h + (0, 90, 180)[ii]) % 360), int(s), \
                                 int(l), int(a * (.95 * (1 - ii * .15)))
                    pixels[x][y] = color
            del pixels
            layer.add_frame(frame)
            layer.move((0, -5, 5)[ii])
            layer.location.bottom = self.ds.get_height()
            layer.add_location(offset=(0, -layer.location.h))
            layers.append(layer)

    def update(self):
        fr = self.get_game().floor.location
        ds = self.ds
        ds.set_clip(fr.topleft, (ds.get_width(), ds.get_height() - fr.top))
        for ii, layer in enumerate(self.layers):
            layer.move(dy=1 + (ii * .5))
            if layer.location.top > ds.get_height():
                layer.move(dy=-layer.location.h)
            layer.update()
        ds.set_clip(None)
3.231.226.13
3.231.226.13
3.231.226.13
 
September 13, 2013

from array import array
from time import sleep

import pygame
from pygame.mixer import Sound, get_init, pre_init

class Note(Sound):

    def __init__(self, frequency, volume=.1):
        self.frequency = frequency
        Sound.__init__(self, self.build_samples())
        self.set_volume(volume)

    def build_samples(self):
        period = int(round(get_init()[0] / self.frequency))
        samples = array("h", [0] * period)
        amplitude = 2 ** (abs(get_init()[1]) - 1) - 1
        for time in xrange(period):
            if time < period / 2:
                samples[time] = amplitude
            else:
                samples[time] = -amplitude
        return samples

if __name__ == "__main__":
    pre_init(44100, -16, 1, 1024)
    pygame.init()
    Note(440).play(-1)
    sleep(5)

This program generates and plays a 440 Hz tone for 5 seconds. It can be extended to generate the spectrum of notes with a frequency table or the frequency formula. Because the rewards in Send are idealized ocean waves, they can also be represented as tones. Each level has a tone in its goal and a tone based on where the player's disc lands. Both play at the end of a level, sounding harmonic for a close shot and discordant for a near miss. The game can dynamically create these tones using the program as a basis.

I'm also building an algorithmically generated song: Silk Routes (Scissored). Here is an example of how it sounds so far: