Carrot
본문 바로가기
Unity/멋쟁이사자처럼 부트캠프

[천도컴퍼니] 플레이어가 사망했을 때 타 플레이어가 업어가는 로직 구현 (4)

by 독기품은토끼 2025. 12. 1.
✅ 오늘의 백로그
1. 버그 해결!!
- 시체 내려두기 안되는 현상
- 아이템과 시체 동시에 들지 못하게 하기

가능하다면
- 시체 운반 시 걷는 애니메이션 실행되지 않는 현상
- 클라이언트 위치 동기화 한 프레임씩 늦는 거 해결

1. 시체 내려놓기

호스트, 클라이언트 모두 시체를 제대로 운반하는 거 까지 동작은 되는데,

시체를 다시 바닥에 내려놓으려고 하니 제대로 동작되지 않는다.

 

 

당연히 동작되지 않는 이유가 있었다..!

바로 Drop 함수를 호출하는 부분이 아무데도 없었기 때문..!

 

public void OnDropItem(InputValue value)
{
    if (isPaused || !HasInputAuthority) return;

    // 시체 내려놓기
    var corpseHandler = GetComponent<CorpseCarryHandler>();
    if (corpseHandler != null && corpseHandler.IsCarryingCorpse)
    {
        // PlayerInteraction에서 쏘고 있던 Ray 결과 활용
        Vector3 dropPos;
        var interaction = GetComponent<PlayerInteraction>();

        if (interaction != null && interaction.HasValidHit)
        {
            // 카메라 Ray가 맞은 위치에 시체 내려놓기
            dropPos = interaction.HitInfo.point;
        }
        else
        {
            dropPos = dropPosition.position;
        }

        corpseHandler.TryRequestDrop(dropPos);
        return; // 시체만 내려놓고 아이템 드랍되지 않도록
    }

    Vector3 pos = dropPosition.position;
    Quaternion rot = dropPosition.rotation;
    Debug.Log($"[클라이언트] 아이템 드랍 시도. dropPosition: {pos}");
    RPC_DropItem(CurrentSlotIndex, pos, rot);
}

 

시체를 내려놓을 위치는

기존에 계속 쏘고있었던 Ray를 활용해주어 그 Ray가 향한 곳에 떨어지도록 하였다.

 

 

그런데 이게 무슨 일인가 ㅋ.ㅋ...ㅠ

시체를 내려놓으니 죽을 때 실행되는 애니메이션이 다시 실행되는 문제가 있었다...

 

 

이렇게 해도 될지?? 모르겠지만..

시체가 누워있는 프레임만 클립으로 갖고와서 시체를 내려놓을 때 애니메이션 실행 없이 바로 눕도록 해주었다.

 

그런데 이렇게 해주니까

다시 시체를 들어올릴 때 Beinh Carried 애니메이션이 실행되어야 하는데

무슨 이유에서인지 애니메이션이 실행되지 않는다아..

 

 

bool 값을 제대로 못가져와서 그런가? 하고 로그도 찍어봤는데

정상적으로 작동된다..ㅜ

애니메이터에서 화살표를 잘못 이어준 것도 아니다..

 

한참을 찾아보다가 결국 모르겠어서

애니메이터 클립 지우고 다시 시도해봤는데 또 정상적으로 작동된다..^^ 미칠지경

 

2. 아이템 동시에 들지 못하도록 예외처리

이제 시체를 들으면 기존에 들고 있던 아이템이 인벤토리 안으로 들어가고,

바닥에 있는 아이템을 줍지 못하도록 막아주려고 한다.

 

public void ApplyCarry()
{
    var corpseHandler = GetComponent<CorpseCarryHandler>();
    if (corpseHandler != null && corpseHandler.IsCarryingCorpse)
        return;
}

 

우선 인벤토리 매니저에서 시체를 들고 있으면 바로 return으로 빠져나가게 해서

아이템 줍기, 사용 등 아이템 관련 상호작용이 안되도록 막아주었다.

 

흠 근데 내가 원하는 구조는

아이템을 들고 있는 상태에서 > 시체를 들면 > 들고 있던 아이템이 인벤토리 슬롯으로 들어가고 > 손에는 시체만 있도록

이렇게 하고싶은데

지금은 아이템 들은 상태에서 시체를 들면 아이템이랑 시체 둘다 들고있다..

그리고 여전히 휠로 아이템 슬롯을 바꾸는 것도 가능하다..!!

