본문 바로가기
마블 VR 프로젝트 제작

[마블 VR] 튜토리얼 완료 -> 미션 보여주기 -> 공중 적 생성

by 노재두내 2023. 12. 26.

1. 미션 UI 애니메이션 만들기

팀원이 만들어놨던 미션 UI에 깜빡거리는 효과를 주기 위해서 애니메이션 제작

간단하게 구현 후

 


2. 튜토리얼 완료되면 미션 UI 생성, 미션 UI 사라지면 적 생성

팀원이 작성해놓은 TutorialMain 스크립트에 추가

튜토리얼 완료되면 미션 UI Instantiate 후 Destroy이 되면 isFinish 값이 true가 되도록,

isFinish 값이 true면 CreateEnemy함수 호출 

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

public class TutorialMain : MonoBehaviour
{
    [SerializeField] private Shield shield;
    [SerializeField] private GameSceneMain gameSceneMain;
    [SerializeField] private GameObject missionPrefab;
    public GameObject step1High;
    public GameObject step2High;
    public GameObject step3High;
    public GameObject setp1;
    public GameObject setp2;
    public GameObject setp3;

    private bool isFinish;
    private Coroutine coroutine;
    private Animator anim;
    private void Start()
    {
        Invoke("Active", 1f);
        this.coroutine=StartCoroutine(CoGrab());
        this.anim = GetComponent<Animator>();
    }

    private void Active()
    {
        this.step1High.SetActive(true);
        this.setp1.SetActive(false);
    }

    private void Update()
    {
        if (isFinish == true)
        {
            this.gameSceneMain.CreateEnemy();
        }
    }

    private bool isRegrab = false;
    IEnumerator CoGrab()
    {
        while (true)
        {
            if (isRegrab == false)
            {
                if (OVRInput.GetDown(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch))
                {
                    Debug.Log("step1완료");
                    this.step1High.gameObject.SetActive(false);
                    this.setp1.SetActive(true);
                    this.step2High.gameObject.SetActive(true);
                    this.setp2.SetActive(false);
                }
                else if (OVRInput.GetUp(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch))
                {
                    Debug.Log("step2완료");

                    this.step2High.gameObject.SetActive(false);
                    this.setp2.SetActive(true);
                    this.step3High.gameObject.SetActive(true);
                    this.setp3.SetActive(false);
                    isRegrab = true;
                }
            }
            if (isRegrab == true)
            {
                if (OVRInput.Get(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch)&& Vector3.Distance(shield.pos.transform.position, shield.lHandAnchor.position) < 0.2f)
                {
                    this.anim.SetInteger("IsFinish", 0);

                    //미션 나오기
                    yield return new WaitForSeconds(0.5f);
                    GameObject missionGo = Instantiate(this.missionPrefab);
                    Destroy(missionGo, 3);
                    this.isRegrab = false;
                    //적 생성 및 코루틴 중지
                    yield return new WaitForSeconds(2f);
                    this.isFinish = true;
                    if (this.coroutine != null) StopCoroutine(this.coroutine);
                }
            }
            yield return null;
        }
    }
}

미션 ui가 다시 그랩할때마다 계속 생성되어서 stopcoroutine을 해야하는데 그러면 적 생성이 한번만 돼서 어떻게 해야할까 고민했는데 적 생성은 Update에서 하고 stopcoroutine을 하도록 했음

 

결과

 


3. 미션 ui가 플레이어의 시선 이동을 따라 움직임

 

GameObject missionGo = Instantiate(this.missionPrefab);
missionGo.transform.SetParent(this.centerEyeAnchor);

부모를 centerEyeAnchor로 설정 한다.

 

수정 결과

너무 바로 따라오는 느낌

Non-convex MeshCollider with non-kinematic Rigidbody is no longer supported since Unity 5.
If you want to use a non-convex mesh either make the Rigidbody kinematic or remove the Rigidbody component. 

오류가 뜸 

하지만 나는 rigidbody가 있지도 않은데 ..

걍 rigidbody를 아예 추가해버리고 isKinematic을 키니까 오류는 안난다.

 

 


바로 시선을 따라오는게 아니라 시간차를 두고 따라옴 =>Queue 이용

골드메탈님의 https://www.youtube.com/watch?v=QPwF2Lsf7c8&list=PLO-mt5Iu5TeYtWvM9eN-xnwRbyUAMWd3b&index=10

을 참고해서 만들었음


결과

문제는 따라오긴 하는데 크게 변화가 없음

보니까 우리는 가만히 서서하는 게임이다보니,  centerEyeAnchor의 위치값은 크게 변하지 않음

position이 아니라 rotation값을 받아와야할거같다.

 

수정1. rotation값을 받아오도록 코드를 모두 수정함

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

public class MissionUI : MonoBehaviour
{
    public Quaternion followRot;
    public int followDelay;
    private Transform parent;
    public Queue<Quaternion> parentRot;

    private void Awake()
    {
        this.parent = GameObject.Find("CenterEyeAnchor").transform;
        parentRot = new Queue<Quaternion>();
    }

    private void Update()
    {
        Watch();
        Follow();
    }

