안녕하세요. 다시 VR로 돌아왔습니다.
시험기간이 얼마 남지 않아 큰일남을 깨닫고 허겁지겁 만들었습니다.
저번 시간에는 큐브를 생성하고 간단한 물리적 상호작용부터 잡는 것, 그리고 3가지 Movement Type에 대해서 알아보았습니다.
이번 시간에는 저번 시간보다는 이론 위주가 아닌 실습 위주로, 저번 시간에 배웠던 것을 응용하여 총알이 발사되는 총을 만들어보겠습니다.
우선 저번시간에 이어 저희가 해야 할 것들을 정리해 보겠습니다
- 오브젝트의 Attach Point에 대해서 알아보고, 알맞게 설정해 보기.
- 물리적 상호작용이 가능한 총알을 제작하고, Trigger 버튼에 의해 총알이 발사되도록 프로그래밍 해보기
이 정도가 있겠네요. 바로 시작해보도록 하겠습니다.
1. 오브젝트의 Attach Point에 대해서 알아보고, 알맞게 설정해 보기
먼저 Attach Point에 대해 알아보겠습니다. Attach Point란, 어떤 오브젝트를 잡는 중심이 되는 부분입니다.
확실한 이해를 돕기 위해서 먼저 오브젝트를 하나 집어보겠습니다.
이번 시간의 최종 목표는 총알이 발사되는 총을 제작하는 것이기 때문에, 총 오브젝트를 대상으로 이번 글을 진행해보도록 하겠습니다.
우선 저희가 총 오브젝트 디자인을 직접 만들기에는 너무 힘들기 때문에, 이미 만들어져 있는 총 모양 프리팹을 불러와 진행하겠습니다.
아래 링크로 가서 총 오브젝트 유니티패키지 파일을 다운로드 받으신 다음, 유니티 에디터로 끌어와 임포트해주세요!
https://drive.google.com/file/d/1C5Fn4Yq79yof4X1lkl0MIYzVqY_UBz3M/view
Pistol.unitypackage
drive.google.com
Pistol 유니티패키지를 Project폴더에 끌어다놓으시면 유니티 에디터 내에 창이 뜨는데, import를 눌러주시면 됩니다.
그러면 Pistol이라는 폴더가 생성되는데요, 그 안에 있는 Pistol prefab을 하이라키 창에 끌어다놓아서 오브젝트를 생성해주세요!
그 다음 권총을 만들어놓은 테이블 위의 위치로 이동시켜 준 후, 잡을 수 있도록 컴포넌트를 추가해주어야 하는데요,
오브젝트를 클릭하고, Inspector 창의 Add New Component를 클릭한 뒤, 아래 세 개의 컴포넌트를 추가해 주세요.
( 지금까지 했던 것이라 설명은 넘어가겠습니다! )
- Box Colider 추가 - 권총 크기에 맞게 사이즈 조절 ( 0.01 / 0.04 / 0.05 추천 )
- Rigidbody 추가, Use Gravity 체크 ( 중력 사용 )
- XR Grab Interactable 추가 ( VR에서 잡을 수 있도록 하는 컴포넌트 )
Box Colider는 아래와 같이 권총의 크기에 맞게 설정해 주어야 합니다!
이렇게 만들었으면 바로 실행시켜서 잡아보겠습니다.
보시는 것처럼 총을 잡는 부위가 살짝 이상합니다. 이처럼 오브젝트를 잡을 때 중심이 되는 부분을 설정해 주는 것을 Attach Point를 설정하는 것이라고 합니다.
Attach Point를 설정해 주어야 오브젝트를 자연스럽게 잡을 수 있는 것이죠.
Attach Point를 설정해주기 위해서 권총 프리팹 안에 GameObject 하나를 만들어줍니다. ( 우클릭 - Create Empty )
저는 이름을 Attach Point로 설정해주겠습니다.
그 다음, Pistol의 XR Grab Interactable 컴포넌트에 가서 Attach Transform에 저희가 만든 게임오브젝트를 드래그하여 넣어줍니다.
그리고 게임을 실행해가시면서 적당한 Attach Point로 맞추어 주시면 끝납니다.
이렇게 Attach Point를 설정해주면 자연스럽게 잡을 수 있게 됩니다.
2. 물리적 상호작용이 가능한 총알을 제작하고, Trigger 버튼에 의해 총알이 발사되도록 프로그래밍 해보기
다음으로는 총을 만들었으니 발사할 수 있는 총알을 만들어보겠습니다.
그 전에 먼저, 저희가 고쳐주어야 할 것이 있습니다. 바로 저희가 예전에 만들어 봤었던 Teleportation과 총알 발사 버튼이 겹친다는 것인데요, 이것은 총을 잡고 있는데 총을 쏘지 못하는 심각한 문제가 될 수 있죠.
따라서 저희가 물건을 들고 있을 때는 트리거버튼으로 텔레포트 하지 않도록 설정해주겠습니다.
이 과정은 if문에 물건을 잡고 있는가 아닌가에 대한 조건만 추가해주면 되므로 그리 어렵지 않습니다.
우선 스크립트를 수정해주어야 하기 때문에 XR Origin - Activative (Teleportation) Ray 컴포넌트에 있는 스크립트를 더블클릭하여 이동해줍니다.
우선 저희가 오브젝트를 잡고 있는지 아닌지 ( 그랩 여부 ) 를 인식해줄 변수가 필요하겠죠?
이는 양손에 각각 하나씩 적용되어야 하므로, 총 2갱의 퍼블릭 입력변수를 받아줍니다.
( 저의 경우 텔레포트를 오른손만 구현했기 때문에 입력변수를 하나 받아주겠습니다. )
다음에 이 값이 0일때( 그랩을 누르지 않고 있을 때)만 텔레포트를 허용해주면 되는 것이겠죠?
따라서 코드를 다음과 같이 작성할 수 있습니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit; // XR 인터렉션 툴킷을 사용합니다.
using UnityEngine.InputSystem; // 퍼블릭 변수 입력을 위한 입력관리 시스템을 사용합니다.
public class ActivateRay : MonoBehaviour
{
public GameObject RightTP; // 광선 오브젝트를 퍼블릭 변수로 입력받습니다.
public InputActionProperty RightActivate; // 오른쪽 트리거 버튼 입력을 받고 값을 읽기 위한 변수
public InputActionProperty RightHandIsGrab; // 그랩했는지 안했는지 여부 확인
// Update is called once per frame
void Update()
{
RightTP.SetActive(RightHandIsGrab.action.ReadValue<float>()==0 && RightActivate.action.ReadValue<float>()> 0.1f);
// 오른쪽 그랩 버튼의 입력값이 0이고 오른쪽 트리거 버튼의 입력값이 0.1f보다 크다면 오른쪽 텔레포트 광선 활성화
}
}
그 다음에 Activate Ray 컴포넌트에 새로 생긴 퍼블릭변수에 액션을 추가해주기 위해 Use Reference 체크, XRI RightHand Interaction/Select 를 선택해줍니다.
바로 실행시켜서 잘 작동하는지 확인해보겠습니다.
트리거 버튼을 계속 눌렀음에도, 텔레포트가 작용하지 않았음을 확인할 수 있었습니다.
이제 본격적으로 총알을 만들어보겠습니다.
먼저 총알이 작동하기 위한 스크립트부터 작성해보겠습니다. Pistol 프리팹을 클릭한 뒤에 Add Component - 원하는 이름의 스크립트를 하나 만들어줍니다. ( 저는 Bullet이라고 작성하겠습니다. )
총알을 만들기 위해 받을 변수 목록은 다음과 같습니다.
- Public [ GameObject ] : 한 번 발사할 때마다 생성되어야 할 총알 오브젝트를 변수로 받음
- Public [ Transform ] : 총알을 발사할 때마다 생성되게 하는 위치를 퍼블릭 변수로 받음
- Public [ Float ] : 총알의 속도를 퍼블릭변수 float형으로 받음
다음으로 총알 코드를 작성할 때 이용할 핵심 기능인데요, 바로 XR Grab Interactable의 activate 이벤트입니다.
activate 이벤트는 오브젝트가 활성화되었을 때 ( 일반적으로 VR 트리거 버튼이 눌렸을 때 ) 실행되는 이벤트입니다.
이런 상황처럼, 트리거 버튼을 눌러 총알을 발사하거나 다른 액션을 만들 때 많이 쓰이는데요,
이 activate 이벤트를 코드에서 참조하여, 트리거 버튼이 눌릴 때마다 총알을 발사하도록 만들 수 있습니다.
activate 이벤트를 이용하는 대표적인 함수로는 AddListener() 함수가 있는데요, 이는 activate 이벤트가 실행되었는지 아닌지를 보고, 실행되었다면 특정 함수를 실행할 수 있는 함수를 말합니다.
이를 이용하여 총을 잡고 있는 상태로 트리거 버튼이 눌리게 되면, 총알을 발사하게 되는 것이지요.
AddListener() 안에 들어갈 Firebullet 함수도 만들어주어, 총알의 게임오브젝트화를 진행해줄것입니다.
자세한 내용은 주석에 달아두었으니 참고하시기 바랍니다!
< Instantiate와 Distroy 함수 사용법에 관한 글 >
https://codingmania.tistory.com/166
[Unity] 유니티에서 Instantiate()와 Destroy() 함수 사용방법
GameObject Object.Instantiate(GameObject original, Vector3 position, Quaternion rotation) Instantiate()함수를 사용하면 게임을 실행하는 도중에 게임오브젝트를 생성할 수 있다.물론 게임이 실행되기 전 미리 만들어놓
codingmania.tistory.com
순서도는 다음과 같이 작성하였습니다.
코드는 다음과 같습니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
public class Bullet : MonoBehaviour
{
public GameObject bullet;
public Transform SpawnPt;
public float speed;
// Start is called before the first frame update
void Start()
{
// 현재 오브젝트의 컴포넌트 내의 XR Grab Interactable을 XGI 변수에 할당 ( 변수처럼 사용할 수 있게끔 )
XRGrabInteractable XGI = GetComponent<XRGrabInteractable>();
// XGI 안의 activated 이벤트에 FireBullet이라는 함수를 추가하여, 트리거 버튼을 누를 때마다 FireBullet함수가 실행되게끔 만듦
XGI.activated.AddListener(Firebullet);
}
// Update is called once per frame
void Update()
{
}
// 총알을 발사하는 FireBullet 함수. 인자로는 트리거 버튼이 눌렸을 때 컨트롤러에 대한 다양한 정보를 담고 있는 ActivateEventArgs를 받음
// 그러나 현 코드에서는 트리거 버튼이 눌렸을 때 실행해주는 역할만 있으면 되므로, 저 변수는 사용하지 않음.
// ( 저 매개변수를 추가하지 않으면 AddListener 함수를 사용할 수 없으므로 매개변수 추가만 해줌 )
public void Firebullet(ActivateEventArgs arg)
{
// 퍼블릭 변수로 받은 bullet 프리팹의 원본 속성과 컴포넌트를 복제하여 독립적인 게임오브젝트를 생성함, 그 이름을 spawnedBullet이라고 함
GameObject spawnedBullet = Instantiate(bullet);
// 생성된 총알의 위치를 퍼블릭 변수로 입력받은 스폰위치로 지정함
spawnedBullet.transform.position = SpawnPt.position;
// 총알의 물리적 시스템을 다루는 Rigidbody 컴포넌트를 참조, 스폰위치의 앞 방향단위벡터에 속도( 크기 )를 곱해주어 그 방향으로 지정된 속도로 나가게 설정
spawnedBullet.GetComponent<Rigidbody>().velocity = SpawnPt.forward * speed;
// 5초 후에 오브젝트를 파괴, 렉걸림을 방지
Destroy(spawnedBullet, 5);
}
}
이제는 변수로 입력해줄 오브젝트와 Transform을 생성하고 알맞게 설정해주기만 하면 되는데요,
우선 총알 오브젝트를 만들어주겠습니다.
하이라키 창을 우클릭한 뒤 3D Object - Sphere ( 구 ) 혹은 Cube ( 정육면체 ) 를 선택해줍니다.
크기를 알맞게 조정해주시고 ( 0.03 추천 ) , Meterial또한 취향껏 조정해주세요.
다음으로 Rigidbody 컴포넌트를 추가하고, Use Gravity를 체크해제해줍니다. 총알은 중력으로 인한 효과를 무시할만큼 충분히 빠르다고 가정하겠습니다. ( 조준하는 곳으로 총알이 나가도록 하기 위해서 )
다음으로 Rigidbody 내의 Collision Detection 을 Continuous Dynamic으로 설정하여 줍니다.
이는 빠른 속도로 움직이는 오브젝트에 적용하면 좋은 콜라이더 감지 모드인데요, 물체가 빠르게 움직이거나 강하게 움직일 때 게임에서 가끔 낑김 현상이나 통과현상이 일어나곤 합니다. 그것을 방지하기 위해 물체의 콜라이더를 더 정밀하게 감지하고 충돌을 인식하는 기능인 것이죠.
자세한 것은 유니티 공식 홈페이지를 참고하시면 되겠습니다.
https://docs.unity3d.com/kr/560/Manual/class-Rigidbody.html
리지드바디 - Unity 매뉴얼
Rigidbody 는 GameObject 가 물리 제어로 동작하게 합니다. 리지드바디는 힘과 토크를 받아 오브젝트가 사실적으로 움직이도록 해줍니다. 리지드바디가 포함된 모든 게임 오브젝트는 중력의 영향을
docs.unity3d.com
무튼 이렇게 총알을 만들어준 후, 만들어준 총알을 Project 폴더로 끌어와 프리팹으로 사용할 수 있게끔 해줍니다.
이 프리팹을 pistol 오브젝트에서, 저희가 작성한 스크립트의 퍼블릭 변수로 드래그하여 넣어 주면 되는 것입니다.
다음으로는 총알의 생성 위치를 설정해 주어야 하는데요, pistol 프리팹 내에 Empty Object를 생성해주고, 총알 입구 쪽에 생성위치를 맞추어 주면 되겠습니다.
그 다음 이 오브젝트를 다시 퍼블릭 변수에 드래그해주시고, 총알의 속도를 원하는 대로 설정해주시면 되겠습니다.
바로 실행시켜보도록 하겠습니다.
총알이 잘 나가는 모습을 확인할 수 있습니다.
+ 심심하니 총알이 발사되는 소리도 넣어보겠습니다. ㅋㅋ
먼저 총 효과음을 구해야 하는데요, 제가 작년도부터 유니티를 사용하면서 이용했던 효과음 사이트가 있습니다.
効果音ラボ - 商用無料、報告不用の効果音素材をダウンロード
2400音以上の音源を掲載したフリー効果音サイト。品質にこだわっており、テレビなどのプロの音響現場でも使われています。
soundeffect-lab.info
일본어긴 하지만 정말 많은 사이트들이 있어 유용합니다.
여기서 마음에 드는 총 발사 효과음을 하나 찾아주세요.
다음에 pistol 오브젝트에 들어가서 Add Component - Audio Source를 추가해줍니다.
AudioClip에 다운로드 받은 효과음을 드래그하여 넣어줍니다.
다음으로는 총알이 발사 될 때 효과음이 발생하도록 설정해주어야 하므로,
Play On Awake를 체크해제해줍니다. ( 시작할 때 바로 재생하는 기능 )
다음으로는 스크립트를 수정해주어야 하는데요,
먼저 퍼블릭 변수로 오디오소스를 받아주어야 하므로, 변수 하나를 선언하고,
Start 함수에 오디오소스 컴포넌트를 가져와 변수에 저장, 총알이 발사될 때 Firebullet 함수에 플레이하는 코드를 입력해주면 해결입니다!
다음과 같이 작성할 수 있겠네요.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
public class Bullet : MonoBehaviour
{
public GameObject bullet;
public Transform SpawnPt;
public float speed;
public AudioSource audiosource;
// Start is called before the first frame update
void Start()
{
// 현재 오브젝트의 컴포넌트 내의 XR Grab Interactable을 XGI 변수에 할당 ( 변수처럼 사용할 수 있게끔 )
XRGrabInteractable XGI = GetComponent<XRGrabInteractable>();
// XGI 안의 activated 이벤트에 FireBullet이라는 함수를 추가하여, 트리거 버튼을 누를 때마다 FireBullet함수가 실행되게끔 만듦
XGI.activated.AddListener(Firebullet);
// 오디오 소스 변수에 저장
audiosource = GetComponent<AudioSource>();
}
// Update is called once per frame
void Update()
{
}
// 총알을 발사하는 FireBullet 함수. 인자로는 트리거 버튼이 눌렸을 때 컨트롤러에 대한 다양한 정보를 담고 있는 ActivateEventArgs를 받음
// 그러나 현 코드에서는 트리거 버튼이 눌렸을 때 실행해주는 역할만 있으면 되므로, 저 변수는 사용하지 않음.
// ( 저 매개변수를 추가하지 않으면 AddListener 함수를 사용할 수 없으므로 매개변수 추가만 해줌 )
public void Firebullet(ActivateEventArgs arg)
{
// 퍼블릭 변수로 받은 bullet 프리팹의 원본 속성과 컴포넌트를 복제하여 독립적인 게임오브젝트를 생성함, 그 이름을 spawnedBullet이라고 함
GameObject spawnedBullet = Instantiate(bullet);
// 생성된 총알의 위치를 퍼블릭 변수로 입력받은 스폰위치로 지정함
spawnedBullet.transform.position = SpawnPt.position;
// 총알의 물리적 시스템을 다루는 Rigidbody 컴포넌트를 참조, 스폰위치의 앞 방향단위벡터에 속도( 크기 )를 곱해주어 그 방향으로 지정된 속도로 나가게 설정
spawnedBullet.GetComponent<Rigidbody>().velocity = SpawnPt.forward * speed;
// 오디오소스 재생
audiosource.Play();
// 5초 후에 오브젝트를 파괴, 렉걸림을 방지
Destroy(spawnedBullet, 5);
}
}
바로 실행시켜보도록 하겠습니다.
이제 게임을 만드는 듯한 느낌이 납니다.
이렇게 해서 오늘은 Attach Point 설정 및 총알 제작을 해보았는데요, 여러분도 코드 작성 부분에서 이해가 힘드셨을거라고 생각합니다. 저도 유니티 공식홈페이지와 영상들을 참고하면서 아무래도 공부를 했으니, 많이 부족한 부분이 있습니다.
이해한 부분을 바탕으로 최대한 작성해보았으니 이해 부탁드립니다.
이상으로 6월 정보융합탐구 과제를 급하게 마치겠습니다. 감사합니다.
'정보융합탐구' 카테고리의 다른 글
[ Unity VR & 정보융합탐구 ] 06. Distance Grab (2) | 2023.07.12 |
---|---|
정융탐 ] Diffusion Model과 GAN의 비교 (1) | 2023.05.30 |
[ Unity VR & 정보융합탐구 ] 05. 오브젝트의 물리적 상호작용 - (1) (1) | 2023.05.27 |
정융탐 ] 3. 이공계체험학습 내용 정리 및 후기 (4) | 2023.05.16 |
정융탐 ] 2. 행렬곱 ( Matrix Multiplication ) (0) | 2023.05.11 |