Source

pygamegsoc12 / alchemymadness / blocks.py

Full commit
"""Mixing potion"""

import random
from itertools import izip, chain

import pygame

import resources
import layout
from sprite import MaskedSprite

class Block(MaskedSprite):
    """ A single block.
    """
    rect = layout.Main.block_rect

    def __init__(self, color, *groups):
        super(Block, self).__init__(color, *groups)
        self.t_image = resources.block

    def grid_pos(self, pos, grid_rect):
        """ set the rect for the given (x,y) grid pos
        """
        ox, oy, w, h = self.rect

        gx, gy = pos
        x, y = gx * w, gy * h
        x += grid_rect[0]
        y += grid_rect[1]
        self.rect = pygame.Rect(x, y, w, h)
        #print self.rect
        #self.changed = True
        self.dirty = 1


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

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


class Blocks(object):
    """ 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)) 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.grid_pos(pos, self.parent.rect)
            i += 1

        #print "-" * 20

    def update(self, time):
        pass

    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(object):
    """ 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.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)