본문 바로가기
VR 팀프로젝트/[GroundZero] 제작 일지

GroundZero 제작일지 - 아이템 비행체 구현

by 잰쟁 2023. 11. 16.
728x90

구현할 부분

 

 

 

구현할 것

- 비행체를 레이로 조준하여 3번 맞추기 --> 비행체 사라지고 아이템 생성

- 생성된 아이템이 player쪽으로 이동

- 스코어 UI에 닿으면 아이템이 사라지고 스코어 점수 증가

 

 

구현 과정

- 컨트롤러로 Ray를 쏴서 비행체 조준하고 인식하기

- 오른손 IndexTrigger를 누르면(비행체를 Select)하면 비행체 없어지고 아이템(볼트) 생성하기

- 생성된 아이템(볼트)가 PlayerVehicle로 날아오기

- 아이템(볼트)이 PlayerVehicle에 닿으면 아이템 없어지고 스코어UI 점수 증가시키기

 


 

▶컨트롤러로 비행체에 Ray 쏘기

 

- MainCamera 삭제 후, 'OVRCameraRig' 와 'OVRInteraction' 붙여주기

 

(컨트롤러 모델을 손 모델로 바꿔주기)

- OVRInteraction -> OVRControllers 붙여주고 RightController-> 'OVRControllerVisual' 비활성화하기

- OVRCameraRig -> TrackingSpace -> RightHandAnchor에 미리 정해놓은 총 Prefab 넣어주고 알맞게 Transform 조정하기

 

 

 


 

 

▶RayInteraction 만들기

 

- OVRInteraction -> OVRControllers -> RightController -> ControllerInteractors에 'ControllerRayInteractor' 프리팹 붙여주기

- ControllerInteractors -> BestHoverInteractorGroup 스트립트 -> Interactors에 'ControllerRayInteractor' 넣어주기

 

 


 

 

▶비행체 설정하기 - RayInteractable

 

- 빈 오브젝트 'Zeppelin' 만든 후 비행체 prefab을 자식으로 붙여주기 (이름: ZepplinMesh) 

- Zepplin 자식으로 빈오브젝트 'balloonCollider' 만들고 Ray를 인식할 부분인 풍선 부분에 Collider 만들어주기

 

 

- 'Zepplin'에 'Rigidbody''RayInteractable' 컴포넌트 붙여주고 아래와 같이 설정하기

(Use Gravity 비활성화, Surface에 'balloonCollider' 넣어주기)

 

 

- 'balloonCollider'에 'Collider Surface' 컴포넌트 붙여주고 자기 자신 넣어주기

 

 

 


 

▶비행체가 없어지면 아이템(볼트) 생성하기

 

- 아이템 prefab들을 만들고 Rigidbody 붙여주기

- 아래와 같이 Collider 및 Rigidbody 설정하기

(중력 영향 제거 : Use Gravity 비활성화 / Trigger체크 : Collider Convex 활성화)

 

 

- 아이템들 구분을 위해 임시로 Bolt, Nut 색 바꿔주기

Bolt                                                                                                                                      Nut 

 

 

 

'TestItemMain'스크립트의 items에 아이템 프리팹 2가지 넣어주기

 

 

 


 

 

▶ 점수 UI에 나타내기

- UI->Canvas 추가하고 빈오브젝트 'Score'만들어서 자식으로 추가하기

- 'Score'의 자식으로 배경이 될 Image 'bgScore' 추가하고 그 자식으로 문자를 출력할 Text-TextMeshPro 'txtScore' 추가하기

 

 

 

- 3가지를 아래와 같이 설정해주기

Score UI

 

 

(Trigger 체크 해주기)

 

- 'txtScore'에 아래의 'ScoreUI' 스크립트 부착하기

- 'PlayerVehicle'에 trigger 체크 할 빈오브젝트 'point' 붙여주기

- 'point'에 'BoxCollider'와 아래의 'Point' 스크립트 부착하기

(BoxCollider에 IsTrigger체크 해주기)

Collider 부착 모습

 


 

 

아이템 이동 효과 주기 (DOTween 사용)

 

 => 비행체가 폭발하면서 나오는 아이템이 더 실감나게 이동하도록 하기 위해 'DOTween' 이라는 에셋을 사용!

 

DOTween

: ' DOTween'은 빠르고 효율적이며 안전한 Unity용 객체 지향 애니메이션 엔진으로, C# 사용자에게 최적화되어 있음.

: 번거러운 스크립트 작성 대신에 몇 가지 함수들을 이용하여 애니메이션 및 값 변경시 더 부드럽게 연출 가능.

 

 

https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676

 

DOTween (HOTween v2) | 애니메이션 도구 | Unity Asset Store

Use the DOTween (HOTween v2) tool from Demigiant on your next project. Find this & more animation tools on the Unity Asset Store.

assetstore.unity.com

 

 

 

○ 사용하기

: namespace에 'using DG.Tweening' 추가

using DG.Tweening;

 

○ 여러가지 함수들

: Transform, Material, Rigidbody, Light 등 다양한 컴포넌트 뒤에 'DO~'를 붙여 사용

 

(EX)

 

 

 

 

○ 여러가지 Ease 함수들

- 'Ease' 함수 : 변환시 더 부드럽고 다양한 움직임을 연출하기 위한 시간당 변화 그래프. 주로 'DO~'함수 뒤에 붙여서 사용.

 

.

.

.

 

