10.3 네트워크 게임으로 만들기 1

단 한대의 컴퓨터에서만 동작하는 게임(이를 지칭하는 용어로 standalone 게임이라 함)을 네트워크 게임으로 변모시키기 위해서는 기존 퐁 게임을 구성하는 객체들(점수, 반사판, 공)의 코드에 일부 수정이 필요하다. 우리가 처음부터 네트워크형 게임으로 만들 것을 작정하고 객체설계를 한 것이 아니기 때문에 네트워크 게임을 위해 미흡한 부분이 있고 이번 절에서는 이를 보완하도록 하자.

먼저, 점수(Score) 객체이다. 참고로 각 객체의 코드 전체가 아닌 추가/수정된 부분만 따로 떼내 살펴보도록 하겠다. reinit 멤버 함수가 추가로 필요한데 이 함수의 목적은 게임을 아예 최초 시작단계로 돌아가기 위한 목적이다. 이런 상황은 네트워크 게임에서만 발생할 수 있는 상황인데 언제 필요할 수 있을까? 그것은 한창 게임 진행 중에 갑자기 네트워크 불완전성으로 인한 또는 의도적인 상대방의 불특정 게임중단 상황을 대응하기 위함이다.

class Score():
    ...
    
    def reinit(self):
        self._b1_score = -1
        self._b2_score = -1
    ...

def update():
    ...   
    
    # 상대 연결 끓김
    num_peers = len(net.get_peers())
    if num_peers < MAX_PEERS:
        if is_host:
            score.reinit()
            ball.reset()
        else:  # Plyer2 
            print("The host is disconnected.")
            exit()  # 호스트가 종료되면 방 폭파
    ...

릴레이 서버방식의 게임의 특징은 우리가 앞서 살펴봤듯이 그룹방에서 호스트가 중요하고, 호스트는 게임의 전체적인 상태의 관리를 통해 게임을 유지시키는 것을 담당하는 주인장 같은 역할이다. 이 호스트가 어떤 상황에서든 게임 도중에 그룹방에서 나가게 되면 당연히 더이상 게임은 진행될 수 없는 상황으로, 어떻게 처리할지는 여러 시나리오를 만들 수 있는데, 제일 간단히 처리하는 방법은 우리가 알고 있는 소위 방폭파(?)라는 방법으로 그룹안에 있는 모든 클라이언트들이 그룹방에서 내쫒기는 것으로, 즉 모든 클라이언트들의 기존 서버와의 네트워크 연결을 강제종료 시키는 것이다(18~20라인). 이와는 반대로 호스트가 아닌 일반 유저가 갑자기 그룹방에서 나간 상황에 대해서는 어떻게 처리해야 할까? 이 때가 바로 renint 함수를 호출해서 게임을 완전초기화해서 최초 상태로 돌리는 지점인 것이다(15~17라인).

그렇다면, 게임중간에 어떤 클라이언트가 그룹에서 빠져나갔는지를 감지할 수 있을까? 그 해답은 update 함수의 5번 라인에 NetNode 객체의 get_peers 멤버함수로 이 함수는 현재 그룹안에 있는 클라이언트들의 id목록을 리턴해주며 update 함수 안에 위치시켜 그 변동성을 실시간 확인함으로써 게임중간에 어떤 클라이언트가 그룹에서 빠져나갔는지 알 수 있다.

다음으로는 각 클라이언트들의 반사판의 조작과 움직임 처리하는 루틴을 살펴보자.

def update():
    ...
    
    # 반사판
    if keyboard.a or keyboard.up:
        my_bar.up()
    if keyboard.z or keyboard.down:
        my_bar.down()
    net.send_msg(peer_id, 'bar_pos', my_bar.center)

    for bar in bars:
        if is_host:
            bar.collide_ball()
        else:  # Plyer2
            bar.collide_ball(sound_only=True)     
    ...

반사판의 조작은 호스트/일반 유저이든 상관없이 둘 다 본인이 선호하는 방식으로 키보드의 'a' 또는 '윗방향키' 로 윗방향으로 움직이고, 키보드의 'z' 또는 '아래방향키' 로 아래방향으로 움직일 수 있다(5~8라인). 참고로 my_bar 변수값은 이전 장의 connect_server 함수에서 살펴보았듯이 그룹방에 입장한 순서에 따라, bar1 또는 bar2값이 사전에 할당되어 있음을 알 수 있다. 여기까지 UI적으로 본인화면에 움직임을 만든 후에는 상대방에게도 나의 움직임에 대한 변경폭을 네트워크를 통해 알려주어야만 상대방 화면에 나의 움직임이 실시간으로 보일 것이다. 그러한 목적의 멤버함수가 바로 그 다음 9번 라인에서 사용한 send_msg 함수이다.

이 함수는 3가지 파라미터 값을 갖는다. 첫번째로 이 (정보성)메시지의 수신자의 그룹방에서의 id값으로 여기서는 peer_id를 인자로 넘겼는데, 마찬가지로 이전 장의 connect_server 함수에서 이 값이 사전 설정되어 있다. 즉, 호스트가 된 게임유저는 상대인 일반유저에게/일반유저인 게임유저는 호스트에게 메시지를 보내게 되는 것이다. 두번째 값은 메시지 수신자가 자신에게 도착하면 여러 메시지들 중에서 특정 메시지를 구분할 수 있게 하려는 목적의 메시지 식별자(일종의 id)이다. 마지막으로는 실제 메시지의 내용으로 여기서는 반사판 객체의 중심좌표(my_bar.center)를 보내고 수신측에서는 이 값을 화면에 UI적으로 반영시킴으로서 상대방 반사판의 움직임을 표현한다. 이처럼 메시지를 전송하는 부분이 있다면, 당연히 해당 메시지 수신하여 처리하는 루틴이 있을 것이고, 이 부분에 대해서는 추후에 모아서 한꺼번에 살펴보도록 하자.

반사판 조작해서 새롭게 추가된 부분을 더 살펴보면(12~15라인), 게임 호스트와 일반유저의 처리를 구분했고, 호스트의 경우, 단독게임(standalone) 때와 다를바가 없고

Last updated

Was this helpful?