마우스 클릭 후 드래그 해서 사각형을 그리는 프로그램을 써본적이 있는가? 컴퓨터를 좀 다루는 사람이라면 아마 파워포인트나, 포토샵 같은 프로그램에 도형이나 텍스트박스를 그리기 위해서 사용해본 경험이 있을 것이다.
이번 포스트는 마우스를 클릭 후 드래그하여 마우스에서 손을 떼었을 때 사각형을 그리도록 코드를 작성한다.
이게 무슨 게임과 관련이 있냐고 질문할 수 도 있다. 혹시 스타크래프트같은 전략게임을 해본 적이 있다면 부대를 선택할때 어떻게 했는가? 마우스를 클릭한 상태에서 아군 유니트들을 사각형으로 드래그 하여 포함시키고 손가락을 뗀다.
사각형을 드래그로 그리는 것은 저것과 똑같은 원리이다. 전략게임에서는 사각형 안에 걸쳐있는 유니트를 선택한다. 그리고 마우스 위치에 따라 사각형을 그리고 있다.
다음 코드를 살펴본다.
from pygame import *
import pyc
C1_GREEN = (204, 255, 204)
C1_BLUE = (153, 204, 255)
bgColor = C1_GREEN
size = width, height = 800,600
screen = display.set_mode(size)
screen.fill(bgColor)
display.update()
init()
start = (0,0)
end = (0,0)
dSize = (0,0)
drawing = False
rectList = []
run =True
while (run):
for pyEvent in event.get():
if pyEvent.type == QUIT:
run = False
elif pyEvent.type == MOUSEBUTTONDOWN:
start = pyEvent.pos
dSize = 0,0
drawing = True
print(pyEvent)
elif pyEvent.type == MOUSEBUTTONUP:
end = pyEvent.pos
dSize = end[0]-start[0], end[1]-start[1]
drawing = False
rect = Rect(start,dSize)
rectList.append(rect)
print(pyEvent)
elif pyEvent.type == MOUSEMOTION and drawing:
end = pyEvent.pos
dSize = end[0]-start[0], end[1]-start[1]
screen.fill(bgColor)
for r in rectList:
draw.rect(screen,pyc.BLACK,r,4)
draw.rect(screen,pyc.RED,(start,dSize),2)
display.update()
print("END HERE")
quit()
start = (0,0)
end = (0,0)
dSize = (0,0)
drawing = False
rectList = []
앞부분은 다른 포스트에서 여러번 설명한 부분이다. 여기서 부터 봐야한다.
start 와 end 는 각각 시작좌표와 끝 좌표를 말한다. dSize는 끝좌표에서 시작좌표를 뺀 것이다. 즉 너비와 높이가 나온다. 이 것들은 rect 메소드의 인수로 들어간다. 그냥 시작좌표와 끝좌표를 주면 되지 않느냐라고 할 수도 있으나 rect 메소드의 인수가 시작좌표(x,y)와 너비,높이의 인자를 받도록 되어있다. 따라서 별도로 dSize를 계산한다.
drawing 은 boolean 형이다. 마우스 클릭시 drawing 을 계속하고 마우스에서 손을 떼면 drawing이 끝난다. True 와 False 값으로 상태 플래그를 설정한다.
rectList 는 사각형 객체를 저장하는 리스트이다. (객체 배열같은 것) 화면이 갱신될때(display.update()) 기존의 화면을 다 지우는데 객체에 저장된 사각형을 다시 그려준다. 즉 사용자가 드래그 해서 사각형을 하나 만들 때마다 기존의 저장된 사각형 객체를 다시 그려주는 것이다. 많을 수록 시간이 더 걸릴 것이다. 예를 들어 사각형을 100개 그렸다 하면 화면이 갱신될 때 마다 100개를 다시 그려줘야한다. 너무 빨라서 우리눈에 안보일 뿐이다. 항상 다시 그려줘야한다. 수백개건 수천개건 다시 그린다.
아래는 사각형을 그리는 로직이다. 크게 세가지 상태를 본다. 마우스클릭했을 때, 마우스 클릭해서 이동할 때, 마우스에서 손을 뗐을때.
run =True
while (run):
for pyEvent in event.get():
if pyEvent.type == QUIT:
run = False
elif pyEvent.type == MOUSEBUTTONDOWN:
start = pyEvent.pos
dSize = 0,0
drawing = True
print(pyEvent)
elif pyEvent.type == MOUSEBUTTONUP:
end = pyEvent.pos
dSize = end[0]-start[0], end[1]-start[1]
drawing = False
rect = Rect(start,dSize)
rectList.append(rect)
print(pyEvent)
elif pyEvent.type == MOUSEMOTION and drawing:
end = pyEvent.pos
dSize = end[0]-start[0], end[1]-start[1]
screen.fill(bgColor)
for r in rectList:
draw.rect(screen,pyc.BLACK,r,4)
draw.rect(screen,pyc.RED,(start,dSize),2)
display.update()
print("END HERE")
quit()
- 마우스 클릭: 스타트 포지션(시작지점)을 저장한다. drawing 을 True로 바꿈으로써 사각형을 그릴 수 있게 된다.
- 마우스 클릭 + 이동 : 이것은 이벤트에서 MOUSEMOTION and drawing 으로 판단한다. 마우스모션은 윈도우창에서 마우스가 움직이고 있다. drawing의 경우 클릭해서 드래그하면 True 일 것이고, 그냥 이동만 하고 있으면 False 일 것이다. 즉 마우스를 드래그 중이라는 것을 알수있다. 아까 dSize 가 필요하다고 했다. (rect 함수의 매개변수니까) 마우스를 움직일 때마다 dSize값이 계산 되고 있다. 그 다음은 화면을 다시 그려줘야한다. 일단 배경색상을 채우고, 객체배열(리스트)에 있는 사각형들을 하나씩 꺼내서 스크린에 그려준다. (BLACK 펜에 두께 4를 설정했다) 그리고 현재의 사각형을 그린 후 화면을 갱신한다.
코드를 실행해보고 매개변수를 건드려 보면 작동원리를 알 수 있다. 마우스를 드래그하는 순간 내부적으로 얼마나 많은 일들이 일어나고 있는지 파악하는 것은 중요하다. 그 이벤트가 일어나는 사이사이에 컴퓨터가 해야할 일들의 로직을 짜는 것이 개발자가 할 일이다. 얼마나 정교하게 프로그램을 짤 수 있느냐에 따라서 사람들에게 주는 감동의 크기가 달라질 것이다.