[XR 전문 인력 과정] 유니티 타워디펜스 만들기(1) -XR 세팅, 씬 세팅, 화면 회전, 플레이어 이동

2023. 11. 22. 22:10Unity

728x90
반응형

XR 프로젝트 세팅

 


 

 

에셋 다운로드

https://drive.google.com/file/d/1lo48lG5iuIbq-TauEUYEdnGLj0XaVcnb/view?usp=drive_link

 

Bootcamp Map.zip

 

drive.google.com

 


 

 

에셋 씬 수정을 한다. Directional Light과 Camera를 뺀 나머지를 하나의 그룹으로 묶는다.

 

 


 

 

에셋 오류 해결

오류를 클릭해서 나온 오브젝트의 Rigidbody 전체 제거

 

 


 

Rtower 에셋 Hierarchy에 배치, 이름을 TowerObject로 변경한다. 이름을 변경하는 이유는 나중에 AI를 위해서.

 

Transform 변경

 

충돌 효과를 위해서 Mesh Collider 추가

 

 


 

 

빈 오브젝트로 Player 생성, Transform 수정

 

플레이어가 두리번 거리게 만들기 위해 카메라가 플레이어의 눈에 위치한다. 카메라를 플레이어의 자식 오브젝트로 둔다. 카메라의 Transform은 리셋.

PC버전에서 마우스를 회전할 때 두리번 거리게 만든다. 먼저, Input Manager를 확인한다.

 

CamRotation 스크립트 생성 (**오큘러스에서는 시야 회전이 자동으로 된다.)

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

public class CamRotation : MonoBehaviour
{
    //마우스 감도
    public float rotSpeed = 200f;
    //회전 값 변수
    float mx = 0;
    float my = 0;

    void Update()
    {
        //축 받아오기
        float horizontal = Input.GetAxis("Mouse X");
        float vertical = Input.GetAxis("Mouse Y");
        //값 누적
        mx += horizontal * rotSpeed * Time.deltaTime;
        my += vertical * rotSpeed * Time.deltaTime;
        //위아래 시야 y축 제한
        my = Mathf.Clamp(my, -90f, 90f);
        //x, y 축 회전 Vector3에 유의해서 작성
        transform.eulerAngles = new Vector3(-my, mx, 0);
    }
}

 

생성된 스크립트를 카메라에 넣기

 

 


 

 

XR 컨트롤러로 이동 구현

오큘러스 등 VR 기기가 없는 사람이 있을 수 있으니 '크로스 플랫폼'으로 프로젝트를 생성할 예정.

 

 

XRInput.cs 크로스 플랫폼 스크립트 생성 예시

#define PC
//#define Oculus

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class XRInput
{
#if PC
    public enum ButtonTarget
    {
        Fire1,
        Fire2,
        Fire3,
        jump
    }
#endif
}

 

 


 

 

크로스 플랫폼 스크립트

// 크로스 플랫폼

#define PC
//#define Oculus

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

public static class XRInput
{
#if PC
    public enum ButtonTarget
    {
        Fire1,
        Fire2,
        Fire3,
        Jump,
    }
#endif

    // 버튼 정의
    public enum Button
    {
#if PC
        One = ButtonTarget.Fire1,
        Two = ButtonTarget.Jump,
        Thumbstick = ButtonTarget.Fire1,
        IndexTrigger = ButtonTarget.Fire2
#elif Oculus
        One = OVRInput.Button.One,
        Two = OVRInput.Button.Two,
        Thumbstick = OVRInput.Button.PrimaryThumbstick,
        IndexTrigger = OVRInput.Button.PrimaryIndexTrigger
#endif
    }

    public enum Controller
    {
#if PC
        LTouch,
        RTouch
#elif Oculus
        LTouch = OVRInput.Controller.LTouch,
        RTouch = OVRInput.Controller.RTouch
#endif
    }

    // 왼쪽 컨트롤러
    static Transform lHand;
    // 씬에 등록된 왼쪽 컨트롤러를 찾아 반환
    public static Transform LHand
    {
        get
        {
            if (lHand == null)
            {
#if PC
                // LHand라는 이름으로 게임 오브젝트를 만든다.
                GameObject handObj = new GameObject("LHand");
                // 만들어진 객체의 트랜스폼을 lHand에 할당
                lHand = handObj.transform;
                // 컨트롤러를 카메라의 자식 객체로 등록
                lHand.parent = Camera.main.transform;
#elif Oculus
                lHand = GameObject.Find("LeftControllerAnchor").transform;
#endif
            }
            return lHand;
        }
    }
    // 오른쪽 컨트롤러
    static Transform rHand;
    // 씬에 등록된 오른쪽 컨트롤러 찾아 반환
    public static Transform RHand
    {
        get
        {
            // rHand에 값이 없을경우
            if (rHand == null)
            {
#if PC
                // RHand 이름으로 게임 오브젝트를 만든다.
                GameObject handObj = new GameObject("RHand");
                // 만들어진 객체의 트렌스폼을 rHand에 할당
                rHand = handObj.transform;
                // 컨트롤러를 카메라의 자식 객체로 등록
                rHand.parent = Camera.main.transform;
#endif
            }
            return rHand;
        }
    }

