XR플밍 - 12. UnityEngine3D 네트워크 프로그래밍 - 네트워크 프로젝트 Round5 9일차 (8/1)

이형원·2025년 8월 1일
0

XR플밍

목록 보기
152/215
post-thumbnail

1. 금일 한 업무 정리

어제 저녁부터 시작한 작업으로 캐릭터 애니메이션 만드는 작업을 했는데, 어려워서 생각보다 오래 걸릴 거라 생각했던 작업이 하루 내로 끝낼 수 있었다.

  • 카드 선택에서의 캐릭터 몸통 및 팔 애니메이션을 구성
  • 캐릭터가 카드를 플립할 때 해당 카드를 가리키고, 가리키고 있는 카드의 라이브 애니메이션만 재생되도록 설정함.

2. 문제의 발생과 해결 과정

2.1 팔 애니메이션의 구성

몸통의 움직임은 간단하게 DOTween으로 구성했다. 하지만 팔의 구성의 생각보다 까다로울 것으로 생각되었다.

이에 따라 방법을 시도하면서 결과적으로 채택한 방법에 대해 알아보고자 한다.

  1. 각종 Joint의 사용

이전에 로프를 구성했을 때 사용했던 Hinge Joint나, Character Joint 같은 것을 활용해 보았다. 하지만 해당 방식을 사용해 보니 정말 징그러운 움직임을 보이는 것을 확인했다.

더군다나 관절이 끊기거나 부자연스럽게 이동하는 방식 때문에, 다른 방법을 고민해보기로 했다.

  1. 곡선을 그리는 방법? 베지어 곡선과 Spline

베지어 곡선은 컴퓨터 그래픽스에서 곡선을 그리는 방식으로 사용되는 방식이다. 그림판에서도 이런 방식으로 곡선을 그린 적이 있었는데 거의 비슷한 방식으로 보인다.
유니티에서 해당 기능을 직접 구현할 수도 있고, 여기서 유니티 레지스트리 기능 중에서 Spline이란 이름으로 곡선을 그릴 수도 있다.

Splines은 곡선이나 트랙 같은 것을 사용하는 데 사용될 수 있는 패키지이다. 그냥 곡선을 그릴 수도 있고, Closed - 시작과 끝이 연결된 곡선도 만들 수 있으며 레이싱 게임의 트랙 만들기 등에서도 활용될 수 있다.

  1. Spline의 기능을 어떻게 활용할 것인가.

이제 곡선을 그리는 기능 자체는 알게 되었지만, 문제는 하나 더 있다. 이런 Splines를 이용해서 팔 같은 것을 구현한 예제는 찾을 수가 없었기 때문에 맨땅에 헤딩하면서 방법을 찾을 수밖에 없었다.

해당 패키지에서 제공하는 Example 씬과 다른 여러 유튜브 강의 등에서 확인한 내용 등을 종합하여, 이와 같이 만들었다.

우선 팔을 만든다. 여기에서 Spline Extrude 옵션이 해당 곡선을 게임 뷰와 같이 시각적으로 보이는 구의 집합으로 만들어준다. 그 다음, 팔을 움직이는 스크립트를 작성했다.

using UnityEngine;
using UnityEngine.Splines;

public class CardSceneCharacterRightArm : MonoBehaviour
{
    [SerializeField] Transform shoulderTransform;
    [SerializeField] Transform currentHandTarget;
    [SerializeField] Transform[] cardsTransforms;

    private SplineContainer splineContainer;
    private Spline spline;
    private BezierKnot shoulderKnot;
    private BezierKnot handKnot;
    int targetCardNum = 3;

    private void Start()
    {
        splineContainer = GetComponent<SplineContainer>();
        spline = splineContainer.Spline;
    }

    void Update()
    {
        if (splineContainer == null || currentHandTarget == null || shoulderTransform == null) return;                

        shoulderKnot.Position = shoulderTransform.position;
        currentHandTarget.position = Vector3.Lerp(currentHandTarget.position, cardsTransforms[targetCardNum].position, Time.deltaTime * 10f);
        handKnot.Position = splineContainer.transform.InverseTransformPoint(currentHandTarget.position);

        spline.SetKnot(0, shoulderKnot);
        spline.SetKnot(2, handKnot);

        Vector3 mid = Vector3.Lerp(shoulderKnot.Position, handKnot.Position, 0.5f);
        mid += new Vector3(1, -1) * 1f;
        spline.SetKnot(1, new BezierKnot(mid));
    }

