XR플밍 - 10. XR 애플리케이션 개발을 위한 VR/AR 프로그래밍 - 개인 프로젝트(VR) VRGunRange 2일차 (6/13)

이형원·2025년 6월 13일
0

XR플밍

목록 보기
103/215

0. 들어가기에 앞서
VR 프로젝트는 그 어느 때보다도 버그와의 싸움이 많은 것 같다. 하지만 오늘은 꽤 성과가 있었다!

1. 2일차 작업 정리


작업량만 보면 사실 많지는 않지만, 그래도 꽤 큰 성과를 냈다. 사실상 사용 불가에 가까웠던 총알 파티클 이펙트를 사용할 수 있게 만들었기 때문이다.

  • 패턴 구사 - 오브젝트 풀 패턴, 싱글톤 패턴(단일맵 구성이라서 굳이 없어도 될 것 같지만 일단 구성했다)
  • 총알에 오브젝트 풀 패턴 적용
  • 총알 프리팹을 총알 파티클로 교체 (이게 제일 오래 걸렸다. 에셋 구성을 아예 다 뜯고 스크립트도 너무 비효율적으로 짜여 있어서 아예 스크립트부터 다시 짰다.)
  • 게임 매니저 추가 및 스코어 시스템 추가
  • 과녁과 총알 충돌 시 스코어 증가, 과녁이 내려가는 애니메이션 출력
  • 시작 UI 추가, 스코어 UI 추가
  • 각종 버그 수정 - 빌드 시에 발생한 버그 및 총 빠지는 이슈 수정

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

2.1 신규 문제 발생 - 에디터 상의 테스트와 빌드 시의 동작 불일치

빌드를 매일 해 보라는 강사님의 조언에 따라 빌드를 해 보았는데, 정말로 빌드를 하자마자 바로 버그가 발생했다.
분명 에디터 상에서는 총을 양손으로 잡을 수 있고 왼손으로 겨냥을 할 수 있는 부분이 잘 구현됐는데, 이상하게도 빌드를 하면 총기를 겨누는 부분이 적용이 되지 않고 그냥 양손으로 총기를 잡는 모션이 되는 것이다.
에디터 상에서는 정상 작동하니 이런 현상이 발생하는 원인을 찾기가 어려워 계속 빌드하면서 테스트할 수밖에 없었다.

이 과정에서 꽤나 도움이 되었던 정보가 아래 내용이다.

https://smilejsu.tistory.com/3323

XR Interaction Toolkit 중 Grab와 관련된 내용에 대해 상세하게 다룬 내용이다. 그리고 이 내용을 바탕으로 조합해본 결과 이와 같이 세팅해서 빌드까지 문제가 발생하지 않게 되는 걸 확인했다.

XR Grab Interactable, XR General Grab Transformer, 그리고 XR Single Grab Free Transformer

이렇게 3개를 조합하는 방식으로 빌드 상에서도 원하는 의도의 총기 양손 잡기 방식이 구현되었다.

2.2 에셋 적용 이슈 해결

에셋이 적용되지 않는 이슈에 대해서 계속 어떻게 해결해야 할지 고민이었는데, 정말 어이없는 방법으로 해결했다.
혹시나 에셋 자체가 문제가 있는 건지 다시 새 프로젝트를 만들어서 에셋을 실행시켜 봤는데, 잘 실행되는 것이었다.

아무리 생각해도 이상해서, 새 프로젝트와 설정이 비슷하게 만들어 보았다.

  1. URP를 삭제하고, Shader Graph를 다시 설치한다.
  2. 새로 씬을 만든다
  3. 해결 (???)

결론은 그냥 씬을 새로 파니까 해결이 됐다. 진짜 이유를 모르겠는데 그것만으로 해결이 되서 그냥 새 씬에다가 맵과 구성요소를 다 옮기고 작업을 시작했다.

이제 다음으론 총알 프리팹으로 오브젝트 풀 패턴까지 구현해 놓은 것을 그대로 파티클로 교체하는 작업을 해야 했다.
문제는 이 에셋을 만든 사람이 프로그래밍을 잘 하는 사람은 아닌 모양인지, 매우 비효율적인 코드로 총알 작동 방식이 되어 있었던 것이다.
실제로 유튜브 영상을 참고해서 에셋을 제작했다는 Readme 코멘트도 있었고 리뷰 중에서도 코드가 너무 비효율적이라는 리뷰가 있었다.

다행히도 에셋을 발사 - 날아가는 모션 - 충돌 후 파편 튀김 프리팹을 전부 다 따로 만들어놔서 어떻게든 커스텀이 가능하다는 것이었다. 결국 발사 모션을 따로 빼고, 날아가는 모션 - 충돌 후 파편 튀김을 하나로 묶은 다음 총알을 오브젝트 풀로 생성하고 쏘는 작업을 진행했다.

현재 상황에서 적용된 코드는 다음과 같다.

using DesignPattern;
using UnityEngine;

public class Shooter : MonoBehaviour
{
    [SerializeField] private ParticleBulletController m_bulletPrefab;
    private ObjectPool m_bulletPool;    

    [SerializeField] private GameObject m_muzzleFire;

    [SerializeField] private float speed;

    private Transform m_muzzle;
    private Rigidbody m_bulletRigid;