정말 사용, 줍기만 안되고 나머지는 다 되는 상황 ^-^

 


 

어차피 잘 안되는거 지금 ApplyCarry를 구현해준 부분은 너무 의존도가 높으니까 이걸 좀 바꿔주어야겠당

 

- CorpseCarryHandler

이 스크립트는 플레이어가 시체를 들고 있냐/아니냐 상태를 관리하고 > 네트워크 동기화 하고 > 애니메이션까지 관리

=> 그러니까 시체 운반 자체를 담당하고 있고

- InventoryManager

이 스크립트는 인벤토리 슬롯, 장착, 손 모델, 아이템 사용/줍기, 휠 스크롤 등

플레이어의 손과 아이템에 대한 것만 담당하고 있으니

 

인벤토리 매니저가 직접 ApplyCarry 함수 호출해서 시체 들고있냐 여부를 파악하지말고

(나중에 문 여닫이 등 여러 상호작용과의 충돌도 있을테니) 구독형태로 좀 바꿔주려고 한다.

 

// 아이템 사용/줍기 가능 여부
private bool _isEquipBlocked = false;

 

인벤토리 매니저에서 아이템 사용/줍기 가능 여부를 체크하는 변수를 선언해준 다음

 

/// <summary>
/// 플레이어 손 사용 가능/불가 알리기
/// 시체 들고있을 때에는 상호작용하지 못하도록 하기 위함
/// </summary>
public void SetEquipBlocked(bool blocked)
{
    _isEquipBlocked = blocked;

    // 휠 동작
    SetScrollPaused(blocked);

    // 현재 슬롯의 시각적 상태 다시 계산
    UpdateHeldItemVisuals(CurrentSlotIndex, CurrentSlotIndex);
}

 

외부 클래스에서 이 값을 제어해서

휠 동작을 막고, 손에 든 아이템 모델을 끄고, 애니메이션을 맨손처럼 바꾸고, 아이템 줍기/사용 등 모두 막아버리게 바꿔주겠다.

 

[시체를 들었을 때]

public bool IsCarryingCorpse => CarriedCorpse != null;

 

이제 플레이어가 시체를 들면

CorpseCarryHandler가 TryRequestCarry() 로 시체 운반을 시작하고

CarriedCorpse 값이 true가 된다.

 

public override void Render()
{
    bool nowCarrying = IsCarryingCorpse;

    if (nowCarrying != _prevIsCarrying)
    {
        _prevIsCarrying = nowCarrying;
        ApplyEquipBlock(nowCarrying);
    }
}

 

각 클라이언트에서 Render을 매 프레임마다 호출시켜서

이전 프레임 값과 비교해서 상태가 바뀌었는지 감지한다음

시체를 들었으면 (true이면) ApplyEquipBlock(true)를 호출한다.

 

private void ApplyEquipBlock(bool isCarrying)
{
    if (_inventory == null)
        return;

    _inventory.SetEquipBlocked(isCarrying);
}

 

여기서 이제 인벤토리 매니저에 나 시체들고 있다! 여부를 넘겨줄 것이다

 

[손에 들려있는 아이템 사라지기]

bool showNew = !_isEquipBlocked;

if (newIndex >= 0 && newIndex < inventorySize)
{
    if (_thirdPersonInstances[newIndex] != null) _thirdPersonInstances[newIndex].SetActive(showNew);
    if (HasInputAuthority && _viewModelInstances[newIndex] != null) _viewModelInstances[newIndex].SetActive(showNew);
}

UpdateAnimatorAndHands();

 

시체를 들고있으면 showNew는 false로 만들어서 손에 들고있는 아이템을 모두 SetActive(false)로 변경하여

손에 들려있는 아이템이 없어보이게 바꿔주고

 

[애니메이션 / 손 모델 정리]

int animType = (data == null ? 0 : data.animationID);

// 손이 막혀 있으면 애니메이션은 “맨손”처럼
if (_isEquipBlocked)
    animType = 0;

playerAnimator.SetInteger("EquippedItemType", animType);
// 손이 막혀 있으면 Hand 모델 자체를 꺼버리기
viewModelHandsObject.SetActive(hasItemInSlot && !_isEquipBlocked);

 

기존에 아이템을 들면 손이 보이던것도 보이지 않게해주었다.

 

if (_isEquipBlocked) return;

 

마지막으로 OnUseItem(), PickUpItem(), RPC_useItem()에서

이 조건문을 넣어주어서 아이템 사용, 줍기도 막아주었다.