コード例 #1
0
ファイル: game.py プロジェクト: sman865/falling-block-game
def newShadow(piece):
    global shadow_piece

    shadow = Piece(clock, piece=piece)
    shadow_sprites.add(shadow.getSprites())
    shadowMove(shadow, hard_drop_key)
    shadow_piece = shadow
コード例 #2
0
ファイル: game.py プロジェクト: sman865/falling-block-game
def main():
    global falling_piece
    global shadow_piece
    global falling_sprites

    running = True

    new_piece_pending         = False
    new_piece_pending_elapsed = 0 # ms

    #
    # Text displays
    #
    level      = Level.startLevel()
    level_surf = None

    total_elapsed = 0
    zero_time     = datetime.timedelta(seconds=0)
    time_surf  = None

    points     = 0
    point_surf = None

    if display_level:
        lines = Level.lines(level)
    else:
        lines = start_lines # from Settings
    lines_surf = None

    if display_level:
        level_surf = createText(level_x, level_y, 'Level: ')
        updateText(level_surf, level)
    if display_time:
        time_surf = createText(time_x, time_y)
        updateText(time_surf, timeObj(time_limit, 0)[1])
    if display_points:
        point_surf = createText(points_x, points_y, 'Points: ')
        updateText(point_surf, points)
    if display_lines:
        lines_surf = createText(lines_x, lines_y, 'Remaining: ')
        updateText(lines_surf, lines)

    #
    # Delayed auto shift variables:
    #
    last_movement = 0 # tracks when last manual movement was
    das_triggered = False # tracks if DAS has been triggered

    #
    # The goal for hard drops is the piece to hit the bottom as fast as
    # possible. We want the user to be able to hold the hard drop button down
    # to continuously drop pieces too. BUT there needs to be a delay otherwise
    # they'll be forced to press the button for only one frame, otherwise
    # there's a good chance 2+ pieces will drop since we're running at 60 fps.
    #
    # SO, this is a delay that extends into the next piece.
    #
    hard_drop_repeat_wait         = 0
    hard_drop_repeat_wait_elapsed = 0

    #
    # Initialize invisible pieces that occupy the well. well_rows and
    # well_sheets are lists of sprite groups with one entry per row.
    #
    # well_rows: In order to detect when a row is complete we need 10 (width)
    #            surfaces per row to check when all of them are colliding with
    #            pieces on the screen.
    #
    # well_sheets: In order to move pieces down when a row is completed we
    #              need to be able to determine which blocks are *above* the
    #              row that is completed. Therefore these surfaces will stretch
    #              the width of the well and get longer and longer the farther
    #              down they are (stretching upward). These could be avoided
    #              if surfaces gave info about their position on the screen?
    #
    for y in range(0, well_length):
        # Initialize the sprites for each column
        for x in range(0, well_width):
            curr = Piece(clock, x_coord=x, y_coord=y).getSprites()
            well.add(curr)
            well_rows[y].add(curr)

        # Initialize the sheet.
        well_sheets.append(Sheet(y, well_width))

    # Initialize invisible pieces that line the outside of the well. In order:
    # top, right, bottom, left.
    border_coords  = [(x,-1)          for x in range(-1, well_width)]
    border_coords += [(well_width,y)  for y in range(-1, well_length)]
    border_coords += [(x,well_length) for x in range(well_width,  -1, -1)]
    border_coords += [(-1,y)          for y in range(well_length, -1, -1)]
    for (x,y) in border_coords:
        curr = Piece(clock, x_coord=x, y_coord=y)
        sprites = curr.getSprites()
        border.add(sprites)
        if not (y < 0 and x >= 0 and x < well_width):
            border_U.add(sprites) # shaped like a U
        if x < 0:
            border_l.add(sprites)
        if x == well_width:
            border_r.add(sprites)

    # Set up first piece
    all_drawable.add([piece.getSprites() for piece in manager.getPieces()])
    gravity = Level.gravity(level) # starts at 1 second per drop
    falling_piece = newPiece(gravity)

    saved_piece = None

    last_line_animation = lines

    # Draw countdown
    for i in range(countdown_secs, 0, -1):
        animations.append(Animation(i, clock, screen))
        while animations:
            clock.tick(fps)
            updateScreen()

    # Flush input buffer - applicable if countdown happened
    pygame.event.get()

    #
    # MAIN LOOP
    #
    while running:

        clock.tick(fps)
        total_elapsed += clock.get_time()

        if display_time:
            if time_counts_up:
                time_obj, time_string = timeObj(0, total_elapsed)
            else:
                time_obj, time_string = timeObj(time_limit, -total_elapsed)
            updateText(time_surf, time_string)
            if time_obj <= zero_time:
                updateText(time_surf, zero_time)
                print(points)
                gameOver()

        last_movement += clock.get_time()

        reverted_downward_move = False

        # See explanation in Settings.py, under MISC.
        if level_enabled:
            new_piece_pending_period = Level.nppp(level)
        else:
            new_piece_pending_period = hard_drop_wait

        if new_piece_pending:
            new_piece_pending_elapsed += clock.get_time()

        if hard_drop_repeat_wait:
            hard_drop_repeat_wait_elapsed += clock.get_time()
            if hard_drop_repeat_wait_elapsed > 200:
                hard_drop_repeat_wait = False

        #######################################################################
        #                            KEY PRESSES                              #
        #######################################################################

        events = pygame.event.get()

        # Artificially add an arrow key to the events queue. Without this code,
        # holding a key down does nothing.
        if not events:
            keys = pygame.key.get_pressed()
            for key in hard_drop_key, left_key, right_key:
                if keys[key]:
                    if last_movement > 150 or das_triggered:
                        das_triggered = True
                        events.append(pygame.event.Event(KEYDOWN, {'key': key}))

        for event in events:
            if event.type == KEYDOWN:

                key = event.key

                # Quit
                if key in quit_keys:
                    running = False

                # Store piece and restart loop.
                elif key == hold_key:
                    falling_piece, saved_piece = hold(falling_piece,
                                                      saved_piece, gravity)

                    # NOTE: not sure if these are necessary but they could save
                    # the game from a few bugs.
                    new_piece_pending = False
                    das_triggered = False
                    last_movement = 0

                    updateScreen()
                    continue

                # Code related to user moving or rotating piece
                else:
                    last_movement = 0

                    # Code for downward movement - does not affect shadow.
                    if key in down_keys:
                        if key in hard_drop_keys:
                            if hard_drop_repeat_wait:
                                continue
                            lines_down = well_length
                        else:
                            lines_down = 1

                        successful_drops = 0
                        for i in range(lines_down):
                            falling_piece.move(hard_drop_key)
                            if needToRevert(falling_piece):
                                falling_piece.move(cheat_key)

                                # Override normal detection
                                if key in hard_drop_no_wait_keys:
                                    new_piece_pending = True
                                    new_piece_pending_period = 0
                                    hard_drop_repeat_wait = True
                                    hard_drop_repeat_wait_elapsed = 0
                                break
                            successful_drops += 1

                        if display_points:
                            points += Scoring.drop_points(successful_drops)
                            updateText(point_surf, points)

                    # Other movement
                    else:
                        # Let player move piece even around the bottom
                        #new_piece_pending = False

                        falling_piece.dispatch(key)
                        shadow_moved = shadowMove(shadow_piece, key)

                        # Try wall/floor kicks if a rotation was illegal.
                        if needToRevert(falling_piece) and key in rotate_keys:
                            kick(falling_piece)

                        # Revert movement if it was illegal and can't be done.
                        # shadowMove usually takes care of reverting itself but
                        # since the dection is different we need to double
                        # check here.
                        if needToRevert(falling_piece):
                            falling_piece.dispatch(opposite[key])
                            if shadow_moved:
                                shadow_moved = shadowMove(shadow_piece,
                                                          opposite[key])
                                if not shadow_moved:
                                    print('no revert = bad?')

                        # If we just moved the piece left/right and it's now
                        # over a gap, reset the new piece pending variables.
                        #if key in left_right_keys:
                        if True:
                            falling_piece.move(hard_drop_key)
                            if not needToRevert(falling_piece):
                                new_piece_pending = False
                            falling_piece.move(cheat_key)

            elif event.type == KEYUP:
                das_triggered = False
                if event.key in hard_drop_keys:
                    hard_drop_repeat_wait = False

            elif event.type == QUIT:
                running = False

        #######################################################################
        #                           PIECE MOVEMENT                            #
        #######################################################################

        # Auto movement
        if not new_piece_pending and falling_piece.handleGravity(needToRevert):
            #reverted_downward_move = checkDownwardRevert(falling_piece)
            reverted_downward_move = True


        # If the shadow and the falling piece overlap completely, we're at the
        # bottom so let's just kill off the shadow. This is really just because
        # shadow movement is buggy and this avoids some corner cases.
        if len(groupcollide(falling_sprites, shadow_sprites)) >= \
           len(falling_piece.getSprites()):
            resetShadow()


        # The piece can't move down farther if it just collided with another
        # piece or is currently colliding with the bottom row of invisible
        # blocks.
        if not new_piece_pending and (
            reverted_downward_move or
            groupcollide(falling_sprites, well_rows[-1])
        ):
            new_piece_pending         = True
            new_piece_pending_elapsed = 0

        # Piece is locked in. Check for row completion and eventually spawn a
        # new piece.
        if new_piece_pending and \
           new_piece_pending_elapsed >= new_piece_pending_period:

            new_piece_pending = False

            # Transfer falling_sprites to piece_sprites and reset variables
            # related to the falling piece.
            piece_sprites.add(falling_sprites)
            falling_sprites = pygame.sprite.Group()
            resetShadow()

            # Check all rows for completion.
            rows_completed = 0
            for i, row_sprites in enumerate(well_rows):
                sheet = well_sheets[i] # idx 0 will be None

                # 'collisions' will be a dict of Block objects that are in
                # 'piece_sprites'.
                collisions = groupcollide(piece_sprites, row_sprites)

                # Completed row!
                if len(collisions) == well_width:
                    rows_completed += 1

                    # Delete the row
                    for block in collisions:
                        for piece in pieces:
                            if block in piece.getSprites():
                                piece.remove(block)

                        # We don't need to keep empty Piece objects around.
                        if not piece.getSprites():
                            pieces.remove(piece)

                    # Move other pieces down.
                    for piece in pieces:
                        piece.downIfCollide(sheet)

            # Check for new level or game over, depending on the mode.
            if display_lines:
                lines -= rows_completed
                updateText(lines_surf, lines)

                if lines <= 0:
                    # New level
                    if level_enabled:
                        level += 1
                        lines, new_piece_pending_period, gravity = \
                                                    Level.updateLevel(level)
                        updateText(level_surf, level)
                        updateText(lines_surf, lines)
                    # User cleared all the lines
                    else:
                        updateText(lines_surf, 0)
                        print(timeObj(0, total_elapsed)[1])
                        gameOver()

            # Handle animations
            if display_lines and not level_enabled:
                if lines <= 10 and lines != last_line_animation:
                    last_line_animation = lines
                    animations.append(Animation(lines, clock, screen))

            if display_points:
                points += Scoring.line_points(rows_completed)
                updateText(point_surf, points)

            falling_piece = newPiece(gravity)

        updateScreen()