마블 VR 프로젝트 제작

[마블 VR] 첫번째 포인트 도착 구현

노재두내 2023. 12. 27. 12:43

오늘 해야할 일

1. 첫번째 포인트로 이동하면 찍기 튜토리얼 나오기 - 오전

2. 찍기 튜토리얼 할 때는 공격하지 않고, 가까운 적 한마리 생성하기 - 오전

3. 두번째 적 모두 죽이면 다시 인디케이터+ 자동이동 - 오전 

4. 두번째 포인트 도착하면 리프 튜토리얼 나오기 - 오후

5. 두번째 적 움직임 구현 - 오후

6. 못끝낸거 있다면 - 저녁

 

내일은 근접공격이랑 원거리 공격 합치기

 


1. 첫번째 포인트에 도착하면 찍기 튜토리얼 나오기

찍기 튜토리얼이 아직 만들어지지 않아서 일단 로그로 찍고, indexTrigger버튼 누르면 적이 나오도록 만들었다.

 

<Playercontroller.cs>

private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Point"))
        {
            Debug.Log("목적지에 도착했습니다");
            //인디케이터 지우고 이동 멈추기
            this.indicatorGo.SetActive(false);
            this.pathGo.SetActive(false);
            if (this.coroutine != null) StopCoroutine(this.coroutine);

            //근거리 공격 튜토리얼
            Debug.Log("근거리 공격 튜토리얼");

            if (OVRInput.GetDown(OVRInput.Button.SecondaryIndexTrigger))
            {
                Debug.Log("찍기 완료");
                //근거리 공격 튜토리얼 끝나면 isFirstEnemy false로 만들기
                this.gameSceneMain.isFirstEnemy = false;
                this.gameSceneMain.enemyNum = 0;
            }
        }
    }

===> 이렇게 하면 triggerEnter가 딱 들어왔을때 한번만 호출되므로 트리거버튼 눌러도 생성되지 않는다

 

임의로 전에 만들어뒀던 leapUI를 일단 쓰자

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

public class LeapMain : MonoBehaviour
{
    public GameObject step1High;
    public GameObject step2High;
    
    public GameObject setp1;
    public GameObject setp2;

    private Animator anim;
    private GameSceneMain gameSceneMain;
    private void Start()
    {
        this.gameSceneMain = GameObject.FindObjectOfType<GameSceneMain>();
        Invoke("Active", 2f);
        StartCoroutine(CoGrab());
        this.anim = GetComponent<Animator>();
    }


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

            if (OVRInput.GetDown(OVRInput.Button.One, OVRInput.Controller.RTouch))
            {
                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.One, OVRInput.Controller.RTouch))
            {
                Debug.Log("step2완료");

                this.step2High.gameObject.SetActive(false);
                this.setp2.SetActive(true);

                //적 생성하기
                this.gameSceneMain.isFirstEnemy = false;
                this.gameSceneMain.enemyNum = 0;
                Destroy(this.gameObject, 0.2f);
            }

            yield return null;
        }
    }
}
using Meta.WitAi;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;

public class PlayerController : MonoBehaviour
{
    [SerializeField]
    private PathMain pathMain;
    [SerializeField]
    private GameObject indicatorGo; 
    [SerializeField]
    private Transform destination;
    [SerializeField]
    private Transform[] pos;
    [SerializeField] Transform leapPos;
    [SerializeField] ParticleSystem warp;
    [SerializeField] private GameObject closeTutorial;
    public GameObject pathGo;
    public float ms = 0.025f;

    private Coroutine coroutine;
    
    //float curTime = 0;
    //float warpTime = 0.5f;



    // Start is called before the first frame update
    void Start()
    {
        this.coroutine = this.StartCoroutine(this.CoMove());
    }

    private IEnumerator CoMove()
    {
        yield return new WaitForSeconds(1f);
        while (true)
        {
            var dis = Vector3.Distance(this.transform.position, destination.position);
            
            if (dis < 9f)
            {
                this.transform.position = Vector3.MoveTowards(this.transform.position, pos[2].position, ms);
            }
            else
            {
                this.transform.position = Vector3.MoveTowards(this.transform.position, pos[1].position, ms);
            }
            
            yield return null;
           
        }
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Point"))
        {
            Debug.Log("목적지에 도착했습니다");
            //인디케이터 지우고 이동 멈추기
            this.indicatorGo.SetActive(false);
            this.pathGo.SetActive(false);
            if (this.coroutine != null) StopCoroutine(this.coroutine);

            //근거리 공격 튜토리얼
            Debug.Log("근거리 공격 튜토리얼 생성");
            Instantiate(this.closeTutorial);
        }
    }
}

나중에 근접공격UI(찍기 튜토리얼)으로 변경될 예정

 

튜토리얼이 완료되면 적이 생성되도록 만들었다.

결과물

 

 


2. 찍기 튜토리얼 할 때는 공격하지 않고, 가까운 적 한마리 생성하기 

