WWolves Den

파이썬 · 약 5분

pygame 마우스 입력: 클릭과 드래그로 그리는 작은 캔버스

마우스 이벤트의 좌표를 사용하고 별도 Surface에 그림을 보존하여, 화면 갱신과 그리기 데이터를 분리합니다.

Wolfgadeok · 업데이트

지금 위치와 이벤트가 발생한 위치

마우스로 선을 그리는 작은 캔버스를 만들면 입력이 화면에 바로 나타나므로 이벤트의 흐름을 관찰하기 좋습니다. 이때 이벤트를 처리하는 순간의 pygame.mouse.get_pos와 해당 이벤트가 발생한 시점의 event.pos는 다를 수 있습니다. 큐에 모인 움직임을 순서대로 그리려면 이벤트에 포함된 좌표를 사용하는 편이 의도가 명확합니다. 현재 위치 조회와 이벤트 좌표의 역할을 나누어 사용해 봅시다.

MOUSEMOTION은 움직임을, MOUSEBUTTONDOWN과 MOUSEBUTTONUP은 버튼 상태 변화의 순간을 알려 줍니다. 이 정보로 ‘누르고 움직일 때만 그린다’는 규칙을 만들 수 있습니다. 화면 전체를 매번 지우면 이전 선이 사라지므로 그림을 보존할 캔버스와 현재 화면을 별도로 두겠습니다. 왼쪽 드래그로 그리고 오른쪽 클릭으로 지우는 예제입니다.

그림을 저장하는 Surface와 화면 출력

아래 예제는 캔버스 Surface에 선을 누적한 뒤 매 프레임 화면으로 복사합니다. 빠르게 움직일 때 점들 사이가 끊기는 현상을 줄이기 위해 이전 이벤트 위치에서 현재 위치까지 선을 잇습니다. 포커스를 잃으면 드래그 상태를 취소하여 복귀 순간 엉뚱한 긴 선이 생기지 않게 합니다. 프레임 제한도 추가해 입력이 없을 때 불필요한 무제한 반복을 줄입니다.

예제 · python

import pygame

pygame.init()
screen = pygame.display.set_mode((640, 360))
canvas = pygame.Surface(screen.get_size())
canvas.fill((20, 24, 35))
clock = pygame.time.Clock()
last = None
running = True
try:
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.WINDOWFOCUSLOST:
                last = None
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    last = event.pos
                    pygame.draw.circle(canvas, (220, 100, 230), event.pos, 4)
                elif event.button == 3:
                    canvas.fill((20, 24, 35))
                    last = None
            elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
                last = None
            elif event.type == pygame.MOUSEMOTION:
                if last is not None and event.buttons[0]:
                    pygame.draw.line(canvas, (220, 100, 230), last, event.pos, 8)
                    last = event.pos
                elif not event.buttons[0]:
                    last = None
        if not running:
            break
        screen.blit(canvas, (0, 0))
        pygame.display.flip()
        clock.tick(60)
finally:
    pygame.quit()

그림판에서 게임 도구로 확장하기

이 구조는 맵 편집기의 타일 배치나 경로 표시 도구로 확장할 수 있습니다. 다만 게임 데이터를 화면 픽셀만으로 보관하면 저장·되돌리기·확대에 불리합니다. 타일 번호나 선의 좌표 목록을 실제 데이터로 보관하고 캔버스는 그 결과를 그리는 수단으로 삼으면 기능을 추가하기 쉽습니다. 화면 크기를 바꾸는 경우에는 입력 좌표를 월드나 캔버스 좌표로 변환하는 규칙도 필요합니다.

실습에서는 클릭만 했을 때 점이 찍히는지, 빠른 드래그의 선이 이어지는지, 오른쪽 클릭 후 이전 점과 연결되지 않는지 확인합니다. 창 밖으로 마우스를 옮기거나 다른 프로그램으로 전환한 뒤 돌아오는 상황도 검사합니다. 드래그 시작점과 종료 상태를 명확히 관리해야 새로 그리는 선이 이전 동작에 잘못 이어지지 않습니다.

마우스 좌표와 버튼 상태를 로그로 관찰할 때는 매 움직임마다 무제한 출력하지 않도록 합니다. 로그 자체가 입력 실습의 반응성을 떨어뜨릴 수 있습니다.

참고 자료

예제는 학습용이며, 모든 환경에서 실행 검증된 완성 프로젝트는 아닙니다. 적용 전 사용 중인 버전과 프로젝트 환경에서 동작을 확인하세요.