    void Watch()
    {
        //Queue FIFO
        if (!parentRot.Contains(parent.rotation))
        {
            parentRot.Enqueue(this.parent.rotation);
        }

        if (parentRot.Count > followDelay)
        {
            this.followRot = parentRot.Dequeue();
        }
        else if(parentRot.Count < followDelay)
        {
            this.followRot = this.parent.rotation;
        }
    }

    void Follow()
    {
        this.transform.rotation = followRot;
    }
}

실행결과

그런데도 뭔가 이상..

 

 

수정2.position과 rotation을 모두 받아오기

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

public class MissionUI : MonoBehaviour
{
    public Quaternion followRot;
    public Vector3 followPos;
    public int followDelay;
    private Transform parent;
    public Queue<Quaternion> parentRot;
    public Queue<Vector3> parentPos;

    private void Awake()
    {
        this.parent = GameObject.Find("CenterEyeAnchor").transform;
        parentRot = new Queue<Quaternion>();
        parentPos= new Queue<Vector3>();
    }

    private void Update()
    {
        Watch();
        Follow();
    }

    void Watch()
    {
        //Queue FIFO
        if (!parentRot.Contains(parent.rotation))
        {
            parentRot.Enqueue(this.parent.rotation);
            parentPos.Enqueue(this.parent.position - new Vector3(0, 0, -1));
        }

        if (parentRot.Count > followDelay)
        {
            this.followRot = parentRot.Dequeue();
            this.followPos = parentPos.Dequeue();
        }
        else if(parentRot.Count < followDelay)
        {
            this.followRot = this.parent.rotation;
            this.followPos = this.parent.position-new Vector3(0,0,-1);
        }
    }

    void Follow()
    {
        this.transform.rotation = followRot;
        this.transform.position = followPos;
    }
}

 

실행결과

 

각도가 좀 이상하다

 

setparent centerEyeAnchor할때와 비교해서 보면 확실히 각도가 이상함

 

수정3. x축으로 15도 위로 올려줌

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

public class MissionUI : MonoBehaviour
{
    public Quaternion followRot;
    public Vector3 followPos;
    public int followDelay;
    private Transform parent;
    public Queue<Quaternion> parentRot;
    public Queue<Vector3> parentPos;

    private void Awake()
    {
        this.parent = GameObject.Find("CenterEyeAnchor").transform;
        parentRot = new Queue<Quaternion>();
        parentPos = new Queue<Vector3>();
    }

    private void Update()
    {
        Watch();
        Follow();
    }

    void Watch()
    {
        //Queue FIFO
        if (!parentRot.Contains(parent.rotation))
        {
            parentRot.Enqueue(this.parent.rotation*Quaternion.Euler(new Vector3(15f,0,0)));
            parentPos.Enqueue(this.parent.position - new Vector3(0, 0, -1));
        }

        if (parentRot.Count > followDelay)
        {
            this.followRot = parentRot.Dequeue();
            this.followPos = parentPos.Dequeue();
        }
        else if (parentRot.Count < followDelay)
        {
            this.followRot = this.parent.rotation * Quaternion.Euler(new Vector3(15f, 0, 0));
            this.followPos = this.parent.position - new Vector3(0, 0, -1);
        }
    }

    void Follow()
    {
        this.transform.rotation = followRot;
        this.transform.position = followPos;
    }
}

실행결과

좀 나아짐

하지만 여전히 부자연스러움


또다른 문제점

시야에 따라 회전은 하는데 시야의 앞으로 위치하지 않음

 

- new Vector3(0, 0, -1)

이코드를 없애니까 잘 따라오는거같음

 

생각해보면 당연하다. centerEyeAnchor의 z축 1앞에 위치는 항상 저 앞에 위치임

==>centerEyeAnchor의 forward가 항상 바뀌기 때문에 forward의 앞쪽에 위치해야한다.

this.followPos = this.parent.position+this.parent.forward*1f;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class MissionUI : MonoBehaviour
{
    public Queue<Quaternion> parentRot;
    public Queue<Vector3> parentPos;
    public int followDelay;

    private Quaternion followRot;
    private Vector3 followPos;
    private Transform parent;
   
    private void Awake()
    {
        this.parent = GameObject.Find("CenterEyeAnchor").transform;
        parentRot = new Queue<Quaternion>();
        parentPos = new Queue<Vector3>();
    }

    private void Update()
    {
        Watch();
        Follow();
    }

    void Watch()
    {
        //Queue FIFO
        if (!parentRot.Contains(parent.rotation))
        {
            parentRot.Enqueue(this.parent.rotation*Quaternion.Euler(new Vector3(10f,0,0)));
            parentPos.Enqueue(this.parent.position + this.parent.forward *1f);
        }

        if (parentRot.Count > followDelay)
        {
            this.followRot = parentRot.Dequeue();
            this.followPos = parentPos.Dequeue();
        }
        else if (parentRot.Count < followDelay)
        {
            this.followRot = this.parent.rotation * Quaternion.Euler(new Vector3(10f, 0, 0));
            this.followPos = this.parent.position+this.parent.forward*1f;
        }
    }

    void Follow()
    {
        this.transform.rotation = followRot;
        this.transform.position = followPos;
    }
}

이렇게 코드를 수정하니 각도가 이상한것도 해결됐다.

 

[최종 결과!!!]

이제 원작과 매우 흡사한 모습