시작하기 앞서....

2편은 Unity3D 와 WinForm 의 통신에 대한 이야기를 할것이며 혹시나마 UForm(Unity3D + WinForm) 에 대해서 잘 모르겠다면 필자가 적은 

2015/07/20 - [Programming/Unity3D] - Unity + WinForm 을 구현해보자! 1편 을 보고 이 글을 보도록 하자..


그리고 초보 프로그래머가 적은 내용이므로 틀린 내용, 부족한 설명, 이상한 단어 가 많을 수도 있지만... 이해하고 보시기를 간곡히 부탁드리옵니다.


UFom 의 통신을 구현하기 전 알아보고 가자~!

UForm 에서 쓸수있는 통신방법은 여러가지가 있으나 구글링을 해본 결과 TCP Socket , SendMessage 이 2가지 통신방법이 가장 많이 보였고 이 글에서는 이 2가지를 이용하여 제작하였다. (TCP, SendMessage 관련 내용은 자세한 설명은 생략하고 진행하겠다.)


일단 클라이언트과 서버를 담당할 프로그램을 정해야한다. 필자는 클라이언트을 Unity3D 로 정하고 서버를 WinForm 으로 정했다. 서로 C# 코드를 사용하였기 때문에 이 글을 보고 자신이 원하는 방향으로 바꿔도 좋을꺼 같다. 


그럼 본격적으로 본제로 들어가겠다.


UForm 통신 구현하기~! 클라이언트 (Unity3D)

TCP 를 구현하기 전 로딩시간 차이로 인한 터짐현상 (이 문제가 필자한테만 일어나는건지 아니면 다른 코드가 있는지는 잘 모르겠지만.. 필자를 가장 고생시킨 이 문제를 주제로 정하고 글을 진행하겠다.) 을 해결하기 위해 SendMessage 로 클라이언트 (Unity3D) -> 서버 (WinForm) 을 먼저 연결해기로 생각하였다.


Unity3D 가 완전히 로딩이 끝나지 않으면 Socket 에 이상한 값이 들어가며 터져버리므로 Unity3D 가 로딩이 다 끝났다는 것을 WinForm 에 알려주는 형식으로 코드를 구현해야 했고, 필자는 이 부분을 해결하기 위해 UnityWeb 에서 로딩이 끝난 후 가장 먼저 켜지는게 무엇인지 고민하였고 카메라가 켜지면 로딩이 끝났다는 것을 간접적으로 알려주는 것이라는 생각을 하였다.

1
void OnRenderObject() { }
cs

http://docs.unity3d.com/450/Documentation/ScriptReference/Camera.OnRenderObject.html : Unity Manual 에서 나오는 설명


이 함수 안에 인제 코루틴을 이용하여 서버스크립트가 들어있는 GameObject 을 실행하도록 하였다. (끄고 키고가 편하도록 GameObject 안에 스크립트를 넣고 제작하였지만 다르게 제작해도 좋다.)