찍기 튜토리얼 (지금은 leap튜토리얼) 하는 동안에 근접공격 튜토리얼용 공격하지 않는 가까운 적 한마리를 생성하자 

그리고 leap 튜토리얼이 끝나면 그 적은 사라지게 한다. ( 나중에는 근접공격 튜토리얼에서 근접공격을 통해 적이 죽으면)

실제 전투용 적을 생성한다 

코드로 말고 간단하게 애니메이션으로 움직임 구현한다.

 

<PlayerController>

private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Point"))
        {
            Debug.Log("목적지에 도착했습니다");
            //인디케이터 지우고 이동 멈추기
            this.indicatorGo.SetActive(false);
            this.pathGo.SetActive(false);
            if (this.coroutine != null) StopCoroutine(this.coroutine);

            //근거리 공격 튜토리얼
            Instantiate(this.closeTutorial);
            //튜토리얼용 적 생성
            this.tutorialAerialEnemy.SetActive(true);
        }
    }

포인트에 도착하면 튜토리얼과 함께 나오도록 한다.

 

==> 문제점이 있음 애니메이션을 position으로 잡아서 쉴드에 맞아도 바닥으로 안떨어진다.

 

부딪히면 애니메이션 끄도록 함

 

결과

 

==>여기까지 했을 때 이상한 부분들..

방패 팔에 붙는거 위치나 모양새가 이상 

방패 날라가는거 방향,, 상당히 수정 필요해보임

살짝 이상한 부분은 아무래도 아래에 적은 튜토리얼 넘어가는 부분

 


3. 두번째 적 모두 죽이면 다시 인디케이터+ 자동이동

path가 생긴게 다르기 때문에 두개를 만들었다.

public GameObject[] pathGo;

배열로 만들고

 public void CreateEnemy()
    {
        if (this.enemyGo.Length == 0)
        {
            //첫번째 포인트에서 생성되는 적임(최대 8마리 3-3-2)
            if (isFirstEnemy == true)
            {
                if (enemyNum < 6)
                {
                    //적 3마리 생성
                    for (int i = 0; i < 3; i++)
                    {
                        //Debug.Log("적 생성해라");
                        Instantiate(this.aerialEnemyPrefab, this.points[i].position, Quaternion.identity);
                        enemyNum++;
                    }
                }
                else if (enemyNum >= 6 && enemyNum < 8)
                {
                    //2마리 생성
                    for (int i = 0; i < 2; i++)
                    {
                        Instantiate(this.aerialEnemyPrefab, this.points[i].position, Quaternion.identity);
                        enemyNum++;
                    }
                }
                else
                {
                    //더이상 생성하지 X
                    //첫번째 인디케이터 생성
                    this.playerController.pathGo[0].SetActive(true);
                    this.playerController.GetComponent<PlayerController>().enabled = true;
                    return;
                }
            }
            //두번째 포인트에서 생성되는 적임(최대 7마리 2-2-1)
            else
            {
                if (enemyNum < 4)
                {
                    for (int i=3;i<5; i++)
                    {
                        Instantiate(this.aerialEnemyPrefab, this.points[i].position, Quaternion.identity);
                        enemyNum++;
                    }
                }
                else if (enemyNum >= 4&&enemyNum<5 )
                {
                    Instantiate(this.aerialEnemyPrefab, this.points[5].position, Quaternion.identity);
                    enemyNum++;
                }
                else
                {
                    //두번째 인디케이터 생성
                    this.playerController.pathGo[1].SetActive(true);
                    return;
                }
            }
        }
    }

첫번째 적이 모두 죽으면 첫번째 인디케이터 활성화,

두번째 적이 모두 죽으면 두번째 인디케이터를 활성화 해줌

 

자동이동 구현하기

indicator(원모양 포인트)도 두개가 필요하니까 배열로 만들어주고, 

using Meta.WitAi;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;

public class PlayerController : MonoBehaviour
{
    [SerializeField]
    private PathMain pathMain;
    [SerializeField]
    private GameObject[] indicatorGo; 
    [SerializeField]
    private Transform[] pos;
    [SerializeField] Transform leapPos;
    [SerializeField] ParticleSystem warp;
    [SerializeField] private GameObject closeTutorial;
    [SerializeField] private GameObject tutorialAerialEnemy;
    public GameObject[] pathGo;
    public float ms = 0.025f;

    private Coroutine coroutine;
    private bool isSecond;
    //float curTime = 0;
    //float warpTime = 0.5f;
    void Start()
    {
        this.Move();
    }
    public void Move()
    {
        this.coroutine = this.StartCoroutine(this.CoMove());
    }

    public void SecondMove()
    { 
        this.coroutine = this.StartCoroutine(this.CoSecondMove());
    }

    private IEnumerator CoMove()
    {
        yield return new WaitForSeconds(1.3f);
        while (true)
        {
            var dis = Vector3.Distance(this.transform.position, indicatorGo[0].transform.position);

            if (dis < 9f)
            {
                this.transform.position = Vector3.MoveTowards(this.transform.position, pos[1].position, ms);
            }
            else
            {
                this.transform.position = Vector3.MoveTowards(this.transform.position, pos[0].position, ms);
            }
            yield return null;
        }
    }

