[이전 포스팅]
2023.01.13 - [programming] - 유니티 UDP 소켓 통신 구현하기 - 예제 프로젝트 소개 <1>
이 포스팅에서는 유니티에 UDP 서버를 구현하고
수신한 UDP 데이터를 이용해 게임 오브젝트를 이동시키는 방법에 대해 설명한다
유니티 씬 만들기
먼저 유니티 게임 씬에 Plane 1개, Sphere 1개를 생성한다
* Sphere position: (x: 0, y: 0.5, z:0)로 수정
* Plane scale: (x: 100, y: 100, z:100)로 수정
Sphere에 물리엔진을 적용하기 위해 인스펙터에서 Rigidbody를 추가한다
(이대로 Play 하면 Sphere가 Plane위에 가만히 놓여있게 된다)
JSON 데이터 형식 정의하기
일반적으로 서버에서 클라이언트로 데이터를 보낼 때 사용하는 양식. 클라이언트가 사용하는 언어에 관계없이 통일된 데이터를 주고받을 수 있도록, 일정한 패턴을 지닌 문자열을 생성해 내보내면 클라이언트는 그를 해석해 데이터를 자기만의 방식으로 온전히 저장, 표시할 수 있게 된다. (나무위키)
이번 샘플 프로젝트에서는 정-말 단순한 형식으로 JSON 데이터를 정의했다 (key 1개)
* KEY: "direction"
* VALUE: "up", "down", "left", "right"
{
"direction":"up"
}
이제 파이썬에서 위처럼 정의된 JSON 문자열을 만들어 보내면, 유니티에서 잘 파싱만 하면 된다
유니티 C# 스크립트 작성하기
우선 C# 파일 두 개를 만든다 (SphereManager.cs, UdpManager.cs)
SphereManager.cs
SphereManger.cs 스크립트는 Sphere의 컴포넌트에 추가한다
(Sphere 인스턴스가 생성될 때 Start()가 호출되고, 매 프레임마다 Update() 함수가 호출됨)
간략히 설명하면
Sphere 인스턴스가 생성될 때 Start()가 호출되며 아래와 같은 동작을 수행한다
1. UDPManager udp_manager = new UdpManager("127.0.0.1", 50002); // UDP Manager 생성자 호출
2. udp_manager.initilaize(); // UDP 소켓 리시버 초기화
3. udp_manager.SetMessageCallback(new CallbackDirection(OnDirection)); // UDP 소켓 수신 시 동작 함수 전달
UDPManager에 Sphere의 방향을 바꾸는 OnDirection 함수를 전달해서
UDPManager가 UDP 데이터를 수신할 때마다 OnDirection 함수를 호출하도록 구현하였다
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SphereManager : MonoBehaviour
{
public float speed = 5f;
private Rigidbody characterRigidbody;
float inputX, inputZ;
void Start()
{
Debug.Log("Start ShpereMove");
characterRigidbody = GetComponent<Rigidbody>();
UdpManager udp_manager = new UdpManager("127.0.0.1", 50002); # UDP 서버 주소, 포트번호
udp_manager.Initialize();
udp_manager.SetMessageCallback(new CallbackDirection(OnDirection));
}
void Update()
{
Vector3 velocity = new Vector3(inputX/3, 0, inputZ/3);
velocity *= speed;
characterRigidbody.velocity = velocity;
}
void OnDirection(JsonData message)
{
string direction = message.direction;
Debug.Log("CharacterMove : " + direction);
switch (direction)
{
case "up":
inputZ = 1f;
inputX = 0f;
break;
case "down":
inputZ = -1f;
inputX = 0f;
break;
case "right":
inputX = 1f;
inputZ = 0f;
break;
case "left":
inputX = -1f;
inputZ = 0f;
break;
}
}
}
UdpManager.cs
UdpManager에 IP주소와 포트번호 ( _IpAddr, _Port)를 할당하여 초기화하면 (Initilalize() 함수 호출)
새로운 Thread에서 ListenForIncommingRequest 함수를 호출한다
ListenForIncommingRequest() 함수에서는
* UDP 소켓으로부터 byte array를 받아오고 (byte[] bytes = listener.Receive(ref groupEP);)
* byte array를 JSON 형식의 데이터로 파싱한다 ⭐⭐⭐⭐⭐ (var json_data = GetJsonFromByte(bytes);)
* 마지막으로 SphereManager에서 전달한 OnDirection 함수를 호출한다 (MessageHandler(json_data);)
cf. JsonData 클래스는 위에서 정의한 JSON 형식에 맞게 작성하였다.
* KEY: direction
* Value: string
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Newtonsoft.Json;
[System.Serializable]
public class JsonData
{
public string direction { get; set; }
}
public delegate void CallbackDirection(JsonData message);
public class UdpManager
{
public string _IpAddr = "127.0.0.1";
public int _Port = 50002;
CallbackDirection _CallbackDirection;
#region private members
private Thread ListenerThread;
#endregion
public UdpManager(string IpAddr, int Port) {
_IpAddr = IpAddr;
_Port = Port;
}
public void Initialize() {
// Start TcpServer background thread
ListenerThread = new Thread(new ThreadStart(ListenForIncommingRequest));
ListenerThread.IsBackground = true;
ListenerThread.Start();
}
void ListenForIncommingRequest() {
Debug.Log("Start Server : " + _IpAddr + ", " + _Port);
UdpClient listener = new UdpClient(_Port);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, _Port);
try {
while (true){
byte[] bytes = listener.Receive(ref groupEP);
// Debug.Log(Encoding.ASCII.GetString(bytes, 0, bytes.Length));
var json_data = GetJsonFromByte(bytes);
MessageHandler(json_data);
}
} catch (SocketException e) {
Debug.Log("SocketException " + e.ToString());
} finally {
listener.Close();
}
}
public JsonData GetJsonFromByte(byte[] data) {
string JsonString = Encoding.UTF8.GetString(data);
Debug.Log(JsonString);
var JsonData = Newtonsoft.Json.JsonConvert.DeserializeObject<JsonData>(JsonString);
return JsonData;
}
public void SetMessageCallback(CallbackDirection callback)
{
if (_CallbackDirection == null) {
_CallbackDirection = callback;
} else {
_CallbackDirection += callback;
}
}
private void MessageHandler(JsonData json_data)
{
if (_CallbackDirection != null) {
_CallbackDirection(json_data);
}
}
}
유니티 끝
하지만 이대로 Play 해보아도 여전히 Sphere가 가만히 놓여있을 뿐 아무런 동작을 하지 않는다
UDP 데이터가 오지 않기 때문에..
UDP 데이터를 송신하는 클라이언트를 구현해야 하는데
UDP 클라이언트는 python과 C++로 한 번 구현해보았다
(계속)
2023.01.13 - [programming] - 유니티 UDP 소켓 통신 구현하기 - 파이썬 UDP 클라이언트 예제 코드 <3>
2023.01.13 - [programming] - 유니티 UDP 소켓 통신 구현하기 - C++ UDP 클라이언트 예제 코드 <4>
'💻 programming > unity' 카테고리의 다른 글
유니티 UDP 소켓 통신 구현하기 - C++ UDP 클라이언트 예제 코드 <4> (2) | 2023.01.13 |
---|---|
유니티 UDP 소켓 통신 구현하기 - 파이썬 UDP 클라이언트 예제 코드 <3> (0) | 2023.01.13 |
유니티 UDP 소켓 통신 구현하기 - 예제 프로젝트 소개 <1> (0) | 2023.01.13 |
[유니티] WebGL 빌드에러: Unable to parse Build/Build.framework.js.gz! (0) | 2022.12.09 |
[유니티] WebGL 빌드에러: Getting System.ComponentModel.Win32Exception (2) (2) | 2022.12.09 |
댓글