    public static Vector3 RHandPosition
    {
        get
        {
#if PC
            // 마우스의 스크린 좌표 얻어오기
            Vector3 pos = Input.mousePosition;
            pos.z = 0.7f;
            // 스크린 좌표를 월드 좌표로 변환
            pos = Camera.main.ScreenToWorldPoint(pos);

            RHand.position = pos;
            return pos;
#elif Oculus
            Vector3 pos = OVRInput.GetLocalControllerPosition(OVRInput.Controller.RTouch);
            pos = GetTransform().TransformPoint(pos);
            return pos;
#endif
        }
    }

    public static Vector3 RHandDirection
    {
        get
        {
#if PC
            Vector3 direction = RHandPosition - Camera.main.transform.position;

            RHand.forward = direction;
            return direction;
#elif Oculus

            Vector3 direction = OVRInput.GetLocalControllerRotation(OVRInput.Controller.
            RTouch) * Vector3.forward;
            direction = GetTransform().TransformDirection(direction);

            return direction;
#endif
        }
    }

    public static Vector3 LHandPosition
    {
        get
        {
#if PC
            return RHandPosition;
#elif Oculus
            Vector3 pos = OVRInput.GetLocalControllerPosition(OVRInput.Controller.LTouch);
            pos = GetTransform().TransformPoint(pos);
            return pos;
#endif
        }
    }

    public static Vector3 LHandDirection
    {
        get
        {
#if PC
            return RHandDirection;
#elif Oculus
            Vector3 direction = OVRInput.GetLocalControllerRotation(OVRInput.Controller.LTouch) * Vector3.forward;
            direction = GetTransform().TransformDirection(direction);

            return direction;
#endif
        }
    }

#if Oculus
    static Transform rootTransform;
#endif

#if Oculus
    static Transform GetTransform()
    {
        if (rootTransform == null)
        {
            rootTransform = GameObject.Find("TrackingSpace").transform;
        }
        return rootTransform;
    }
#endif

    // 컨트롤러의 특정 버튼을 누르고 있는 동안 true를 반환
    public static bool Get(Button virtualMask, Controller hand = Controller.RTouch)
    {
#if PC
        // virtualMask에 들어온 값을 ButtonTarget 타입으로 변환해 전달
        return Input.GetButton(((ButtonTarget)virtualMask).ToString());
#elif Oculus
        return OVRInput.Get((OVRInput.Button)virtualMask, (OVRInput.Controller)hand);
#endif
    }

    // 컨트롤러의 특정 버튼을 눌렀을 때 true를 반환
    public static bool GetDown(Button virtualMask, Controller hand = Controller.RTouch)
    {
#if PC
        return Input.GetButtonDown(((ButtonTarget)virtualMask).ToString());
#elif Oculus
        return OVRInput.GetDown((OVRInput.Button)virtualMask, (OVRInput.Controller)hand);
#endif
    }

    // 컨트롤러의 특정 버튼을 눌렀다 떼었을 때 true를 반환
    public static bool GetUp(Button virtualMask, Controller hand = Controller.RTouch)
    {
#if PC
        return Input.GetButtonUp(((ButtonTarget)virtualMask).ToString());
#elif Oculus
        return OVRInput.GetUp((OVRInput.Button)virtualMask, (OVRInput.Controller)hand);
#endif
    }

    // 컨트롤러의 Axis 입력을 반환
    public static float GetAxis(string axis, Controller hand = Controller.LTouch)
    {
#if PC
        return Input.GetAxis(axis);
#elif Oculus
        if (axis == "Horizontal")
        {
            return OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick, (OVRInput.Controller)hand).x;
        }
        else
        {
            return OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick, (OVRInput.Controller)hand).y;
        }
#endif
    }


#if PC
    static Vector3 originScale = Vector3.one * 0.02f;
#else
    static Vector3 originScale = Vector3.one * 0.005f;
#endif
}

class CoroutineInstance : MonoBehaviour
{
    public static CoroutineInstance coroutineInstance = null;
    private void Awake()
    {
        if (coroutineInstance == null)
        {
            coroutineInstance = this;
        }
        DontDestroyOnLoad(gameObject);
    }
}

 

#define 참고 매뉴얼

 

#define 지시어 - Unity 매뉴얼

Unity의 Platform Dependent Compilation 기능은 지원되는 플랫폼 중 하나를 위해 작성된 코드 섹션을 컴파일 및 실행할 수 있게 하고, 스크립트를 파티션화할 수 있는 전처리 명령으로 구성됩니다.

