JS/TIL(Today I Learned)

2025-02-13 <최종 프로젝트 D-29> 이동동기화 핸들러 클라이언트에 적용하기

프린스 알리 2025. 2. 13.

마을에 입장하자마자 이동할 때(첫 클릭)

 

왠지는 모르겠는데 폴리곤을 찾아내지 못한다. 분명 같은 NavMesh 데이터를 가지고 있을 텐데 어떻게 가능한 걸까? 디버그 터미널을 실행시켜보았다.

 

 

가장 처음 움직일 때 end 포인트(클라이언트에서 클릭한 지점)의 값이 어째선지 (0, 0, 0)으로 들어오는 중이다.

두번째 이동 지점을 클릭했을 때

 

 

보다시피 제대로된 값이 들어온다. 클라이언트로부터 수신받는 첫 좌표가 잘못 된 게 확실하기 때문에 클라이언트에서 로직을 다시 살펴보았다.

// 왼쪽 마우스 버튼을 눌렀을 때 (Input.GetMouseButtonDown(0))
// UI 요소를 클릭하지 않았을 경우만 실행 (!eSystem.IsPointerOverGameObject())
// 마우스 위치에서 3D 광선(Ray)을 발사하여 충돌 지점을 찾음 (Physics.Raycast(...))
// 충돌한 위치로 NavMeshAgent를 이동시킴 (agent.SetDestination(rayHit.point);
private void HandleInput()
{
        if (Input.GetMouseButtonDown(0) && !eSystem.IsPointerOverGameObject())
        {
                if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out rayHit))
                {
                        agent.SetDestination(rayHit.point);
                        var movePacket = new C_Move
                        {
                                StartPosX = transform.position.x,
                                StartPosY = transform.position.y,
                                StartPosZ = transform.position.z,
                                TargetPosX = rayHit.point.x,
                                TargetPosY = rayHit.point.y,
                                TargetPosZ = rayHit.point.z
                        };

                        GameManager.Network.Send(movePacket);
                }
        }
}

역시나 클라이언트에서 실수가 있었다. 함수 실행 위치를 if문 내부로 옮기니까 문제 없이 돌아간다.

초기 스폰 좌표 오류

초기 스폰 좌표가 잘못되어서 게임이 시작되지 않는 문제가 발생했다.
=> NavMesh 위의 가장 가까운 좌표를 검색하고, 존재하지 않는다면 초기 스폰 좌표를 수동으로 맞춰주기로 결정

public Player CreatePlayer(PlayerInfo playerInfo, Vector3 spawnPos)
    {
        string playerResPath = playerDb.GetValueOrDefault(playerInfo.Class, DefaultPlayerPath);
        Player playerPrefab = Resources.Load<Player>(playerResPath);

        // NavMesh 위의 가장 가까운 위치 찾기
        Vector3 validatedSpawnPos = GetNearestNavMeshPosition(spawnPos, 3.0f);

        var player = Instantiate(playerPrefab, validatedSpawnPos, Quaternion.identity);
        player.Move(validatedSpawnPos, Quaternion.identity);
        player.SetPlayerId(playerInfo.PlayerId);
        player.SetNickname(playerInfo.Nickname);

        if (playerList.TryGetValue(playerInfo.PlayerId, out var existingPlayer))
        {
            playerList[playerInfo.PlayerId] = player;
            Destroy(existingPlayer.gameObject);
        }
        else
        {
            playerList.Add(playerInfo.PlayerId, player);
        }

        return player;
    }

    // NavMesh 위에서 가장 가까운 위치를 찾는 함수
    private Vector3 GetNearestNavMeshPosition(Vector3 position, float maxSearchDistance)
    {
        NavMeshHit hit;
        if (NavMesh.SamplePosition(position, out hit, maxSearchDistance, NavMesh.AllAreas))
        {
            return hit.position; // NavMesh 위의 가장 가까운 위치 반환
        }
        else
        {
            Debug.LogWarning("NavMesh 위의 위치를 찾을 수 없음, 기본 안전한 위치 반환");
            return new Vector3(-5, 1, 137); // NavMesh가 있는 기본 안전한 위치로 변경
        }
    }

앞으로의 개선사항

  • C_Location 패킷이 현재 0.01초마다 전송되고 있는데… 이걸 어케든 수정해야 한다.
  • C_Move 패킷이 도착했을 때 S_Move로 도착 지점을 브로드 캐스트 => 나를 제외한 플레이어 오브젝트를 Vector3.Lerp를 사용해서 움직이기
  • 0.5초마다 C_Location 패킷을 전송하고 위치 검증 문제가 없으면 빈 패킷 전송. 있으면 에러 발생
  • minDistance : NaN << 이거 고치기

댓글