    public void SelectCard(int cardNum)
    {
        if (cardNum == 2) targetCardNum = 0;
        else if (cardNum == 3) targetCardNum = 1;
        else if (cardNum == 4) targetCardNum = 2;
        else targetCardNum = 3;
    }
}

여기서 유의해야 할 부분은 어깨 트랜스폼과 손 트랜스폼을 다르게 처리했다는 부분이다. 어깨 트랜스폼의 경우 직접적으로 해당 트랜스폼을 연결함으로서 월드 스페이스 상의 좌표를 참고하기 때문에, 캐릭터가 들썩일때마다 움직이게 된다. 손의 경우 고정된 좌표를 반환해야 하므로, 타겟 위치를 float3으로 변환하여 Knot을 설정해주어야 한다. 이와 같이 설정하면, 팔이 손의 위치가 변경될때마다 자연스럽게 움직이게 할 수 있다.

2.2 카드와의 연동 작업

카드를 손으로 집는 기능과 카드의 플립, 애니메이션 기능을 연결해주면 된다. 해당 과정 자체는 어렵지 않지만, 다른 사람의 코드를 건드려야 하는 문제 때문에 다소 억지스럽게만 우선 연결했다.

최종적으로 나온 결과물은 다음과 같다.

3. 개선점 및 과제

3.1 게임 사이클 디자인 변경

어제자 제출했던 프로토타입에 대한 피드백을 받았다. 게임의 디테일이나 폴리싱 작업이 잘 되어 있어 퀄리티가 높다는 점은 좋게 평가된 부분이었지만, 프로토타입인데 게임의 한 사이클이 제대로 작동되지 않은 것이 보완해야 할 점으로 지적되었다. 이는 카드 시스템의 구현이 늦어진 점이 있었으며, 비동기 로딩 시스템의 구현이 늦어지는 바람에 한 사이클을 돌리는 게임을 구성하지 못했다. 이에 따라 어떻게 한 사이클의 게임을 만들 것인가에 대한 논의가 오갔다.
팀장이 처음 게임 사이클 방식을 비동기 로딩 방식으로 디자인했던 이유는 네트워크적으로 씬을 초기화해주는 작업이 있어야지 문제가 덜 발생할 것이라고 생각했기 때문이다. 하지만 우리 게임은 엄연이 따지면 이펙트가 좀 많이 들어기간 해도 씬에 데이터 누적이 부담되는 퀄리티의 게임은 아니며, 비동기 로딩 방식으로 게임을 만드는 것 자체가 난이도가 있는 작업이기 때문에 해당 방식 자체가 오버 엔지니어링이라고 판단했다.
따라서 기존에 게임 씬과 카드 선택 씬을 따로 나누었던 방식에서 대신 두 개의 씬을 하나의 씬으로 합치는 것으로 결론이 내려졌다.

이에 따라서 내가 해야 할 일에 추가가 된 것이 다음과 같다.

3.2 맵과 UI 수정

  • 기존에는 씬이 전환된다고 생각했기 때문에 다음 라운드의 맵이 생성되는 방식을 OnEnable로 처리했었다. 하지만 이제는 한 씬에서 처리하므로 해당 방식을 변경하여 맵을 3라운드 분량으로 생성한 후 1라운드 맵만 활성화시키는 방식을 사용해야 한다.

  • UI적 실수를 발견했다. 3판 2선승제로 한 라운드의 승리가 결정되고, 전체 라운드에서 3판 2선승제로 진행해야 한다면, 지금 이 UI는 잘못된 것이다.

    이건 5판 3선승제의 UI니까 점수칸을 하나 줄여야 한다. 아직 맵이 5개밖에 없기도 하고, 5판 3선승제로 하면 이론적으로 맵이 15개가 로딩되어야 하기 때문에 부담도 크고 지루할 것이다. 이에 따라 우선은 3판 2선승제로 9개의 맵만 로딩하는 방식으로 진행하고, 스케일을 키우려면 키우는 것으로 하기로 했다.

3.3 동기화 부분

동기화 부분은 플레이어 데이터와 연동이 된 이후로 진행이 가능한 부분이지만, 우선적으로 동기화 부분에 대해서 테스트를 진행하기로 했다.

3.4 폴리싱

profile
게임 만들러 코딩 공부중

0개의 댓글