docs.unity3d.com

 

아래와 같은 오류는 에셋 스토어에서 Oculus Integration을 다운받으면 해결된다.

https://assetstore.unity.com/packages/tools/integration/oculus-integration-deprecated-82022

 

Oculus Integration (Deprecated) | 기능 통합 | Unity Asset Store

Use the Oculus Integration (Deprecated) from Oculus on your next project. Find this integration tool & more on the Unity Asset Store.

assetstore.unity.com

 

 


 

 

플레이어 움직이기

플레이어에 Charater Controller 컴포넌트 추가

 

PlayerMove 스크립트 생성

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//XRInput 스크립트를 사용해서 플레이어 움직이기
public class PlayerMove : MonoBehaviour
{
    //이동 속도
    public float speed = 10f;
    //캐릭터 컨트롤러 컴포넌트를 변수로 가져오기
    CharacterController cc;
    void Start()
    {
        //캐릭터 컨트롤러 가져오기
        cc = GetComponent<CharacterController>();
    }
    void Update()
    {
        //PC에서는 Input.GetAixs 이지만 크로스 플랫폼은 다르다
        //컨트롤러의 Axis 입력을 반환해야한다. XRInput.cs의 212번째줄.
        /*
        public static float GetAxis(string axis, Controller hand = Controller.LTouch)
        {
        #if PC
        return Input.GetAxis(axis);
        #elif Oculus
        if (axis == "Horizontal")
        {
            return OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick, (OVRInput.Controller)hand).x;
        }
        else //Vertical일 때
        {
            return OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick, (OVRInput.Controller)hand).y;
        }
        #endif
        }*/
        float horizontal = XRInput.GetAxis("Horizontal");
        float vertical = XRInput.GetAxis("Vertical");
        //방향 설정
        Vector3 dir = new Vector3(horizontal, 0, vertical);
        //카메라가 바라보는 방향으로 가라
        dir = Camera.main.transform.TransformDirection(dir);
        //이동
        cc.Move(dir * speed * Time.deltaTime);
    }
}

생성한 후 Player에 컴포넌트로 추가

 

발생한 오류는 Camera의 Tag가 MainCamera가 아니었기 때문이다. MainCamera로 Tag를 수정한다.

 

 


 

 

플레이어에 중력, 점프 구현

플레이어 이동 위에 중력을 적용한다.

//중력 변수
public float gravity = -20f;
//수직 속도 초기화
float yVelocity = 0;
//중력 적용
yVelocity += gravity * Time.deltaTime;
dir.y = yVelocity;
//점프 파워
public float jumpPower = 7f;
//점프 버튼을 누르면 점프 XRInput.cs의 191번째줄 참고
if(XRInput.GetDown(XRInput.Button.Two, XRInput.Controller.RTouch))
{
    //점프 파워 적용
    yVelocity = jumpPower;
}

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//XRInput 스크립트를 사용해서 플레이어 움직이기
public class PlayerMove : MonoBehaviour
{
    //이동 속도
    public float speed = 10f;
    //캐릭터 컨트롤러 컴포넌트를 변수로 가져오기
    CharacterController cc;
    //중력 변수
    public float gravity = -20f;
    //수직 속도 초기화
    float yVelocity = 0;
    //점프 파워
    public float jumpPower = 7f;
    void Start()
    {
        //캐릭터 컨트롤러 가져오기
        cc = GetComponent<CharacterController>();
    }
    void Update()
    {
        //PC에서는 Input.GetAixs 이지만 크로스 플랫폼은 다르다
        //컨트롤러의 Axis 입력을 반환해야한다. XRInput.cs의 212번째줄.
        /*
        public static float GetAxis(string axis, Controller hand = Controller.LTouch)
        {
        #if PC
        return Input.GetAxis(axis);
        #elif Oculus
        if (axis == "Horizontal")
        {
            return OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick, (OVRInput.Controller)hand).x;
        }
        else //Vertical일 때
        {
            return OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick, (OVRInput.Controller)hand).y;
        }
        #endif
        }*/
        float horizontal = XRInput.GetAxis("Horizontal");
        float vertical = XRInput.GetAxis("Vertical");
        
        //방향 설정
        Vector3 dir = new Vector3(horizontal, 0, vertical);
        
        //카메라가 바라보는 방향으로 가라
        dir = Camera.main.transform.TransformDirection(dir);

        //중력 적용
        yVelocity += gravity * Time.deltaTime;

        //점프 버튼을 누르면 점프 XRInput.cs의 191번째줄 참고
        if(XRInput.GetDown(XRInput.Button.Two, XRInput.Controller.RTouch))
        {
            //점프 파워 적용
            yVelocity = jumpPower;
        }

        dir.y = yVelocity;
        
        //이동
        cc.Move(dir * speed * Time.deltaTime);

    }
}
728x90
반응형