1
2
3
4
5
6
7
8
9
10
11
void OnRenderObject()
{
    StartCoroutine("StartClient");
    Debug.Log("OnRenderObject");
// http://seonbicode.tistory.com/
 
IEnumerator StartClient()
{
    text.text = "StartClient On"// Debug 을 위한 text
    TCPclient.SetActive(true); // TCPclient 실행
}
cs


WebPlayer 가 로딩이 끝난 후 카메라에 오브젝트가 렌더링 되면 TCPclient GameObject 가 실행이 되고 TCPclient 라는 GameObject 에 있는 TcpClient 스크립트가 실행된다.


OnRenderObject 는 Update 처럼 켜있는 동안 계속 불러지기 때문에 중간에 체크를 하여 한번만 들어가게 해야한다. 사실 OnRenderObject 를 꼭 안 써도 되지만 확실하게 로딩이 끝났을때 실행되는 메소드이기 때문에 사용한다.


TCPclient 가 실행이 되면 Start 가 가장 먼저 실행이 되며 이 곳에서 ConnectServer(); 함수를 실행한다. Awake() 를 사용해도 괜찬타.

1
2
3
4
public void Start()
{
    ConnectServer();
// http://seonbicode.tistory.com/
cs


1
2
3
4
5
6
7
8
9
10
11
12
private void ConnectServer()
{
    /*/////////////////////////////////*/
    /* Tcp 서버 구현 SocketAsyncEventArgs */
    /*/////////////////////////////////*/
    
    Application.ExternalCall("TcpSet""프로퍼티값");
 
    /*/////////////////////////////////*/    
    /* Tcp 서버 구현 ConnectAsync */
    /*/////////////////////////////////*/
// http://seonbicode.tistory.com/
cs

(Tcp 클라이언트는 구글링을 하여 직접 적도록 하자. 필자의 소스코드가 너무 미개하여...)


ConnectServer() 에서는 비동기 소켓을 만든 후 Application.ExternalCall("함수명", "프로퍼티값"); 으로 서버 (WinForm) 로 "나 로딩이 끝났고 지금 소켓만들어서 접속하니 서버를 열어라!" 를 시전한다. 


Application.ExternalCall("함수명", "프로퍼티값");

  1. "함수명"에는 서버에서 서버부분이 들어가있는 함수나 그것을 실행시켜주는 함수을 실행시켜주도록 하자. (TcpSet)
  2. "프로퍼티값" 에는 서버로 보내줄 상태값이나 머 여러가지 정보를 보내는데 사용하자. 사실상 첫 실행을 한 후 Socket 통신을 하게 되면 더 이상 사용할 일이 없다.
  3. http://docs.unity3d.com/450/Documentation/ScriptReference/Application.ExternalCall.html 자세한 설명은 여기서~

이걸로 클라이언트 (unity3D) 부분은 끝이 났다. 사실상 Unity 는 자신의 상태값만 서버에 보내주고 그 후 여러가지 값을 받아 처리하는 역활만 해준다. 

연결 실패 시 몇 초후 재연결 하는 안전장치도 구현하면 좋다.


UForm 통신 구현하기~! 서버 (WinForm)

자아 인제 가장 중요한 서버 부분이다.

지금 UForm 의 현상태는 클라이언트에서 "나 로딩 끝났고 서버 열어서 소켓 받아줘!" 하며 Application.ExternalCall 으로 서버에 통신을 보냈고 클라이언트의 상태값을 받아줄 서버를 구현해야한다.


먼저 Application.ExternalCall 을 받으려면 몇가지 작업을 거쳐야한다.

1
2
3
4
5
private void Form1_Load(object sender, EventArgs e)
{
    SetUnityClient(); 
}// http://seonbicode.tistory.com/
 
cs

1
2
3
4
public void SetUnityClient() //
{
    UnityForm.OnExternalCall += new _DUnityWebPlayerAXEvents_OnExternalCallEventHandler(TcpSet);   
} // http://seonbicode.tistory.com/
cs


먼저 Load 에서 OnExternalcall 을 인스턴스로 생성해주는 코드가 들어가있는 함수를 실행시켜줘야 합니다.


SetUnityClient 을 함수를 살펴보면 UnityForm 라는 것이 있는데, 자신이 선언한 AxUnityWebPlayerAX 의 Name 이다.

속성에서 간단하게 바꾸어 사용하자.



나머지 SetUnityClient 함수에 관련한 내용은 아래 링크에 서술되있습니다. 참고하시기 바랍니다. :

2015/07/10 - [잡다한 자료(번역)/WinForm+Unity3D] - WPF 포함 UnityWebPlayer 문제 해결 및 사용 정보


클라이언트 (unity3D) 가 로딩이 끝난 후 Application.ExternalCall("TcpSet", "프로퍼티값"); 를 하면 TcpSet 함수가 실행이 된다.

1
2
3
4
5
6
private void TcpSet(object sender, _DUnityWebPlayerAXEvents_OnExternalCallEvent e) 
{
    var vClient = e.value; // Unity가 보내준 프로퍼티 값
    TCPServer.DoInit(); // 서버 실행 함수
// http://seonbicode.tistory.com/
}
cs


TcpSet 이 실행되고 TCPServer.DoInit(); 이 실행된다. (여기서 TCPServer 는 필자가 작성한 TcpServer C# 이다.)


1
2
3
4
5
6
7
8
public void DoInit()
{
    Socket_pThread = new Thread(pStartServer); // Unity policy
    Socket_Thread = new Thread(ServerSet); //TcpServer
 
    Socket_pThread.Start(); // Unity policy Thread Start
    Socket_Thread.Start(); // TcpServer Thread Start
} // http://seonbicode.tistory.com/
cs


DoInit() 함수에서 가장 중요한 부분은 pStartServer (Unity policy) 이다.

UnityWebPlayer 는 보안상의 문제로 Unity policy server 를 통하지 않고 통신을 할 수 없도록 하였고, 자세한 설명, 설정 방법은 아래 링크에서 알아보자.

policy server : http://blog.naver.com/loolsasy/20161810693  (loolsasy)님의 블로그


이 후 서버 제작은 여러분의 아름다운 코드로 구현하시기 바랍니다. 

서버제작도 다 완료하셨다면 여러분의 눈앞에는 아름다운 구현된 UForm 을 보실 숫 있으실겁니다!!


마치며.....

허접한 내용의 글을 보시느라 수고하셨습니다. 사실 이 방식은 완벽한것은 아닙니다. Unity 와 WinForm 의 로딩차이도 사실 제가 소스를 잘못짜서 버그가 난것일수도 있으니까 말이죠... 

그래도 혹시나 구글링하여 이 글을 보시는 여러분들에게 작은 도움이나마 드리고자 이 글을 작성하였습니다. 마지막 3편은 아마 시간이 지난 후 올릴것 같습니다.


제 글을 봐주셔서 감사합니다~!


추가 내용

Visual Studio winForm <---> Unity WebPlayer OCX Works : 

http://forum.unity3d.com/threads/visual-studio-winform-unity-webplayer-ocx-works.33685/


Custom Unity3D Launcher [C# Tutorial] (유니티 런쳐 만들기) : 

https://www.youtube.com/watch?v=PiTnIc50tAA


(Unity3D [C#]) - Game Launcher Tutorial #1 :

https://www.youtube.com/watch?v=CemEZkT1yK8

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기