Unity/Portfolio Daily Log

캐주얼 슈팅 액션 대전 게임 (모바일) - 8 포톤_4 피격 동기화

Korokke 2022. 7. 25. 12:06

주말동안 피격 동기화와 제자리 공격시 꾹 누르고 있어도 한 번만 공격되는 등의 문제 해결을 했다. 사소한 거라 후딱 구현하고 블로그에 정리를 하려고 했는데 예상치 못한 이슈로 오래걸려버렸다...

 

토요일에는 금요일에 발견한 문제를 해결했다.

 

문제 발생: 제자리에서 공격키를 누르고 있으면 로컬 상태에서는 제대로 공격이 계속 나가는데 리모트 상태에서는 처음 한 번만 공격이 나감(공격 애니메이션이 한 번만 작동됨). 

 

이 문제를 해결하기 위해서 공격 애니메이션을 불러오는 함수 RPC 처리를 했다.

 

기존의 Attack 함수

private void Attack()
{
        attackDir = input.GetAttackDirection();
        attackDir.Normalize();
        
        if (attackDir != Vector3.zero)
        {
            aniCtrl.OnAttack(lookDir);
            isAttack = true;          
        }
        else if (attackDir == Vector3.zero)
        {
            aniCtrl.ResetAttack();
            isAttack = false;      
        }
}

변경된 Attack 함수 밑 RPC용 함수 추가

private void Attack()
{
        attackDir = input.GetAttackDirection();
        attackDir.Normalize();
        
        if (attackDir != Vector3.zero)
        {
            isAttack = true;          
            PV.RPC("TempAttack", RpcTarget.AllBuffered, isAttack, lookDir);
        }
        else if (attackDir == Vector3.zero)
        {
            isAttack = false;      
            PV.RPC("TempAttack", RpcTarget.AllBuffered, isAttack, Vector3.zero);
        }
}

[PunRPC]
private void TempAttack(bool isAttack, Vector3 tempVec)
{
        if(isAttack)
            aniCtrl.OnAttack(tempVec);
        else
            aniCtrl.ResetAttack();
}

그리고 애니메이션 넘겨주는 게 중복이 될 수도 있기 때문에 애니메이션 뷰에서 공격 부분을 비활성화 했다. 

이렇게 토요일은 빠른 문제 해결로 편안 했는데...

 

일요일에는 피격 동기화 및 총알 동기화를 하려 했는데 총알 동기화에서 문제가 생겼다.

우선 피격 동기화는 이렇게 했다.

private void OnTriggerEnter(Collider other)
    {
        // 느린쪽에서 판정
        if(other.CompareTag("Player"))
        {
            if (other.GetComponent<PhotonView>().IsMine)
            {
                other.GetComponent<PhotonView>().RPC("SetDamage", RpcTarget.AllBuffered, attackPower);
            }          
        }
    }

1. 느린 쪽에서 판정을 하기 위해서 부딪힌 대상이 Player이고 photonview에서 IsMine일 때 RPC로 SetDamage를 불러서 양쪽 모두한테 자신이 맞았다는 것을 알린다. (적이 자신이 맞았을 때 데미지를 받았다는 것을 알려준다.)

 

그 다음 총알 동기화를 하려고 했는데 여기서 삽질을 엄청 한 것 같다. 

 

처음에는 MemoryPool에서 총알을 생성하는 것과 없애는 것을 RPC로 실행시키는 것을 시도했다.

 

하지만 이 총알들을 Disable할 때 MemoryPool에서 관리하는 ItemList에서 비교를 하는데 오류가 계속 뜨는 것이다.

 

당연히 서로 담는 리스트가 달라서 그럴 수밖에 없었는데 이걸 해결하겠다고 1차적으로 시간을 엄청 소비했다.  

 

그러다가 어차피 공격과 피격판정은 동기화 했으니 총알은 플레이어가 맞으면 사라지게 하면 되는 거 아닌가? 라는 생각이 들었다. 

 

그래서 RPC로 했던 걸 원래대로 돌리고 Player가 맞았을 때 Disable하는 부분에서 또 Null Reference가 떴다.

private void OnTriggerEnter(Collider other)
    {
        // 느린쪽에서 판정
        if(other.CompareTag("Player"))
        {
            if (other.GetComponent<PhotonView>().IsMine)
            {
                other.GetComponent<PhotonView>().RPC("SetDamage", RpcTarget.AllBuffered, attackPower);
            }          
            if (this.gameObject.activeSelf)
            {
                DisableBullet(this.gameObject);
            }
        }
    }

그리고 플레이어가 안 맞더라도 1초가 지나면 Disable이 돼야 하는데

 IEnumerator LifeCycle()
{
        yield return new WaitForSeconds(1);
        if (this.gameObject.activeInHierarchy) 
        {
            DisableBullet(this.gameObject);
        }        
}
private void DisableBullet(GameObject gameObject)
{
        trailRenderer.Clear();
        memoryPool.DeactivatePoolItem(gameObject);
}

여기에서도 오류가 뜬다.

오류 로그를 보니 memoryPool.DeactivatePoolItem을 하는 부분에서 Null Reference가 뜨는 것이다.

 

분명 Awake에서 transform.root.Getcomponent<MemoryPool>(); 을 가지고 왔었다. 그런데도 Null이 떠서 transform.root.gameobject.Getcomponent<MemoryPool>();로 시도를 했는데 또 Null이 뜨는 것이다.

이후 Start에서도 해보고 GetComponentInParent도 해보고 OnEnable에서 null일경우 가지고 가지고 오는코드도 시도해 봤는데 안됐다. Try Catch로 오류 뜰 경우 다시 한 번 시도하는 것도 했는데 다 소용이 없었다.

이걸로 시간을 엄청 소비했다. 

구조가 잘 못 됐을 수도 있으니 다시 확인해보고 확인해봐도 MemoryPool은 transform.root가 맞다... 근데 왜 컴포넌트를 못 가져오는지 이해를 할 수가 없었다. 물론 지금도 이해가 안 된다.

해당 문제는 성능상 기피했던 GameObject.Find로 해결하긴 했는데 이유를 모르니까 답답하다...

 

어쨌든 발생한 문제는 다 해결하긴 했는데 약간 찜찜함이 많이 남는 것 같다. 꺄르륵!