레이블이 HLAPI인 게시물을 표시합니다. 모든 게시물 표시
레이블이 HLAPI인 게시물을 표시합니다. 모든 게시물 표시

3월 21, 2016

[HLAPI] IndexOutOfRangeException:NetworkReader:ReadByte out of range : NetBuf sz: ... pos: ... 에러

아마 서버와 클라이언트 간 메시지를 주고 받다가 이런 에러를 보았을 것이다.
처음엔 메시지 크기가 커서 그런 줄 알았는데...
유니티 공식 문서에는 한번에 최대 1400 바이트는 보낼 수 있다고 되어있다.
알고보니 서버의 메시지 클래스와 클라이언트의 메시지 클래스 간 규격이 일치하지 않아서
발생한 문제였다.

예를 들어 서버에서 정의한 사용자 메시지 클래스가

public class MyMessage : MessageBase
 {
  public string a;
  public string b; 
  public string c;
 }
위와 같다면, 클라이언트에서 역시 위와 동일한 코드로 메시지가 정의되어있어야 한다.
구글링해도 명확한 답변이 없어서 잠시 헤맸는데... 쉽게 해결되는 에러였다.

1월 19, 2016

유니티 5 네트워킹 시스템 HLAPI를 사용하여 LAN 멀티플레이 기본 틀 만들기 - 3(완결)


마지막 장입니다!
1 편에서 예고했던 대로, 동일한 네트워크 내에 존재하는 서버나, 클라이언트를 인식하고, 연결하는 것을 해보겠습니다.
예를 들어, 게임에 접속해서 방을 만들고, 접속한 유저들이 자동으로 뜨는 목록을 보고 싶다거나 할 때 유용하게 쓰일 것 같습니다.
다행히도, HLAPI 의 NetworkDiscovery 컴퍼넌트를 사용해서 이를 쉽게 구현해볼 수 있습니다.

이 컴퍼넌트는 전송 계층의 UDP Broadcasting 기능을 사용하며, 따라서 인터넷에서 작동하는 것이라 오로지 LAN 상에서만 사용할 수 있습니다.
컨셉은 단순히 특정 포트번호로 '방송'을 송신하는 개체와 수신하는 개체 두 가지가 있고, 방송을 수신하였을 때 이벤트를 받아서 송신한 개체의 IP에 접속하는 것입니다.(송신할 때 IP 주소나 기타 데이터를 를 같이 내보냅니다.)

역시나, NetworkManager 와 같이 빈 오브젝트에 NetworkDIscovery 컴퍼넌트를 추가하면 됩니다만,
우리는 기본 제공 GUI 를 사용하지 않고 커스텀하기 위해 코드를 조금 더 쳐 보겠습니다.
앞서 작성한 MyNetManager 를 불러와, 다음 노랗게 색칠한 코드 한 줄을 추가합니다.



 











다음은 서버와 클라이언트로 구동을 시작하는 SetupServer, SetupClient 메서드에 각각 
UDP 브로드캐스팅을 시작하는 명령을 넣습니다.
공통으로 Initialize() 를 실행하여 컴퍼넌트를 초기화 한 뒤,
서버에서는 StartAsServer( ), 클라이언트에서는 StartAsClient( ) 를 각각 실행하면
이제 동일한 네트워크 내의 유니티 게임들이 서로를 인식하게 됩니다.






























하지만 이대로 실행하면 인식을 했는지 전혀 알 수가 없겠죠??

클라이언트에서 방송을 수신했을 때 발생하는 이벤트를 가로채서 처리를 해야 합니다.

빈 게임오브젝트를 생성하고 이름을 'Broadcaster'로 변경하고, 다음 C# Script 를 새로 생성하여 붙입니다.

// MyNetworkDiscovery.cs


using UnityEngine;
using System.Collections;
using UnityEngine.Networking;

public class MyNetworkDiscovery : NetworkDiscovery
{

    public override void OnReceivedBroadcast(string fromAddress, string data)
    {
        //서버로부터 브로드캐스트 메시지를 받았을 때 실행됩니다.
        base.OnReceivedBroadcast(fromAddress, data);
        Debug.Log("recived broadcast from : " + fromAddress);

        StartCoroutine("TweenAnim");
    }
}

그리고 NetworkManager 컴퍼넌트의 인스펙터창에서 빈 칸으로 되어있는
NetworkDiscovery 에 Broadcaster 를 다음과 같이 끌어다 놓습니다.











































NetworkDiscovery 로 부터 상속받은 OnReceivedBroadcast 메서드는 fromAddress 에 
브로드캐스트 메시지를 송신한 개체의 IP 주소, 함께 보낸 data 를 인자로 받습니다.
IP 주소 같은 경우, 게임 내에서 빈번하게 쓰일 것이므로 위 콜백에

   NetworkManager.singleton.networkAddress = fromAddress;

코드를 추가하여 네트워크 매니저 싱글턴이 IP 주소를 저장하도록 할 수도 있습니다.

이제 두 모바일 기기를 같은 와이파이로 접속시킨 후, 각각을 서버와 클라이언트로 구동하여,
클라이언트에서는 OnReceivedBroadcast 콜백에서 라벨을 띄워준다거나, 어떤 표시를 하여 송수신이 이루어졌는지 확인해봅시다.

