[Unity 게임 만들기] Unity Netcode 적용하기 1

lighteko·2024년 6월 22일

Unity 게임 만들기

목록 보기
4/11
post-thumbnail

참고영상

우선 기본적인 이동과, 회전을 구현해놓았는데, 게임 매커니즘도 구체화 되었기 때문에 본격적으로 멀티플레이를 적용하기 위해서
Unity Netcode for Game Objects를 채택했다.

영상을 참고해서 넷코드와 릴레이를 사용할 예정이다.
설치 과정은 영상이나 공식 문서를 참고 바란다.

Network Manager 생성

계층 탭에서 새로운 게임 오브젝트를 만들고, Network Manager 컴포넌트를 추가한다.

image.jpg1image.jpg2

Unity Transport를 선택하면 저렇게 컴포넌트 하나가 더 추가된다.
그대로 두고, Player 오브젝트를 Prefab으로 만든 후, Player Prefab 란에 삽입한다.
또,

Network Object, Network Transform 적용

Prefab으로 만들어진 Player 오브젝트에 Network Object 컴포넌트와, Network Transform 컴포넌트를 추가한다.
Network Transform은 서버에서 받은 Transform 정보를 적용해주는 컴포넌트로, 서버에 보내기 싫은 정보 (ex. 스케일)는 체크 해제 해주면 된다.

참고로, 최상단 오브젝트에 적용해주어야 한다. (Player)

기존 코드 Refactoring 하기

원래 Player라는 상위 오브젝트에서 하위 오브젝트로 Plane, 그리고 Main Camera가 있었고, Rotation 코드는 Plane에, 이동 코드는 Player에 넣어주어 카메라가 회전에 영향받지 않도록 구성했었다.

그런데, Netcode를 적용하면서 데이터를 송수신 받는 위치가 Player가 되었기 때문에, angle 변환과 이동 관련 코드를 모두 Player 쪽으로 옮겨줄 필요가 생겼다.

using UnityEngine;
public class Player : MonoBehaviour
{
    // Start is called once before the first execution of Update after the MonoBehaviour is created
    public float speed = 0;
    // Update is called once per frame
    void FixedUpdate()
    {
        MoveTowardsMouse();
    }
    void MoveTowardsMouse()
    {
        Vector2 worldMousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        Vector3 direction = ((Vector3)worldMousePosition - transform.position).normalized;
        Vector3 currentPosition = transform.position;
        transform.position = new Vector3(currentPosition.x + direction.x * speed, currentPosition.y + direction.y * speed, 0);
    }

}

이것이 기존의 Player 코드다. 보이다시피 angle 관련 코드는 Player에서 다루지 않았다.

그리고 아래가 Jet (과거 Plane이었는데 명칭을 바꿈) 의 코드였다.

using System;
using UnityEngine;
public class Jet : MonoBehaviour
{
    void FixedUpdate()
    {
        RotateToMouseCursor();
    }

    void RotateToMouseCursor()
    {
        Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        Vector3 direction = mousePosition - transform.position;
        float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
        transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle - 90));
    }
}

이렇게 Jet 에서는 기체 회전만 관여하고, Player에서 이동에 관여했다.

그러나 앞서 설명한 것 처럼 Netcode를 사용하면서 서버와 주고받는 오브젝트가 Player이므로, 모든 이동과 회전을 Player 한 곳으로 모아주게 되었다.

using UnityEngine;
using Unity.Netcode;
using Unity.Collections;

public class PlayerMovement : NetworkBehaviour
{
    // Start is called once before the first execution of Update after the MonoBehaviour is created
    public float speed = 0;
    private float angle = 0;
    public NetworkVariable<FixedString32Bytes> nickName = new();

    public override void OnNetworkDespawn()
    {
        if (!IsOwner) return;
        SendNickNameServerRpc($"Player {OwnerClientId}");
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        if (!IsOwner) return;

        Vector2 worldMousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        Vector3 direction = ((Vector3)worldMousePosition - transform.position).normalized;
        angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
        Vector3 currentPosition = transform.position;
        SendMovementServerRpc(currentPosition, direction, speed * 0.1f, angle); 
    }

    [ServerRpc]
    public void SendMovementServerRpc(Vector3 pos, Vector3 dir, float speed, float angle)
    {
        transform.position = new Vector3(pos.x + dir.x * speed, pos.y + dir.y * speed, 0);
        transform.Find("Jet").transform.rotation = Quaternion.Euler(new Vector3(0, 0, angle - 90));
    }

    [ServerRpc]
    public void SendNickNameServerRpc(string nickName) {
        this.nickName.Value = nickName;
    }   
}

이것이 Refactoring이 완료된 코드다.

Netcode를 적용하면서 MonoBehaviour를 상속하는 것에서 NetworkBehaviour를 상속하는 것으로 변경했고, FixedUpdate에서 모든 필요값들을 계산한 뒤, ServerRpc 함수로 (SendMovement) 값을 넘겨주어 서버와 상호작용하는 코드로 변경했다.

결과적으로 중복 계산이 사라졌고 (방향벡터 계산 등) 깔끔해졌다.

Parallel Sync

멀티플레이가 동작하는지 테스트해보고 싶다면 Parallel Sync를 사용해보는 것을 추천한다.
https://github.com/VeriorPies/ParrelSync.git?path=/ParrelSync
패키지 매니저에서 위 링크를 이용하여 설치하면 된다.

설치 후 상단바에 Parallel Sync 옵션이 하나 추가되는데, 그 옵션을 클릭한 후 Clones Manager를 선택하면 하나의 창이 열린다.
창에서 현재 프로젝트를 클론한 뒤 새로운 에디터로 실행하면 빌드 하지 않고 멀티플레이를 테스트해볼 수 있다.

Scene 실행 후 Network Manager의 Start Host 버튼을 누르면 호스팅이 시작된다.
Parallel Sync로 불러온 클론 프로젝트에서는 Start Client를 누르면 호스트의 세션에 접속된다.

0개의 댓글