이번 편의 목표: 가로 10칸, 세로 20칸 판을 2차원 리스트로 표현하고, 격자와 채워진 칸을 화면에 그립니다.
판은 리스트의 리스트
판은 줄(row) 20개를 담은 리스트이고, 줄 하나는 칸 10개를 담은 리스트입니다. 빈 칸은 None, 블록이 굳은 칸은 그 블록의 색을 담습니다. 그래서 board[y][x]로 y번째 줄의 x번째 칸을 읽습니다. 바깥 리스트가 세로, 안쪽 리스트가 가로라서 y를 먼저 씁니다.
좌표는 왼쪽 위가 (0, 0)이고, x는 오른쪽으로, y는 아래쪽으로 커집니다. 화면 픽셀 좌표와 방향이 같아서, 칸 좌표에 CELL(30픽셀)을 곱하면 바로 그 칸의 픽셀 위치가 됩니다.
new_board는 [[None] * COLS for _ in range(ROWS)]로 판을 만듭니다. [[None] * COLS] * ROWS라고 쓰면 안 됩니다. 그렇게 하면 같은 줄 객체 하나를 20번 가리키게 되어, 한 칸을 칠하면 같은 열의 20칸이 모두 칠해집니다. 리스트 내포는 반복할 때마다 새 줄을 만듭니다.
그리기
창의 크기도 칸 수에서 계산합니다. 판의 너비는 10 × 30 = 300픽셀이고, 오른쪽에 점수와 다음 블록을 보여 줄 180픽셀을 더해 480 × 600 창을 만듭니다.
draw 함수는 배경을 칠한 뒤 세로선 11개와 가로선 21개로 격자를 긋고, 판을 한 칸씩 돌면서 None이 아닌 칸만 draw_cell로 칠합니다. enumerate는 순서 번호와 값을 함께 꺼내 주므로, 줄 번호가 y, 칸 번호가 x가 됩니다.
draw_cell은 칸 크기의 사각형을 만들고 inflate(-2, -2)로 사방을 1픽셀씩 줄여서 칠합니다. 이웃한 칸 사이에 틈이 생겨 블록 하나하나가 구분됩니다.
main에서는 시험 삼아 맨 아랫줄 왼쪽 두 칸을 빨강으로, 그 위 한 칸을 파랑으로 채웠습니다. 다음 편부터는 이 시험용 세 줄을 지웁니다.
전체 코드
import sys
import pygame
COLS, ROWS = 10, 20
CELL = 30
BOARD_WIDTH = COLS * CELL
SIDE_WIDTH = 180
WIDTH, HEIGHT = BOARD_WIDTH + SIDE_WIDTH, ROWS * CELL
FPS = 60
BACKGROUND = (18, 18, 24)
GRID = (40, 40, 52)
def new_board():
return [[None] * COLS for _ in range(ROWS)]
def draw_cell(screen, x, y, color):
rect = pygame.Rect(x * CELL, y * CELL, CELL, CELL)
pygame.draw.rect(screen, color, rect.inflate(-2, -2))
def draw(screen, board):
screen.fill(BACKGROUND)
for x in range(COLS + 1):
pygame.draw.line(screen, GRID, (x * CELL, 0), (x * CELL, HEIGHT))
for y in range(ROWS + 1):
pygame.draw.line(screen, GRID, (0, y * CELL), (BOARD_WIDTH, y * CELL))
for y, row in enumerate(board):
for x, color in enumerate(row):
if color is not None:
draw_cell(screen, x, y, color)
def main():
pygame.init()
pygame.display.set_caption("Tetris")
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
board = new_board()
board[19][0] = (220, 60, 60)
board[19][1] = (220, 60, 60)
board[18][0] = (60, 100, 220)
while True:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
draw(screen, board)
pygame.display.flip()
if __name__ == "__main__":
main()격자 왼쪽 아래에 빨간 칸 두 개와 파란 칸 하나가 보이면 성공입니다.
직접 해 보기
맨 아랫줄 10칸을 모두 초록 (80, 200, 80)으로 채우는 코드를 main에 한 줄로 적어 보세요.
해설
board[19] = [(80, 200, 80)] * COLS 입니다. 여기서는 * 로 리스트를 늘려도 괜찮습니다. 안에 든 값이 튜플이라 칸마다 따로 바꿀 일이 없고, 줄 자체는 새 리스트 하나이기 때문입니다. 위에서 피한 문제는 리스트 안에 리스트를 곱할 때만 생깁니다.
COMMENTS
댓글 0
이 글에 대한 의견이나 질문을 남겨 주세요.
댓글은 구글이나 카카오로 시작한 뒤에 남길 수 있습니다.
등록된 댓글이 없습니다.