    // 오브젝트 풀 적용 가능한지 확인용 컴포넌트
    //[SerializeField] private MuzzleFire m_muzzleFire;
    // 오브젝트 풀 적용 가능한지 확인용 컴포넌트
    //private ObjectPool m_muzzlePool;

    private void Awake() => Init();

    private void Init()
    {
        m_muzzle = GetComponent<Transform>();
        m_bulletPool = new ObjectPool(transform, m_bulletPrefab);        
    }


    public void MuzzleFire()
    {
        GameObject muzzleFire = Instantiate(m_muzzleFire, m_muzzle.position, m_muzzle.rotation);
    }

    // Muzzle 발사 부분도 ObjectPool로 처리하고 싶었으나, Object Pool로 처리하면
    // 다시 Pop했을 때 모션 재생이 되지 않는 오류가 있음
    // 우선은 Instantiate로 처리하고 파괴하는 방식으로 처리
    /*
    public void MuzzleFire()
    {
        PooledObject muzzleFire = m_muzzlePool.PopPool() as MuzzleFire;
        muzzleFire.transform.position = m_muzzle.position;
    }
    */

    public void Fire()
    {
        PooledObject bullet = m_bulletPool.PopPool() as ParticleBulletController;
        bullet.transform.position = m_muzzle.position;
        bullet.transform.rotation = m_muzzle.rotation;
        Debug.Log(bullet.transform.position);
        m_bulletRigid = bullet.GetComponent<Rigidbody>();
        m_bulletRigid.velocity = m_muzzle.forward * speed;
    }
}

모든 발사 모션을 오브젝트 풀로 구성하는 것도 나쁘지 않은 방법이라 생각하여 시도했지만, 결국 발사 모션과 충돌 후 파편 튀김 모션은 Instantiate로 처리하고 총알 발사 부분만 우선적으로 오브젝트 풀 처리를 했다.

2.3 게임매니저 생성 및 UI 생성

게임매니저를 생성하고 우선은 스코어 저장과 상승 기능만 추가했다. 그리고 Start로 초기화를 하게 만들어서 UI 버튼으로 초기화 하는 방식을 만들 예정이다.

시작 시 띄우는 UI를 만들기 위해 월드 스페이스 단위의 UI들을 추가했다.

이 UI에서 버튼의 상호작용을 가능하게 하기 위해서는, 우선 레이어를 UI로 처리해주고 Tracked Device Graphic Raycaster만 추가하면 된다.

이와 같이 설정하면 UI 버튼을 컨트롤러로 누를 수 있게 된다.
다만 지금은 UI 전체가 상호작용할 수 있는 것처럼 인식이 되서 이 부분은 세부 조정할 예정이다.

3. 수정해야 할 점과 과제

3.1 (수정) 과녁이 누워있을 때에도 스코어가 올라감

이 부분은 금방 수정할 수 있는 내용이긴 한데, 아직 테스트 단계만 진행한다고 이 부분에 대한 작업이 안 되었다. 까먹지 않도록 조심하자.

3.2 (버그?) 총알을 연속 발사할 때 총알이 사라지는 버그

사실 아직 발사 쿨타임을 만들어 놓지 않아서 그다지 신경 쓰지 않아도 될 문제일 수도 있긴 하지만, 총알을 무지성으로 발사할 때 앞의 총알이 사라지는 버그가 있다 (충돌로 사라지는 것이 아닌, 총알 자체가 사라짐)
다만 이건 쿨타임을 반영하면 없어질 버그인지, 아니면 이후에도 나타나면 해결해야 할 버그인지 확인이 필요하다.

3.3 (구현) 게임 종료 구현

사실 VR 게임을 해 본 적이 없어서 게임 종료를 어떻게 구현해야 할 지 잘 모르겠긴 하지만, 플레이어 뒤쪽에 UI를 하나 더 배치해서 게임 종료를 구현할 지 고민중이다.

3.4 (구현) 내려간 과녁 다시 올리기 - 스테이지 개념 구현

지금은 연습 느낌으로 과녁에 총을 발사하는 부분만 구현했지만, 스테이지 개념을 반영해서 과녁이 랜덤하게 오르락 내리락 하면서 쏘는 방식을 구현해보려고 한다.

3.5 (구현/도전) 총을 양손으로 잡았을 때만 총 발사되도록 하기

지금은 총을 한 손으로 잡아도 발사가 되다 보니 왼손으로 겨냥하는 부분이 조금 불필요하게 느껴지고 총 발사 또힌 비현실적으로 느껴진다. 디테일을 위해서 해당 부분을 구현할 수 있을지 알아보자.

3.6 (구현/도전) 총을 잡는 컨트롤러를, 손으로 교체하기

컨트롤러를 손으로 바꿀 수 있는 에셋을 구했다. 이걸 적용시키면 훨씬 더 실감나는 게임을 할 수 있을지도 모른다.

3.7 (도전) 랭킹시스템 구현

최고기록을 기록할 수 있는 랭킹 시스템을 구현해보고자 한다.
다만 최고기록을 저장하는 건 그렇다 쳐도, 키보드를 구현할 수 있을지가 난감하다.

3.8 (도전) 총 장전 시스템 구현

총을 장전하는 시스템을 구현해보고자 한다. 소켓 기능을 쓰는 등의 방식으로 구현해야 한다는 건 알고 있으나, 앞서 해야 할 작업이 많은 관계로 우선순위를 뒤로 미뤘다.

profile
게임 만들러 코딩 공부중

0개의 댓글