OculusQuest에서 게임을 할 조이스틱 만들기

17176 단어 OculusQuestVRUnity

소개



OculusQuest에서 게임을하기 위해 조이스틱을 원했기 때문에 만들었습니다.

이전에 만든 게임을 조이스틱으로 움직일 수 있게 되었다 피 c. 라고 r. 코 m/z48 이코 zdG7 — 다카하마


XR Interaction Toolkit을 사용하고 있기 때문에 OculusQuest 이외에서도 움직이는 것 같습니다만 미확인입니다.



개발 환경



Unity 2019.3.10f1

XR Interaction Toolkit 0.9.4

Oculus XR Plugin 1.3.3



만드는 방법



구성



April 28, 2020



토대(Base)



· 조이스틱 자체를 잡고 조작하기 위해 XR Grab Interactable 스크립트를 붙입니다.

・XR Grab Interactable로 필요하므로 RigidBody를 붙입니다.

· 잡지 않을 때 움직이지 않도록 RigidBody의 IsKinematic = true로 둡니다.



스틱 아래쪽 볼(Ball1)



· 이 객체를 회전시켜 스틱을 움직입니다.

・XR Stick Interactable 스크립트(스틱을 조작하기 위한 자작 스크립트, 나중에 설명합니다)로 필요하므로 RigidBody를 붙입니다.

・스틱을 조작하기 위한 스크립트는 이 오브젝트에 붙여 버린다고 인식되지 않기 때문에(상위의 계층에 XRBaseInteractable 파생의 스크립트가 있으면 안되는 것 같습니다), 다른 계층에 붙입니다.



스틱(Cylinder)



・스틱을 잡는 판정에 필요하므로 Collider를 붙입니다.



제어(handle)



・XR Stick Interactable 스크립트(스틱을 조작하기 위한 자작 스크립트)를 붙입니다.

・XR Stick Interactable 스크립트의 Colliders에는 조작 대상의 스틱의 Collider를, MovingRigidBody에는 움직이는 볼의 오브젝트를, OnStickChange에는 움직임을 통지하는 함수를 등록합니다.

・SetText는 움직임의 확인 표시용, GetInputAction은 움직임을 게임에 전하기 위해서 붙이고 있는 스크립트입니다.




XRStickInteractable.cs

using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.XR.Interaction.Toolkit;

public class XRStickInteractable : XRBaseInteractable
{
    [Serializable]
    public class StickChangeEvent : UnityEvent<float, float> {}

    public Rigidbody MovingRigidbody;
    public StickChangeEvent OnStickChange;

    private XRBaseInteractor m_GrabbingInteractor;
    private Quaternion m_StartRotation;
    private Vector3 m_CacheTarget;
    private Quaternion m_CacheRotation;


    private Quaternion CheckStickValue(Vector3 target, Vector3 center)
    {
        Quaternion rotation = m_CacheRotation;

        if (m_CacheTarget != target)
        {
            m_CacheTarget = target;

            Vector3 relativePos = target - center;
            if (relativePos.y < 0)
            {
                relativePos.y = 0;
            }
            rotation = Quaternion.LookRotation(relativePos);
            m_CacheRotation = rotation;

            if (OnStickChange != null)
            {
                try
                {
                    float axis_h = Vector3.Angle(transform.right, relativePos);
                    float axis_v = Vector3.Angle(transform.forward, relativePos);
                    float horizontal = (90 - axis_h) / 90;
                    float vertical = (90 - axis_v) / 90;
                    OnStickChange.Invoke(horizontal, vertical);
                }
                catch
                {
                    Debug.LogError("A delegate failed to execute for OnStickChange in XRStickInteractable");
                }
            }
        }
        return rotation;
    }

    // Start is called before the first frame update
    void Start()
    {
        if (MovingRigidbody == null)
        {
            MovingRigidbody = GetComponentInChildren<Rigidbody>();
        }
        if (MovingRigidbody != null)
        {
            m_StartRotation = MovingRigidbody.rotation;
        }
    }

    public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase updatePhase)
    {
        if (isSelected)
        {
            if (updatePhase == XRInteractionUpdateOrder.UpdatePhase.Fixed)
            {
                if (MovingRigidbody != null)
                {
                    Quaternion rotation = CheckStickValue(m_GrabbingInteractor.transform.position, MovingRigidbody.transform.position);
                    MovingRigidbody.MoveRotation(rotation);
                }
            }
        }
    }

    protected override void OnSelectEnter(XRBaseInteractor interactor)
    {
        base.OnSelectEnter(interactor);

        m_GrabbingInteractor = interactor;
    }

    protected override void OnSelectExit(XRBaseInteractor interactor)
    {
        base.OnSelectExit(interactor);

        if (MovingRigidbody != null)
        {
            MovingRigidbody.MoveRotation(m_StartRotation);
        }
    }
}



GetInputAction.cs는 조작할 게임에 의해 다시 작성되어야 합니다.

수평 방향의 움직임이 horizontal에 의해 -1~1의 범위로, 수직 방향의 움직임이 vertical에 의해 -1~1의 범위로 통지되어 오므로, 그것을 게임에 있던 움직임으로 변환합니다. GetInput은 조작 대상의 게임으로부터 불리는 처리입니다.




GetInputAction.cs

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

public class GetInputAction : MonoBehaviour
{
    private float m_CacheHorizontal = 0;
    private float m_CacheVertical = 0;

    public void GetStickValue(float horizontal, float vertical)
    {
        m_CacheHorizontal = horizontal;
        m_CacheVertical = vertical;
    }
    public float[] GetInput()
    {
        var action = new float[2];
        if (m_CacheHorizontal > 0.5f)
        {
            action[1] = 1f; //move right
        }
        else if (m_CacheHorizontal < -0.5f)
        {
            action[1] = 2f; //move left
        }
        if (m_CacheVertical > 0.5f)
        {
            action[0] = 1f; //move up
        }
        if (m_CacheVertical < -0.5f)
        {
            action[0] = 2f; //move down
        }
        return action;
    }
}


좋은 웹페이지 즐겨찾기