본문 바로가기
IT

[유니티/VR 콘텐츠 제작] 4. VR Controller와 트리거 상호작용 물체 만들기 (레이저 총 만들기)

by 배애앰이 좋아 2024. 2. 6.
반응형

 

목표 : 유니티 VR 콘텐츠 제작하는 방법에 대해 알아봅시다.

 

https://www.youtube.com/watch?v=pm9W7r9BGiA&list=PLpEoiloH-4eM-fykn_3_QcJ-A_MIJF5B9&index=3

영상을 기반으로 작성된 글입니다.

사용한 유니티 버전 : 2022.3.16f
사용한 VR 기기 : meta quest 3

 

 

1. VR Controller와 트리거 상호작용 물체 만들기 (레이저 총 만들기)

 

해당 주소 아래에 있는 총 prefab 을 꺼낸 후 스크립크를 아래와 같이 붙여서 설정해줍니다. 

여기서 collider를 추가하는 이유는 실제 총의 collider 가 붙여있는 오브젝트들을 넣어주었으며, 

 

attach transform 에는 총을 집었을 때, 손 위치가 손잡이 부분에 갈 수 있도록 새로운 객채를 만든 후 위치를 조정해주었습니다. 참고로 이때 x 가 0이 아니면 양손 다 집어지지 않는 문제가 있으니 X 값은 0으로 바꿔줍니다.

 

 

아래는 총에 대한 스크립트입니다. 총 오브젝트에 붙여줍니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.Interaction.Toolkit;


public class MeteorPistol : MonoBehaviour
{
    public ParticleSystem particles;

    // Start is called before the first frame update
    void Start()
    {
        XRGrabInteractable grabInteractable = GetComponent<XRGrabInteractable>();
        // 사용자가 트리거를 눌렸을 때
        grabInteractable.activated.AddListener(x => StartShoot());
        // 사용자가 트리거를 눌렸다가 놓았을 때
        grabInteractable.deactivated.AddListener(x => StopShoot());
    }

    public void StartShoot(){
        particles.Play();
    }

    public void StopShoot(){
        // 공중에 있는 파티클 입자 모두 제거
        particles.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
    }
}

 

 

그리고 위에서 실행시킬 파티클을 아래 주소에서 꺼내서 위치를 적당히 맞춰준 후 스크립트 안에 집어 넣어줍니다.

 

그 다음으로는 총에 맞고 부서질 돌을 구해봅니다. 마찬가지로 아래 주소에서 큰 돌을 꺼내준 후,

부서지고 나타날 하위 돌 오브젝트에게 아래 컴포넌트처럼 설정해줍니다. 이때 mesh collider -> convex 를 체크해주며 전 글에서 상호작용하는 물체처럼 설정을 해줍니다.

 

위 상위 큰 돌에도 똑같이 설정해줍니다.

 

 

그 다음 큰 돌에 붙일 스크립트입니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Breakable : MonoBehaviour
{
    public List<GameObject> breakablePieces;

    // Start is called before the first frame update
    void Start()
    {
        foreach(var item in breakablePieces){
            item.SetActive(false);
        }
    }

    public void Break(){
        foreach(var item in breakablePieces){
            item.SetActive(true);
            item.transform.parent = null;
        }
        gameObject.SetActive(false);
    }
}

 

 

스크립트를 작성 후 붙였다면, 아래 사진처럼 스크립트 내에 큰 돌 하위 객체들을 넣어줍니다.

 

그 다음은 총에 붙였던 스크립트를 추가 수정해줍니다.

RayCast를 이용해서 전방에 부딪치는 물체가 있다면 위에서 작성한 Break 함수를 이벤트로 호출하게 해줍니다.

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.Interaction.Toolkit;


public class MeteorPistol : MonoBehaviour
{
    public ParticleSystem particles;
    public LayerMask layerMask;
    public Transform shootSource;
    public float distance = 10;

    private bool rayActive = false;

    // Start is called before the first frame update
    void Start()
    {
        XRGrabInteractable grabInteractable = GetComponent<XRGrabInteractable>();
        // 사용자가 트리거를 눌렸을 때
        grabInteractable.activated.AddListener(x => StartShoot());
        // 사용자가 트리거를 눌렸다가 놓았을 때
        grabInteractable.deactivated.AddListener(x => StopShoot());
    }

    public void StartShoot(){
        particles.Play();
        rayActive = true;
    }

    public void StopShoot(){
        // 공중에 있는 파티클 입자 모두 제거
        particles.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear);
        rayActive = false;
    }

    void Update(){
        if(rayActive) RaycastCheak();
    }

    void RaycastCheak(){
        RaycastHit hit;
        bool hasHit = Physics.Raycast(shootSource.position, shootSource.forward, out hit, distance, layerMask);

        if(hasHit){
            // Breakable 의 Break 함수 호출
            hit.transform.gameObject.SendMessage("Break", SendMessageOptions.DontRequireReceiver);
        }
    }
}

 

 

스크립트를 수정 후에 아래처럼 컴포넌트를 수정해줍니다. 참고로 shoot source 는 해당 위치부터 전방을 검사하는데 쓰이는 위치로 적당히 총구 쪽에 위치한 오브젝트를 생성 후 넣어줍니다.

 

추가적으로 돌이 부서지면서 나타날 Energy material 이 빠져있는데 아래와 같이 material 을 하나 만들어서 넣어줍니다. 여기서 Emission 값은 발광을 이야기합니다.

 

위에서 만든 material 을 Energy 오브젝트에 넣어줍니다.

 

그 다음으로 테스트 해보면 돌이 너무 바로 부서지는 느낌이 있습니다. 이를 수정하기 위해 아래 스크립트처럼 2초 정도 맞고 부서지도록 위에서 작성했던 스크립트를 수정해줍니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Breakable : MonoBehaviour
{
    public List<GameObject> breakablePieces;
    public float timeToBreak = 2;
    public float timer = 0;

    // Start is called before the first frame update
    void Start()
    {
        foreach(var item in breakablePieces){
            item.SetActive(false);
        }
    }

    public void Break(){
        timer += Time.deltaTime;
        if(timer > timeToBreak){
            foreach(var item in breakablePieces){
                item.SetActive(true);
                item.transform.parent = null;
            }
            gameObject.SetActive(false);
        }
    }
}

 

 

테스트 결과, 잘 되는 것을 확인할 수 있습니다!

반응형

댓글