pygamegsoc12 / alchemymadness / blocks.py

"""Mixing potion"""

import random
from itertools import izip, chain

import pygame

import resources
import layout
from sprite import MaskedSprite, Node

class Block(Node, MaskedSprite):
    """ A single block.

    color: block color (r, g, b)
    parent: Blocks instance
    """
    rect = layout.Main.block_rect
    speed = 1.0

    def __init__(self, color, parent, *groups):
        super(Block, self).__init__(color, *groups)
        self.parent = parent
        self.t_image = resources.block
        self.rect = self.rect.copy()
        self.position = [0, 0] # topleft corner of grid
        self._top = float(self.rect.top)
        self.frozen = False

    def move(self, d):
        """Move block horizontally in given direction

        d: positive - move right, negative - move left
        """
        self.rect.centerx += self.parent.parent.grid_size.w * d
        self.dirty = 1

    @property
    def position(self):
        grid = self.parent.parent
        return ((self.rect.left - grid.rect.left) / grid.block_size[0],
                (self.rect.top - grid.rect.top) / grid.block_size[1])

    @position.setter
    def position(self, value):
        grid = self.parent.parent
        self.rect.left = value[0] * grid.block_size[0] + grid.rect.left
        self.rect.top = value[1] * grid.block_size[1] + grid.rect.top
        self.top = float(self.rect.top)
        self.dirty = 1

    def update(self, time):
        if not self.frozen:
            self.top += self.speed * self.rect.h * time / 200.
            self.rect.top = self.top
            pos = self.position
            g_h = self.parent.parent.grid_size.h
            if (pos[0], pos[1]+1) in self.parent.parent.grid or pos[1] + 1 >= g_h:
                self.position = pos
                self.frozen = True
                self.parent.parent.grid[pos] = self
                self.parent.sprite_group.remove(self)
            self.dirty = 1


class SmallBlock(Block):
    """ A single small block.
    """
    rect = layout.Main.small_block_rect

    def __init__(self, color, parent, *groups):
        super(SmallBlock, self).__init__(color, parent, *groups)
        self.t_image = resources.sblock


class Blocks(Node):
    """ contains 3 Block() instances.
    """
    av_colors = [(255,0,0), (0,255,0), (0,0,255)] # available colors

    def __init__(self, parent):
        """ parent - a Grid instance.
        """
        super(Blocks, self).__init__()
        self.sprite_group = pygame.sprite.Group()
        self.parent = parent
        BlockC = Block if not self.parent.small else SmallBlock
        self.sprite_group.add([BlockC(random.choice(self.av_colors), self) for i in range(3)])
        # how do we handle location, and rotation? We say where the grid it is on.
        #     top, left is (0,0)
        self.grid_positions = [[0,0], [1,0], [2,0]]
        self.on_moved()

    def on_moved(self):
        """ called when we have moved.
        """
        i = 0
        for b, pos in izip(self.sprite_group, self.grid_positions):
            #print "on_moved {} {}".format(i, pos)
            b.position = pos
            i += 1

        #print "-" * 20

    def has_collided(self):
        """ checks if we have collided with some other blocks.
              See if the blocks of the same color are below.
        """
        # TODO: self.parent is the grid.
        raise NotImplementedError()

    def make_frozen(self):
        """ makes this a frozen block in the grid.
        """
        # TODO: self.parent is the grid.
        #    Probably create a new grid.blocks...
        #      The Block instances will stay where they are in the sprite_group.
        raise NotImplementedError()


    # action_* methods are inputs.

    def action_move_left(self):
        # if any of them are going out of bounds, we don't move.
        doit = True
        for b in self.grid_positions:
            b[0] -= 1
            if b[0] < 0:
                doit = False
        if not doit:
            # oops!  out of bounds, so reverse moves.
            for b in self.grid_positions:
                b[0] += 1

        self.on_moved()

    def action_move_right(self):
        doit = True
        for b in self.grid_positions:

            b[0] += 1
            if b[0] >= self.parent.grid_size.w:
                doit = False
        if not doit:
            for b in self.grid_positions:
                b[0] -= 1

        self.on_moved()


    def action_move_up(self):
        doit = True
        for b in self.grid_positions:
            b[1] -= 1
            if b[1] < 0:
                doit = False
        if not doit:
            for b in self.grid_positions:
                b[1] += 1

        self.on_moved()

    def action_move_down(self):
        doit = True
        for b in self.grid_positions:
            b[1] += 1
            if b[1] >= self.parent.grid_size.h:
                doit = False
        if not doit:
            for b in self.grid_positions:
                b[1] -= 1

        self.on_moved()

    def change_color(self, color):
        for b in self.sprite_group:
            b.mix_color(color, 1)


class Grid(Node):
    """ Contains Blocks()
    """
    grid_size = layout.Main.grid_size
    def __init__(self, grid_num):
        super(Grid, self).__init__()
        self._sprite_group = pygame.sprite.Group()
        self.grid_num = grid_num
        self.small = grid_num != 0
        self.rect = layout.Main.grid_rects[grid_num]
        self.block_size = (self.rect.w / self.grid_size.w, self.rect.h / self.grid_size.h)
        self.restart()

    @property
    def sprite_group(self):
        self._sprite_group = pygame.sprite.Group(list(chain(self.blocks.sprite_group, self.grid.itervalues())))
        return self._sprite_group

    def restart(self):
        """ restart this Grid instance.
        """
        self.grid = {} # grid in form of dict - position : Block
        self.blocks = Blocks(self) # currently moving block
        # TODO: what about frozen Blocks?
        # theory:
        # - when Blocks hits Block or grid frame, it pushes Block-s to grid
        # - Block-s continue to move until hitting other Block or grid frame

    def init_grid(self):
        """ init_grid initialises the Grid to be all clear.
        """
        # init our grid, to show the color of each grid part.
        #[[(0,0,0), ...],
        # ...
        #]
        self.grid = []
        for x in range(self.grid_size.h):
            self.grid.append([(0,0,0)] * self.grid_size.h)

        #import pprint
        #pprint.pprint(self.grid)


class Grids(object):
    """ This contains all the main Grid objects.
    """
    def __init__(self, sprite_group):
        """ sprite_group - which we add sprites to.
        """
        self.sprite_group = sprite_group
        self.grids = [Grid(x) for x in range(len(layout.Main.grid_rects))]

        for grd in self.grids:
            self.sprite_group.add(grd.sprite_group)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.