토요일, 7월 03, 2021

[B급 프로그래머] xneko를 파이게임으로 이식하면서... (결론: 수학의 중요성)

옛날 옛적에 매킨토시나 X윈도우를 사용하신 분들이라면 스크린세이버 중에서 네코를 기억하시는 분들이 많으실 것이다. 쥐나 새 모양의 커서를 귀여운 고양이 네코가 쫓아다니는 모습은 아직도 기억난다. 맥OS 7이 동작하던 매킨토시 IIci와 SunOS/솔라리스가 돌아가던 스팍스테이션 1도 갑자기 보고 싶어진다. 프로그램 실력이 점점 녹슬고 있어서 X 윈도우에서 동작하던 xneko를 파이썬으로 간단하게 이식해봤다. 파이게임을 사용하면 이미지를 서피스 형태로 만들어 비트블릿을 사용해 화면에 표시하거나 스프라이트(응?) 형태의 구현도 가능하며, 이벤트 처리도 손쉽기 때문에 고양이가 쥐를 쫓아가는 비즈니스(?) 로직만 잘 생각하면 어렵지 않게 구현할 수 있다.

X윈도우용 네코 코드인 BSD용 xneko을 참고해서 쥐를 추적하는 알고리즘을 구현했고, 원래 X윈도우용 네코는 XBM 형식의 이미지를 사용했기에 파이썬 파이게임에 맞는 PNG 형식의 애셋을 txneko에서 가져왔다.

고양이가 쥐를 추격하기 위해 피타고라스의 정리와 삼각함수를 떠올려야 했는데, 수십 년이 지나도 달달 외워 놓은 암기 학습의 위력(?) 덕분에 바로 이해가 가더라. 결론이 조금 이상하긴 하지만... 모두 수학 공부 열심히 하시길... ;) 참고로 고양이와 쥐 사이의 거리에 따라 이동해야 하는 변위를 구했다고 가정하면, 방향을 결정하는 핵심 알고리즘은 다음과 같다:

# 변위를 사용해 방향을 결정한다
X = dx
# 위로 올라가면 변위가 마이너스가 되므로(좌표계: (0,0)에서 (400, 300)) -1을 곱해서 부호를 바꾼다
Y = -1 * dy
# 삼각형 빗변 구하기(여기서도 피타고라스의 정리)
length = math.sqrt(X * X + Y * Y)
# 사인 정의에 따라 sin θ = 삼각형의 높이/삼각형 빗변 길이
sin_theta = Y / length

# 여기서 사용 중인 두 가지 상수: 각도 계산용
#  - sin_pi_per8_times3 = sin(π/8 * 3)
#  - sin_pi_per8 = sin(π/8)

if dx > 0: # 우측으로 움직이는 경우(X 변위가 +)
    # sin(π/8 * 3)보다 크면 위 방향으로 거의 수직
    if sin_theta > self.sin_pi_per8_times3:
        self.state = 'U'
    # sin(π/8)보다 크고 sin(π/8 * 3)보다 작으면 오른쪽 위로 이동
    elif sin_theta <= self.sin_pi_per8_times3 and sin_theta > self.sin_pi_per8:
        self.state = 'UR'
    # -sin(π/8)보다 크고 sin(π/8)보다 작으면 오른쪽으로 이동
    elif sin_theta <= self.sin_pi_per8 and sin_theta > -1 * self.sin_pi_per8:
        self.state = 'R'
    # -sin(π/8 * 3)보다 크고 -sin(π/8)보다 작으면 오른쪽 아래로 이동
    elif sin_theta <= -1 * self.sin_pi_per8 and sin_theta > -1 * self.sin_pi_per8_times3:
        self.state = 'DR'
    # -sin(π/8)보다 크면 아래 방향으로 거의 수직
    else:
        self.state = 'D'

EOB

댓글 없음:

댓글 쓰기