    private IEnumerator CoSecondMove()
    {
        yield return new WaitForSeconds(1.3f);
        while (true)
        {
            var dis = Vector3.Distance(this.transform.position, indicatorGo[1].transform.position);

            if (dis < 9f)
            {
                this.transform.position = Vector3.MoveTowards(this.transform.position, pos[3].position, ms);
            }
            else
            {
                this.transform.position = Vector3.MoveTowards(this.transform.position, pos[2].position, ms); 
            }
            yield return null;
        }
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Point"))
        {
            Debug.Log("목적지에 도착했습니다");
            //인디케이터 지우고 이동 멈추기
            this.indicatorGo[0].SetActive(false);
            this.pathGo[0].SetActive(false);
            if (this.coroutine != null) StopCoroutine(this.coroutine);

            //근거리 공격 튜토리얼
            Instantiate(this.closeTutorial);
            //튜토리얼용 적 생성
            this.tutorialAerialEnemy.SetActive(true);
        }
        //두번째 포인트일때
    }
}

gameMain에서

여러번 호출되는거를 막기 위해서 바로 false로 만들어줬다.

문제점. 1. 쳐다보는 방향

-> LookAt을 추가함 하지만 너무 갑자기 휙 돌아버려서 이상함 lerp로 부드럽게 보도록 하기

if (dis < 9f)
    {
         var dir = pos[3].position - this.transform.position;
         this.transform.rotation = Quaternion.Lerp(this.transform.rotation, Quaternion.LookRotation(dir), Time.deltaTime * 0.2f);
         this.transform.position = Vector3.MoveTowards(this.transform.position, pos[3].position, ms);
    }

2. 이동 위치 이상

현재 포인트가 2개이기때문에 자연스럽지 않음=> 3개로 늘려야할거같다.

각 포인트에서 도착 지점까지의 거리를 구하고

 private IEnumerator CoSecondMove()
    {
        yield return new WaitForSeconds(1.3f);
        while (true)
        {
            var dis = Vector3.Distance(this.transform.position, indicatorGo[1].transform.position);
            if (dis < 7f)
            {
                var dir = pos[4].position - this.transform.position;
                this.transform.rotation = Quaternion.Lerp(this.transform.rotation, Quaternion.LookRotation(dir), Time.deltaTime * 0.15f);
                this.transform.position = Vector3.MoveTowards(this.transform.position, pos[4].position, ms);
            }
            else if(dis<11f&&dis>7f)
            {
                var dir = pos[3].position - this.transform.position;
                this.transform.rotation = Quaternion.Lerp(this.transform.rotation, Quaternion.LookRotation(dir), Time.deltaTime * 0.15f);
                this.transform.position = Vector3.MoveTowards(this.transform.position, pos[3].position, ms); 
            }
            else
            {
                this.transform.position = Vector3.MoveTowards(this.transform.position, pos[2].position, ms);
            }
            yield return null;
        }
    }

 

결과

위치는 자연스러워졌다. 하지만 회전이 더 빨리 되어야할거같음


4. 두번째 포인트 도착하면 리프 튜토리얼 나오기

private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Point"))
        {
            Debug.Log("목적지에 도착했습니다");
            //인디케이터 지우고 이동 멈추기
            this.indicatorGo[0].SetActive(false);
            this.pathGo[0].SetActive(false);
            if (this.coroutine != null) StopCoroutine(this.coroutine);

            //근거리 공격 튜토리얼
            Instantiate(this.leapTutorial);
            //튜토리얼용 적 생성
            this.tutorialAerialEnemy.SetActive(true);
        }
        else if (other.CompareTag("SecondPoint"))
        {
            this.indicatorGo[1].SetActive(false);
            this.pathGo[1].SetActive(false);
            if (this.coroutine != null) StopCoroutine(this.coroutine);

            //리프 튜토리얼 나오기
            Instantiate(this.leapTutorial,new Vector3(-25.8f,1.3f,5.2f),Quaternion.Euler(0,68f,0));
        }
    }

 


else if (OVRInput.GetUp(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch))

이렇게 하면, 방패가 날라가지 않았는데도 다음 튜토리얼로 넘어감

 

그래서

else if (!OVRInput.Get(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch) && av >= 0.42)

GetUp+ 속도 까지 하면 너무 확률이 희박해져서

!Get&&속도 이렇게 함 

또 문제점, 이렇게 하면 버튼 안누른 상태로 컨트롤러 빠르게 움직이면 다음 튜토리얼로 넘어감..

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);
                    this.isButtonUp = true;
                }
else if (!OVRInput.Get(OVRInput.Button.PrimaryHandTrigger, OVRInput.Controller.LTouch) && av >= 0.42&&isButtonUp==true)

그래서 bool을 넣어줌

하지만 또 이러면 trigger버튼 한번 누르고 다시 떼고 컨트롤러 빠르게 움직이면 또 다음 튜토리얼로 넘어가버림