ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [python] 파이썬으로 테트리스 게임
    카테고리 없음 2022. 1. 19. 16:49

    나의 첫 티스토리는 내가 현재 만들고 있는 테트리스 게임을 소개할 것이다. 

     

    테트리스 게임은 대중적인 게임이고, 룰도 매우 간단하다. 그래서 나는 이 게임을 파이썬으로 구현해보고자 여러 자료들을 찾아보며 pygame 모듈을 사용한 게임을 만드는 방법을 공부하였다. 

     

    하지만 게임을 만들다 보니 룰은 간단하다고 생각했던 테트리스가 생각보다 복잡한 처리 과정이 필요하고, 버그는 어떤식으로 수정해야 할 지 막막하기만 했었다. 그래도 단순한 재미만으로 계속하여 생각해보고 고민해봤다. 결국, 게임을 실행할 수 있게 되었다. 아직 버그는 많이 존재하고, 완성된 것은 아니다.

     

    내가 만든 코드는 다음과 같다. 살짝 봐도 효율따위는 신경쓰지 않고 단지 열정만을 보이는 매우 긴 코드를 볼 수 있다. 초보 티를 팍팍 낸다...ㅎㅎ 대략 800줄.... 더 열심히 코딩을 공부하여 효율 및 처리속도 등을 따질 수 있는 날이 오도록 노력해야겠다!

    코드

    import pygame
    import random
    
    def block_mod_set(): 
        global block_blank_size, block_fill
    
        if block_mode == 1:
            block_blank_size = 1
            block_fill = 0
    
        elif block_mode == 2:
            block_blank_size = 1
            block_fill = 2
    
        elif block_mode == 3:
            block_blank_size = int(block_size * 1 / 2)
            block_fill = 0
    
        elif block_mode == 4:
            block_blank_size = 0
            block_fill = int(block_size * 1 / 3)
    
    def draw_screen():
        global rows, columns, grid
    
        screen.fill((0, 0, 0))
    
        for row in range(rows):
            for col in range(columns):
                draw_game(grid[row][col], (row, col))
    
        draw_next()
        draw_hold()
        draw_score()
        draw_block_mode()
        draw_combo_text()
        draw_block()
    
    def draw_game(color_idx, pos):
        global block_size, block_blank_size, block_fill
    
        x_pos = pos[0] * block_size + block_size * 2
        y_pos = pos[1] * block_size + block_size * 2
    
        block = pygame.Rect(0, 0, block_size - block_blank_size, block_size - block_blank_size)
        block.center = (y_pos, x_pos)
    
        pygame.draw.rect(screen, color[color_idx], block, block_fill)
    
    def draw_next():
        global block_size, blocks_data, next_block, block_fill
    
        x_size = block_size * 5
        y_size = block_size * 10
        pygame.draw.rect(screen, (255, 255, 255), (21 * block_size, 22 * block_size - y_size, x_size, y_size), 2)
    
        size = block_size / 4 * 3
    
        for y in range(6):
            num = int(y / 2)
            k = y % 2
            idx = next_block[num]
    
            x_start = 23.5 * block_size - (len(blocks_data[idx - 1][0][0]) / 2) * size
            y_start = 12 * block_size + (num + 1) * block_size + (num + 0.5) * size
    
            if idx == 1 and k == 1:
                k = 0
            elif idx == 1 and k == 0:
                y += 1
    
            for x in range(len(blocks_data[idx - 1][0][k])):
                if blocks_data[idx - 1][0][k][x] == 1:
                    block = pygame.Rect(x_start + x * size, y_start + y * size, size - block_blank_size * 3 / 4, size - block_blank_size * 3 / 4)
                    pygame.draw.rect(screen, color[idx], block, block_fill)
    
        text = small_font.render("Next Blocks", True, color[next_block[0]])
        screen.blit(text, (21.15 * block_size, 11 * block_size))
    
    def hold_block():
        global hold, grid, curr_block_idx, hold_check, blocks_data, hold_now_turn_check
    
        if not hold_now_turn_check: # 이번 턴에 홀드 하지 않았더라면 홀드 가능
            if hold == 0:  # 홀드 한 것이 없다면
                hold_block_idx = curr_block_idx
                hold_check = False
    
            else:  # 있다면
                hold_block_idx = curr_block_idx
                hold_check = True
    
            block_data = blocks_data[curr_block_idx - 1]
            last_block = block_data[last_block_shape_idx]
            last_block_size_x = len(last_block[0])
            last_block_size_y = len(last_block)
    
            if last_block_x_pos > -1:
                for x in range(last_block_size_x):
                    for y in range(last_block_size_y):
                        if last_block[y][x] == 1:
                            grid[y + last_block_y_pos][x + last_block_x_pos] = 0
    
            block_pos_produce()
            hold = hold_block_idx
    
            hold_now_turn_check = True
    
    def draw_hold():
        global hold, blocks_data, block_size
    
        size = block_size / 4 * 3
    
        x_size = block_size * 5
        y_size = block_size * 4
        pygame.draw.rect(screen, (255, 255, 255), (15 * block_size, 12 * block_size, x_size, y_size), 2)
    
        for y in range(2):
            k = y
    
            x_start = 17.5 * block_size - (len(blocks_data[hold - 1][0][0]) / 2) * size
            y_start = 13 * block_size + 0.5 * size
    
            if hold == 1 and k == 1:
                k = 0
            elif hold == 1 and k == 0:
                y += 1
    
            for x in range(len(blocks_data[hold - 1][0][k])):
                if blocks_data[hold - 1][0][k][x] == 1:
                    block = pygame.Rect(x_start + x * size, y_start + y * size, size - block_blank_size * 3 / 4, size - block_blank_size * 3 / 4)
                    pygame.draw.rect(screen, color[hold], block, block_fill)
    
        if hold == 0:
            color_rbg = [255, 255, 255]
        else:
            color_rbg = color[hold]
    
        text = small_font.render("Hold Block", True, color_rbg)
        screen.blit(text, (15.35 * block_size, 11 * block_size))
    
    def draw_score():
        global score, score_title_font, score_font, block_size, color_idx, color
    
        x_size = block_size * 11
        y_size = block_size * 5
        pygame.draw.rect(screen, (255, 255, 255), (15 * block_size, 5 * block_size, x_size, y_size), 2)
    
        if color_idx >= 7:
            color_idx = 1
        else:
            color_idx += 0.001
    
        text = score_title_font.render("S C O R E", True, color[curr_block_idx])
        screen.blit(text, (16.6 * block_size, 2.7 * block_size))
    
        score_text = score_font.render(str(score).zfill(7), True, color[int(color_idx)])
        score_text_rect = score_text.get_rect(center=(20.5 * block_size, 7.8 * block_size))
        screen.blit(score_text, score_text_rect)
    
    def draw_block_mode():
        global mode_1, mode_2, mode_3, mode_4, block_mode
    
        button_size = int(block_size * 3 / 2)
    
        x_size = block_size * 5
        y_size = block_size * 4.5
        pygame.draw.rect(screen, (255, 255, 255), (15 * block_size, 17.5 * block_size, x_size, y_size), 2)
    
        text = small_font.render("Block Mode", True, (255, 255, 255))
        screen.blit(text, (15.15 * block_size, 16.4 * block_size))
    
        mode_1 = pygame.Rect(block_size * 15.1 + button_size * 0.4, block_size * 17.1 + button_size * 0.6, button_size, button_size)
        mode_2 = pygame.Rect(block_size * 17.9, block_size * 17.1 + button_size * 0.6, button_size, button_size)
        mode_3 = pygame.Rect(block_size * 15.1 + button_size * 0.4, block_size * 20, button_size, button_size)
        mode_4 = pygame.Rect(block_size * 17.9, block_size * 20, button_size, button_size)
    
        pygame.draw.rect(screen, (0, 0, 0), mode_1)
        pygame.draw.rect(screen, (0, 0, 0), mode_2)
        pygame.draw.rect(screen, (0, 0, 0), mode_3)
        pygame.draw.rect(screen, (0, 0, 0), mode_4)
    
        mode_1_color = [100, 100, 100]
        mode_2_color = [100, 100, 100]
        mode_3_color = [100, 100, 100]
        mode_4_color = [100, 100, 100]
    
        if block_mode == 1:
            mode_1_color = color[8]
        elif block_mode == 2:
            mode_2_color = color[8]
        elif block_mode == 3:
            mode_3_color = color[8]
        elif block_mode == 4:
            mode_4_color = color[8]
    
        block = pygame.Rect(block_size * 15.1 + 1 + button_size * 0.4, block_size * 17.1 + 1 + button_size * 0.6, button_size - 2, button_size - 2)
        pygame.draw.rect(screen, mode_1_color, block, 0)
    
        block = pygame.Rect(block_size * 17.9 + 1, block_size * 17.1 + 1 + button_size * 0.6, button_size - 2, button_size - 2)
        pygame.draw.rect(screen, mode_2_color, block, 4)
    
        block = pygame.Rect(block_size * 15.1 + int(button_size * 1 / 2) / 2 + button_size * 0.4, block_size * 20 + int(button_size * 1 / 2) / 2, button_size - int(button_size * 1 / 2), button_size - int(button_size * 1 / 2))
        pygame.draw.rect(screen, mode_3_color, block, 0)
    
        block = pygame.Rect(block_size * 17.9, block_size * 20, button_size, button_size)
        pygame.draw.rect(screen, mode_4_color, block, int(button_size * 1 / 3))
    
    def block_pos_produce():
        global curr_block_idx, next_block, block_count, fall_turn, max_fall_turn, curr_block_idx, blocks_data, block_x_pos, block_y_pos, produce_ticks, curr_block_x_size, curr_block_y_size, curr_block_shape_idx, last_block_shape_idx, last_block_x_pos, last_block_y_pos, hold_check, hold, hold_now_turn_check
    
        if hold_check:
            curr_block_idx = hold
            hold_check = False
        else:
            curr_block_idx = next_block[0]
    
            for i in range(len(next_block) - 1):
                next_block[i] = next_block[i + 1]
            next_block[2] = random.randint(1, 7)
    
            hold_now_turn_check = False
    
        fall_turn = max((0.5 - 1.2) / 100 * block_count + 1.2, (max_fall_turn - 0.5) / (300 - 100) * (block_count - 100) + 0.5, max_fall_turn)
    
        curr_block_shape_idx = 0
        last_block_shape_idx = 0
    
        block_data = blocks_data[curr_block_idx - 1]
        curr_block = block_data[curr_block_shape_idx]
        curr_block_x_size = len(curr_block[0])
        curr_block_y_size = len(curr_block)
    
        block_x_pos = 5 + int(2.5 - curr_block_x_size)
        block_y_pos = 0
    
        last_block_x_pos = -1
        last_block_y_pos = -1
    
        produce_ticks = pygame.time.get_ticks()
    
    def block_falling():
        global produce_ticks, now_ticks, fall_turn, block_y_pos, can_under, straight
    
        now_ticks = pygame.time.get_ticks()
    
        if straight:
            falling_finish()
            straight = False
    
        if (now_ticks - produce_ticks) / 1000 > fall_turn:
            produce_ticks = now_ticks
            now_ticks = pygame.time.get_ticks()
            if can_under:
                block_y_pos += 1
                can_under = False
            else:
                falling_finish()
    
    def falling_finish():
        global curr_block_idx, block_y_pos, running, block_count, block_score, score
    
        block_clear_check()
    
        block_count += 1
    
        if block_y_pos <= 0:
            cause_motion()
            running = False
        else:
            block_pos_produce()
    
        score += block_score
    
    def draw_block():
        global curr_block_idx, curr_block_shape_idx, block_x_pos, block_y_pos, last_block_x_pos, last_block_y_pos, last_block_shape_idx, curr_block_x_size, curr_block_y_size, last_block_x_size, last_block_y_size
    
        block_data = blocks_data[curr_block_idx - 1]
    
        curr_block = block_data[curr_block_shape_idx]
        curr_block_x_size = len(curr_block[0])
        curr_block_y_size = len(curr_block)
    
        last_block = block_data[last_block_shape_idx]
        last_block_size_x = len(last_block[0])
        last_block_size_y = len(last_block)
    
        if last_block_x_pos > -1:
            for x in range(last_block_size_x):
                for y in range(last_block_size_y):
                    if last_block[y][x] == 1:
                        grid[y + last_block_y_pos][x + last_block_x_pos] = 0
    
        for x in range(curr_block_x_size):
            for y in range(curr_block_y_size):
                if curr_block[y][x] == 1:
                    grid[y + block_y_pos][x + block_x_pos] = curr_block_idx
    
        last_block_x_pos = block_x_pos
        last_block_y_pos = block_y_pos
        last_block_shape_idx = curr_block_shape_idx
    
    def block_right():
        global block_x_pos, can_right
    
        if can_right:
            block_x_pos += 1
    
    def block_left():
        global block_x_pos, can_left
    
        if can_left:
            block_x_pos -= 1
    
    def block_up():
        global block_y_pos
    
        block_y_pos -= 1
    
    def block_rotate():
        global curr_block_shape_idx, blocks_data, block_x_pos, curr_block_x_size, curr_block_y_size, block_y_pos, can_under_size, can_up_size, can_right_size, can_left_size, can_rotate
    
        block_data = blocks_data[curr_block_idx - 1]
    
        can_horizontal_size = min(can_right_size) + min(can_left_size) + curr_block_x_size
        can_vertical_size = min(can_under_size) + min(can_up_size) + curr_block_y_size
    
        can_rotate = True
    
        if can_horizontal_size >= curr_block_y_size:  # 회전 가능
            if (min(can_up_size) == 100) and (min(can_under_size) + curr_block_y_size + block_y_pos > curr_block_x_size): # 회전 가능
                can_rotate = True
            else:
                if can_vertical_size >= curr_block_x_size and (min(can_under_size) + curr_block_y_size + block_y_pos > curr_block_x_size):  # 회전 가능
                    can_rotate = True
                else:
                    can_rotate = False
        else:  # 회전 불가능
            can_rotate = False
    
        if can_rotate:
            if min(can_right_size) < curr_block_y_size:
                for i in range(curr_block_y_size - (curr_block_x_size + min(can_right_size))):
                    block_left()
    
            if min(can_under_size) < curr_block_x_size:
                for i in range(curr_block_x_size - (curr_block_y_size + min(can_under_size))):
                    block_up()
    
            if (curr_block_idx == 4) and (curr_block_shape_idx == 0):
                if can_under_size[0] == 0:
                    if can_up_size[1] == 1:
                        curr_block_shape_idx -= 1
                    else:
                        block_up()
    
            if (curr_block_idx == 5) and (curr_block_shape_idx == 2):
                if can_under_size[1] == 0:
                    block_up()
    
            if (curr_block_idx == 6) and (curr_block_shape_idx == 2):
                if (can_under_size[0] == 0) or (can_under_size[1] == 0):
                    block_up()
    
            if (curr_block_idx == 6) and (curr_block_shape_idx == 1):
                if can_under_size[1] == 0:
                    block_up()
    
            if curr_block_shape_idx < len(block_data) - 1:
                curr_block_shape_idx += 1
            else:
                curr_block_shape_idx = 0
    
    def block_down():
        global block_y_pos, can_under
    
        if can_under:
            block_y_pos += 1
            can_under = False
    
    def block_can_right_check():
        global block_x_pos, block_y_pos, can_right, blocks_data, curr_block_idx, curr_block_shape_idx, curr_block_x_size, curr_block_y_size, grid, can_right_size
    
        can_right = False
        can_right_size = []
    
        block_data = blocks_data[curr_block_idx - 1]
        curr_block = block_data[curr_block_shape_idx]
        block_margin_x = curr_block_x_size - 1
    
        curr_block_x_size = len(curr_block[0])
        curr_block_y_size = len(curr_block)
    
        for y in range(curr_block_y_size):
            for x in range(curr_block_x_size - 1, -1, -1):
                if curr_block[y][x] == 1:
                    block_margin_x = x
                    break
    
            for x in range(block_x_pos + block_margin_x + 1, 12, 1):
                if grid[y + block_y_pos][x] > 0:
                    can_right_size.append(x - (block_x_pos + block_margin_x) - 1)
                    break
    
        if min(can_right_size) == 0:
            can_right = False
        else:
            can_right = True
    
    def block_can_left_check():
        global block_x_pos, block_y_pos, can_left, blocks_data, curr_block_idx, curr_block_shape_idx, curr_block_x_size, curr_block_y_size, grid, can_left_size
    
        can_left = False
        can_left_size = []
    
        block_data = blocks_data[curr_block_idx - 1]
        curr_block = block_data[curr_block_shape_idx]
        block_margin_x = 0
    
        curr_block_x_size = len(curr_block[0])
        curr_block_y_size = len(curr_block)
    
        for y in range(curr_block_y_size):
            for x in range(curr_block_x_size):
                if curr_block[y][x] == 1:
                    block_margin_x = x
                    break
    
            for x in range(block_x_pos + block_margin_x - 1, -1, -1):
                if grid[y + block_y_pos][x] > 0:
                    can_left_size.append((block_x_pos + block_margin_x) - x - 1)
                    break
    
        if min(can_left_size) == 0:
            can_left = False
        else:
            can_left = True
    
    def block_can_under_check(): #한 칸 아래로 내려갈 수 있는지 확인
        global block_x_pos, block_y_pos, can_under, blocks_data, curr_block_idx, curr_block_shape_idx, curr_block_x_size, curr_block_y_size, grid, can_under_size
    
        can_under = False
        can_under_size = []
    
        block_data = blocks_data[curr_block_idx - 1]
        curr_block = block_data[curr_block_shape_idx]
        block_bottom_y = curr_block_y_size - 1
    
        curr_block_x_size = len(curr_block[0])
        curr_block_y_size = len(curr_block)
    
        for x in range(curr_block_x_size):
            for y in range(curr_block_y_size - 1, -1, -1):
                if curr_block[y][x] == 1:
                    block_bottom_y = y
                    break
    
            for y in range(block_y_pos + block_bottom_y + 1, 21, 1):
                if grid[y][x + block_x_pos] > 0:
                    can_under_size.append(y - (block_y_pos + block_bottom_y) - 1)
                    break
    
        if min(can_under_size) == 0:
            can_under = False
        else:
            can_under = True
    
    def block_can_up_check():
        global block_x_pos, block_y_pos, blocks_data, curr_block_idx, curr_block_shape_idx, curr_block_x_size, curr_block_y_size, grid, can_up_size
    
        can_up_size = []
    
        block_data = blocks_data[curr_block_idx - 1]
        curr_block = block_data[curr_block_shape_idx]
        block_top_y = 0
    
        curr_block_x_size = len(curr_block[0])
        curr_block_y_size = len(curr_block)
    
        for x in range(curr_block_x_size):
            for y in range(curr_block_y_size):
                if curr_block[y][x] == 1:
                    block_top_y = y
                    break
    
            for y in range(block_y_pos + block_top_y - 1, -1, -1):
                if grid[y][x + block_x_pos] > 0:
                    can_up_size.append((block_y_pos + block_top_y) - y - 1)
                    break
    
                if y == 0:
                    can_up_size.append(100)
    
            if block_y_pos + block_top_y == 0:
                can_up_size.append(100)
    
    def block_straight():
        global can_under_size, block_y_pos, straight, straight_score, score
    
        block_y_pos += min(can_under_size)
        straight = True
    
        score += straight_score * min(can_under_size)
    
    def block_clear_check():
        global grid, columns, rows, clear_score, score, clear_combo, draw_combo, clear_row_y_pos
    
        now_clear_rows = 0
    
        for row in range(0, rows - 1, 1):
            check = 1
            for col in range(columns):
                check *= grid[row][col]
    
            if check > 0:
                clear(row)
                clear_row_y_pos = row * block_size + block_size * 2
                now_clear_rows += 1
    
        if not now_clear_rows == 0:
            clear_combo += 1
            draw_combo = 1
        else:
            clear_combo = 0
            draw_combo = 0
    
        score += clear_score * ((now_clear_rows) ** 2) * int(clear_combo ** (3 / 2))
    
    def draw_combo_text():
        global combo_ticks, now_ticks, draw_combo
    
        now_ticks = pygame.time.get_ticks()
    
        if clear_combo >= 2:
            if draw_combo == 1:
                if combo_ticks == None:
                    combo_ticks = pygame.time.get_ticks()
    
                elif now_ticks - combo_ticks <= 1000:
                    combo_text = combo_font.render("Combo X " + str(clear_combo), True, (255, 255, 255))
                    combo_text_rect = combo_text.get_rect(center=(20.5 * block_size, 6.1 * block_size))
    
                    screen.blit(combo_text, combo_text_rect)
    
                else:
                    combo_ticks = None
                    draw_combo = 0
    
    def clear(clear_row):
        global grid, columns, rows
    
        list1 = [8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]
        list2 = [i for i in grid[clear_row]]
    
        for i in range(6):
            if i % 2 == 0:
                grid[clear_row] = list1
            else:
                grid[clear_row] = list2
    
            for row in range(rows):
                for col in range(columns):
                    draw_game(grid[row][col], (row, col))
            pygame.display.update()
    
            pygame.time.delay(100)
    
        for row in range(clear_row, 0, -1):
            grid[row] = grid[row - 1]
    
        grid[0] = [8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]
    
    def cause_motion():
        global grid
    
        list1 = [8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8]
        list2 = [i for i in grid[0]]
    
        for i in range(8):
            if i % 2 == 0:
                grid[0] = list1
            else:
                grid[0] = list2
    
            for row in range(rows):
                for col in range(columns):
                    draw_game(grid[row][col], (row, col))
            pygame.display.update()
    
            pygame.time.delay(100)
    
    def game_over():
        for y in range(21):
            for x in range(12):
                x_pos = x * block_size + block_size * 2
                y_pos = y * block_size + block_size * 2
    
                block = pygame.Rect(0, 0, block_size - block_blank_size, block_size - block_blank_size)
                block.center = (x_pos, y_pos)
    
                pygame.draw.rect(screen, color[8], block, block_fill)
    
            pygame.display.update()
    
            pygame.time.delay(100)
    
    def check_buttons(pos):
        global mode_1, mode_2, mode_3, mode_4, block_mode
    
        if mode_1.collidepoint(pos):
            block_mode = 1
        elif mode_2.collidepoint(pos):
            block_mode = 2
        elif mode_3.collidepoint(pos):
            block_mode = 3
        elif mode_4.collidepoint(pos):
            block_mode = 4
    
    pygame.init()
    
    block_size = 24
    
    screen_width = block_size * 28 # 가로 크기
    screen_height = block_size * 24  # 세로 크기
    screen = pygame.display.set_mode((screen_width, screen_height))
    
    pygame.display.set_caption("TETRIS")
    ##############################################################
    
    background_1 = [(0, i) for i in range(21)]
    background_2 = [(i, 20) for i in range(12)]
    background_3 = [(11, i) for i in range(21)]
    background = background_1 + background_2 + background_3
    
    columns = 12
    rows = 21
    
    grid = [[0 for col in range(columns)] for row in range(rows)]
    miri_grid = [[0 for col in range(columns)] for row in range(rows)]
    
    for pos in background:
        grid[pos[1]][pos[0]] = 8
    
    block_mode = 1
    
    block_blank_size = 1
    block_fill = 0
    
    block_count = 1
    
    score = 0
    
    straight_score = 3
    falling_score = 1
    block_score = 15
    clear_score = 100
    
    clear_combo = 0
    draw_combo = 0
    clear_row_y_pos = 0
    
    draw_increase_score = 0
    
    small_font = pygame.font.Font(None, int(block_size * 5 / 4))
    score_font = pygame.font.Font(None, int(block_size * 3.5))
    score_title_font = pygame.font.Font(None, int(block_size * 2.5))
    combo_font = pygame.font.Font(None, int(block_size))
    
    color_idx = 1
    
    block_x_pos = 0
    block_y_pos = 0
    curr_block_shape_idx = 0
    curr_block_x_size = 0
    curr_block_y_size = 0
    
    last_block_x_pos = -1
    last_block_y_pos = -1
    last_block_shape_idx = 0
    last_block_x_size = 0
    last_block_y_size = 0
    
    next_block = [random.randint(1, 7), random.randint(1, 7), random.randint(1, 7)]
    
    hold = 0
    hold_check = False
    hold_now_turn_check = False
    
    curr_block_idx = 0
    
    # 검은색, 하늘색, 노란색, 초록색, 빨간색, 주황색, 파란색, 보라색, 회색
    color = [(0, 0, 0), (0, 255, 255), (255, 255, 0), (0, 255, 0), (255, 0, 0), (255, 127, 0), (0, 0, 255), (168, 64, 255), (195, 195, 195)]
    
    blocks_data = [
        [
        [[1, 1, 1, 1]],
    
        [[1],
         [1],
         [1],
         [1]]
        ], #하늘색 1
    
        [
        [[1, 1],
         [1, 1]]
        ], #노란색 2
    
        [
        [[0, 1, 1],
         [1, 1, 0]],
    
        [[1, 0],
         [1, 1],
         [0, 1]]
        ], #초록색 3
    
        [
        [[1, 1, 0],
         [0, 1, 1]],
    
        [[0, 1],
         [1, 1],
         [1, 0]]
        ], #빨간색 4
    
        [
        [[0, 0, 1],
         [1, 1, 1]],
    
        [[1, 0],
         [1, 0],
         [1, 1]],
    
        [[1, 1, 1],
         [1, 0, 0]],
    
        [[1, 1],
         [0, 1],
         [0, 1]]
        ], #주황색 5
    
        [
        [[1, 0, 0],
         [1, 1, 1]],
    
        [[1, 1],
         [1, 0],
         [1, 0]],
    
        [[1, 1, 1],
         [0, 0, 1]],
    
        [[0, 1],
         [0, 1],
         [1, 1]]
        ], #파란색 6
    
        [
        [[0, 1, 0],
         [1, 1, 1]],
    
        [[1, 0],
         [1, 1],
         [1, 0]],
    
        [[1, 1, 1],
         [0, 1, 0]],
    
        [[0, 1],
         [1, 1],
         [0, 1]]
        ],  # 보라색 7
    ]
    
    combo_ticks = None
    produce_ticks = None
    now_ticks = None
    fall_turn = 1
    max_fall_turn = 0.15
    
    can_under_size = []
    can_under = True
    can_right_size = []
    can_right = True
    can_left_size = []
    can_left = True
    can_up_size = []
    
    can_rotate = True
    straight = False
    
    mode_1 = pygame.Rect(0, 0, 0, 0)
    mode_2 = pygame.Rect(0, 0, 0, 0)
    mode_3 = pygame.Rect(0, 0, 0, 0)
    mode_4 = pygame.Rect(0, 0, 0, 0)
    
    click_pos = None
    
    block_pos_produce()
    
    running = True
    while running:
        block_mod_set()
    
        block_can_up_check()
        block_can_under_check()
        block_can_right_check()
        block_can_left_check()
    
        block_falling()
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RIGHT:
                    block_right()
                elif event.key == pygame.K_LEFT:
                    block_left()
                elif event.key == pygame.K_UP:
                    block_rotate()
                elif event.key == pygame.K_DOWN:
                    block_down()
                    score += falling_score
                elif event.key == pygame.K_SPACE:
                    block_straight()
                elif event.key == pygame.K_c:
                    hold_block()
            elif event.type == pygame.MOUSEBUTTONUP:
                click_pos = pygame.mouse.get_pos()
                check_buttons(click_pos)
    
        draw_screen()
        pygame.display.update()
    
    pygame.time.delay(500)
    
    game_over()
    
    pygame.quit()

    게임 설명

    게임 방법은 기존 게임과 비슷하다.

    임의로 떨어지는 블럭을 좌우 이동 및 회전을 통해 쌓고 한 줄을 모두 채우면 그 줄이 사라진다. 꼭대기에 블럭이 닿지 않도록 하면서 최대한 빠르고 많은 블럭을 쌓을수록 점수가 높아진다. 점수를 많이 얻는 것이 목적인 게임이다. 

     

    이 게임의 키보드 설정은 다음과 같다. 

    방향키 오른쪽/왼쪽은 떨어지는 블럭을 좌/우로 움직여주고, 방향키 아래쪽은 블럭의 떨어지는 속도를 빠르게 해준다. 방향키 위쪽은 떨어지는 블럭을 회전시켜준다. 스페이스는 블럭을 현재 블럭이 내려갈 수 있는 만큼 내려가도록 해준다. 

    C는 현재 블럭을 홀드해준다. 

    코드 설명 및 실행

    게임 실행 화면

    처음 실행하게 되면 이와 같은 창이 실행이 된다.

     

    창의 이름은 TETRIS로 설정하였다. 

     

    SCORE에서 점수를 보여준다. SCORE 글씨의 색은 현재 블럭의 색이라는 이스터에그(?)도 있다.

    점수의 색은 반복적으로 변화하고, 콤보 시 "Combo X (콤보수)"라는 텍스트를 띄울 수 있다. 

    점수가 오르는 만큼 텍스트를 띄워주는 기능을 추가해볼 것이다. 

     

    홀드 기능

    Hold Block에서는 현재 홀드한 블럭을 볼 수 있다. 

    한 번 홀드를 하면 현재 블럭을 쌓기 전까지는 다시 홀드를 하지 못한다. (기존 테트리스 규칙)

    Hold Block 글씨 색은 홀드한 블럭의 색이라는 이스터에그(?)도 있다.

     

     

    Next Block에서는 다음으로 나올 블럭 3개를 볼 수 있다. 

    Next Block 글씨 색은 바로 다음 블럭의 색이라는 이스터에그(?)도 있다. (이쯤 되면 이스터에그가 아니라는 생각도 든다.)

     

     

     

    Block Mode의 네 개의 버튼을 클릭하면 현재 블럭의 모습을 다음과 같이 바꿀 수 있다. 

    블럭 모드 2
    블럭 모드 3
    블럭 모드 4

    블럭 모드를 바꾸면 지금까지 쌓았던 블럭, 쌓을 블럭, 블럭 테투리, 홀드 블럭, 다음 블럭 등 모든 블럭의 모양이 바뀐다. 

    느낀점 및 개선 방향

    <앞으로 더 추가하고 싶은 기능들>

    1. 점수 증가 텍스트

    2. 게임창 기본 그림 테트리스로 설정

     

    <수정해야 할 버그들>

    1. 아래 블럭 뚫림 현상(내려가는 시간과 블럭의 모양이 변화하는 시간이 겹칠 때 생기는 것으로 추정)

    2. 떨어질 떄 회전 시 내려가는 시간 늘어남(처리 속도 및 시간으로 추정)

    3. can_under_size에 아무 것도 들어가지 않는 현상(이유 모름)

     

    아직 수정해야 할 버그도 있고, 추가해야 할 점도 많은 코드이다...

    그래도 여러 자료를 찾아보면서 따라 만들던 이전과는 달리 처음으로 아무 자료도 찾아보지 않고 처음부터 알고리즘부터 코딩까지 모두 나 혼자 스스로 게임을 만들었다는 것이 뿌듯하고, 자랑스러웠다. 이를 계기로 코딩에 더 재미를 붙일 수 있게 된 것 같았다. 

    앞으로 수정하고, 보안하면서 더 나은 테트리스 게임을 만들어 볼 것이다. 또한 더 다양한 게임을 만들 것이고, 게임 뿐만 아니라 다른 분야의 코딩들도 해볼 것이다. 

Designed by Tistory.