다음 동영상은 서버로부터 메시지를 수신하면 라벨에 트윈 애니메이션을 적용시켜 수신하였음을 알려주는 시연 동영상입니다.



완성된 코드는 다음 저장소에서 다운 받으실 수 있습니다.


지금까지 유니티5의 HLAPI 를 사용해 네트워크 객체를 서로 연결하고, 네트워크 메시지를 수신할 수 있는 기본적인 기능을 구현하는 법을 알아보았습니다.
읽어주셔서 감사드리고, 많은 도움이 됬으면 좋겠습니다^^

1월 06, 2016

유니티 5 네트워킹 시스템 HLAPI를 사용하여 LAN 멀티플레이 기본 틀 만들기

외부 인터넷을 거치지 않고, 로컬 와이파이만을 이용한 멀티 플레이를 구현하기 위해 유니티 매뉴얼을 보다가 좋은 재료를 발견하여 짧게 적어보겠습니다.

본 튜토리얼에서는 LAN 환경에서 네트워크 객체(유니티 애플리케이션)들이 서로의 존재를 인식하고, 접속하여 네트워크 메시지를 주고받고, 각종 콜백처리를 하기 위한 기본 틀을 구현해보겠습니다. 그리고 간단한 UI 구성을 위해 NGUI 를 사용하겠습니다.

유니티가 5.1 버전 이후로 새로운 네트워킹 시스템을 발표하여 이전보다 더 간편하고 쉽게 좋은 성능을 가진 멀티플레이를 구현할 수 있게 되었습니다.

NetworkManager 와 HLAPI(High-Level) 를 사용하여 시작할 수 있습니다.
간단하게 위의 한글 매뉴얼을 흝어보고 오시면 더 이해가 쉽습니다.

먼저 새 프로젝트를 만들고, 빈 게임 오브젝트 하나를 생성합니다.
원래는 'Add Component' 버튼을 눌러 NetworkManager 컴퍼넌트를 추가하는 것으로 끝나지만, 입맛대로 커스터마이징하기 위해 NetworkManager 를 상속한 사용자 정의 스크립트를 생성하겠습니다. 

새로운 C# 스크립트를 생성하여 MyNetManager 로 이름을 변경한 후 빈 게임 오브젝트에 붙입니다.

그리고 아래처럼 코딩해주세요.

using UnityEngine;
using System.Collections;
using UnityEngine.Networking; /* 유니티 네트워킹 API 입니다. */


public class MyNetManager : NetworkManager /* NetworkManager 를 상속합니다. */
{
    NetworkClient myClient;

    /* 확장 함수 */
    public override void OnStartServer() 
    {
        Debug.Log("OnStartServer( )");
    }

    public override void OnStartClient(NetworkClient client)
    {
        Debug.Log("OnStartClient( )");
    }

    public override void OnStopClient()
    {
        Debug.Log("OnStopClient( )");
    }

    /* 사용자 정의 함수 */
    public void SetupServer()
    {
        Debug.Log("SetupServer()");
        StartServer();     
        NetworkServer.Listen(4444);
        NetworkServer.RegisterHandler(MsgType.Connect, OnConnected);

}

    public void SetupClient()
    {
        Debug.Log("SetupClient()");
        StartClient();     

        myClient = new NetworkClient ();
        myClient.Connect("127.0.0.1", 4444);

    }
    public void OnConnected(NetworkMessage netMsg)
    {
        Debug.Log("Connected to server");
    }

}
OnStartServer( ), OnStartClient( ),OnStopClient( ) 는NetworkManager 를 확장한 메서드들입니다. 나중에 이 부분에서 서버를 구동시켰을 때, 클라이언트가 접속했을 때의 처리를 할 것입니다. 이 외의 여러 네트워크 이벤트를 처리할 수 있는 가상 함수들은 공식문서를 참조하시기 바랍니다. 
아래의  SetupServer( ), SetupClient( ) 메서드는 본 튜토리얼에서 NetworkManagerHUD(기본 GUI) 를 사용하지 않을 것이기 때문에 사용자 정의로 직접 서버를 구동하고 클라이언트를 접속시키는 코드를 작성하기 위해 만든 것입니다.
NetworkServer.RegisterHandler 메서드는 서버측에서 네트워크 이벤트를 처리할 처리기를 등록하고 있습니다. 위 코드는 클라이언트 접속시 발생할 이벤트를 처리합니다.
마지막으로 아래와 같이 각각 서버, 클라이언트 모드로 구동하기 위한 버튼을 두 개 배치합니다. 한쪽엔 버튼 클릭시 MyNetManager 의 SetupSever( )를, 다른 하나는 SetupClient( ) 가 실행되도록 클릭 이벤트를 연결합시다.
접속이 이루어졌는지 확인하기 위해, 유니티 에디터에서 서버를 실행하고, PC 버전으로 빌드하여 클라이언트로 실행해봅니다.
그러면 다음과 같이 클라이언트로 접속했을 때 콘솔창에 메시지가 뜨는 것을 볼 수 있습니다.
2편에서는 서버와 클라이언트가 연결 된 상태에서 서로 메시지를 주고받는 기능을 구현해보겠습니다.