여러 함수들이 있지만 나는 아이템들이 지정된 위치로 움직이는 효과를 연출할 것이기 때문에 'DOMove' 함수 사용!

using DG.Tweening;

public class Item : MonoBehaviour
{
    [SerializeField] private Transform playerVehicle;

    void Start()
    {
    	//DOTween 함수를 사용하여 아이템 이동시키기
        this.transform.DOMove(this.playerVehicle.position, 0.8f).SetEase(Ease.InOutQuart);
    }
}

 


 

 

사용 결과

 

(Before - 일렬로 Linear하게 움직임)

 

↓↓

 

(After - 더 부드럽고 생동감있게 움직임)

 


▶ 스크립트

 

Zeppelin

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class ZeppelinController : MonoBehaviour
{
    private int zeppelinMaxHp = 3;
    private int zeppelinHp;
    public float speed = 0.7f;
    [SerializeField] private GameObject effect;
    public System.Action die;

    void Start()
    {
        this.zeppelinHp = this.zeppelinMaxHp;
    }

    void Update()
    {
        this.transform.Translate(Vector3.forward * this.speed * Time.deltaTime);
    }

    public void Hit()
    {
        this.zeppelinHp--;
        if (this.zeppelinHp == 0)
        {
            this.die();
            Instantiate(this.effect,this.transform.position,Quaternion.identity);
            //Destroy(this.gameObject);
            this.gameObject.SetActive(false);
        }
    }
}

 

GameManager : item 프리팹에 이동할 위치를 전달하기 위해 사용

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

public class GameManager : MonoBehaviour
{
	//싱글톤
    public static GameManager instance;
	
    //...item이동 위치
    public Transform playerVehicle;

    private void Awake()
    {
        if(instance == null)
        {
            instance = this;
        }
    }
}

 

Item

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;

namespace LJE 
{
    public class Item : MonoBehaviour
    {

        void Start()
        {
        	//DOTween을 사용하여 아이템 이동
            this.transform.DOMove(GameManager.instance.playerVehicle.position, 0.8f).SetEase(Ease.InOutQuart);
        }

        void OnTriggerEnter(Collider other)
        {
            if (other.CompareTag("PlayerVehicle"))
            {
                Debug.LogFormat("<color=yellow>Trigger</color>");
                Destroy(this.gameObject);
            }
        }
    }
}

 

TestItemMain

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

public class TestItemMain : MonoBehaviour
{
    [SerializeField] ZeppelinController zeppelin;
	//2가지 아이템
    [SerializeField] GameObject[] items;

    void Start()
    {
        this.zeppelin.die = () => 
        {
            this.StartCoroutine(CoCreateItem());
        }; 
    }

    IEnumerator CoCreateItem()
    {
        Debug.Log("Create");
        int i = 0;
        while (true)
        {
            yield return null;
            if (i < 10)
            {
            	//아이템이 랜덤으로 회전
                var rotation = Quaternion.Euler(Random.Range(0.0f, 360.0f), Random.Range(0.0f, 360.0f), Random.Range(0.0f, 360.0f));
                yield return new WaitForSeconds(0.1f);
                
		//아이템 2가지 중 랜덤 생성
                Instantiate(items[Random.Range(0,2)], this.zeppelin.transform.position, rotation);               
                i++;
            }
        }
    }
}

 

Point

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

public class point : MonoBehaviour
{
    public System.Action itemTrigger;

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Item"))
        {
            Debug.LogFormat("<color=green>itemTrigger</color>");
            this.itemTrigger();
        }
    }
}

 

ScoreUI

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

namespace LJE
{
    public class ScoreUI : MonoBehaviour
    {
        [SerializeField] private TMP_Text txtScore;
        private int score =0;
        [SerializeField] private point point;

        void Start()
        {
        	//포인트에 닿으면
            this.point.itemTrigger = () =>
            {
            	//아이템 1개당 +10점씩
                this.score += 10;
                this.txtScore.text = string.Format("{0}",this.score);
            };
        }
    }
}

 

 

- Zeppelin에 'Interactable Unity Event Wrapper' 컴포넌트 부착 후, When Select 부분에 아래와 같이 설정

--> Ray로 Select 될때 ==> Zeppelin 스크립트의 Hit() 메서드 호출

 

 


 

 

최종 실행결과

 

- 비행체 폭발 후 item 프리팹(Bolt, Nut)이 랜덤으로 번갈아가며 잘 생성

 


 

▼참고 사이트

https://easings.net/ko

 

Easing Functions Cheat Sheet

Easing functions specify the speed of animation to make the movement more natural. Real objects don’t just move at a constant speed, and do not start and stop in an instant. This page helps you choose the right easing function.

easings.net

https://m.blog.naver.com/dooya-log/221320177107

 

[Asset] Unity3D 'DOTween' 1 : 기본 기능과 팁

+23.07.26 내용 수정 및 보완 [ DOTween ] 오브젝트의 애니메이션 혹은 부드러운 값 변경 시 기존의 유...

blog.naver.com

https://velog.io/@livelyjuseok/Unity-DOTween-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

 

Unity - DOTween 사용하기

다트윈, 닷트윈으로 불리는 유니티에서 유명한 에셋중 하나입니다. 설명을 보면 C나에게는 가벼운 기능들을 빠르고 효율적이게 쓸 수 있게 해주는 API 같은 존재이다. 사용하기 위해서는 using DG.T

velog.io