2

私は Unity を初めて使用し、Oculus Go 用の VR アプリを構築しています。コントローラーから光線をオブジェクトに向けてオブジェクトを選択して移動し、トリガーボタンを押して選択または解放したいと考えています。オブジェクトがコントローラーに突然来るのではなく、レイの位置の最後に固定されたままになるようにします。このスクリプトを使用して光線を作成し、基本的にコントローラーがそれを拾うことができるようにしましたが、このスクリプトはオブジェクトをコントローラーの位置に移動させ、その結果、オブジェクトを円内 (360 度) でしか移動できません。また、オブジェクトが浮き続けるため、オブジェクトを正しくドロップしません。

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

public class PlayerPointer : MonoBehaviour {

//Returns whatever object is infrount of the controller
private GameObject pointerOver;
[SerializeField]
//Is the object that is currently intractable
private PropBase selectedObject;
//Is the object currently stored in hand, ready to throw.
[SerializeField]
private PickUp inHand;

//This is a refrance to the object we want the pointer to be cast from.
[SerializeField]
public Transform controllerRef;
//This is where we want object we are holding to appear
[SerializeField]
private Transform holdingRef;
//The amount of force we want to throw objects from our hand with.
[SerializeField]
[Range(2,12)]
private float throwForce = 10;

//The script that handles the visuals to show what object is selected
[SerializeField]
private HighlightObject selectVisual;
private LineRenderer line;

void Start () {
    line = GetComponent<LineRenderer> ();
}

void Update () {
    //If a object is currently being held I don't want to select another 
object until it is thrown.
    if (inHand == null) {
        WorldPointer ();
    } else {
        line.SetPosition (0, controllerRef.position);
        line.SetPosition (1, controllerRef.position);
        pointerOver = null;
    }
    //This function handles how you intract with selected objects
    Intract ();
}

//This function handles shooting a raycast into the world from the 
controller to see what can be intracted with.
void WorldPointer(){
    //We set the line visual to start from the controller.
    line.SetPosition (0, controllerRef.position);

    RaycastHit hit;
    //We reset the pointer so things don't stay selected when we are 
pointing at nothing.
    pointerOver = null;

    //This sends a line from the controller directly ahead of it, it returns 
true if it hits something. Using the RaycastHit we can then get information 
back.
    if (Physics.Raycast (controllerRef.position, controllerRef.forward, out 
hit)) {
        //Beacuse raycast is true only when it hits anything, we don't need 
to check if hit is null
        //We set pointerOver to whatever object the raycast hit.
        pointerOver = hit.collider.gameObject;
        //We set the line visual to stop and the point the raycast hit the 
object.
        line.SetPosition (1, hit.point);

        //Here we check if the object we hit has the PropBase component, or 
a child class of its.
        if (pointerOver.GetComponent<PropBase> ()) {
            //We set the object to be highlighted
            selectVisual.NewObject (pointerOver);
        } else {
            selectVisual.ClearObject ();
        }
    } else {
        //If the raycast hits nothing we set the line visual to stop a
little bit infrount of the controller.
        line.SetPosition (1, controllerRef.position + controllerRef.forward 
* 10);
        selectVisual.ClearObject ();
    }

    Debug.DrawRay(controllerRef.position , controllerRef.forward * 
10,Color.grey);
}

void Intract(){
    //We set up the input "OculusTouchpad" in the Input manager
    if (Input.GetButtonDown ("Jump") || OVRInput.GetDown 
(OVRInput.Button.PrimaryTouchpad)) {
        selectVisual.ClearObject ();                
        //Check if you are holding something you can throw first
        if (inHand != null) {
            inHand.Release (controllerRef.forward, throwForce);
            inHand = null;
            //We do this check here to prevent Errors if you have nothing 
selected
        } else if (selectedObject != null) {
            //Check if you can pick up the selected object second
            if (selectedObject.GetComponent<PickUp> ()) {
                //Beacuse PickUp is a child of PropBase, we can ask InHand 
to store selectedObject as PickUp, rather than use GetComponent
                inHand = selectedObject as PickUp;
                inHand.Store (holdingRef);
                //If non of the above were valid then simple call the 
trigger function of the selected object
            } else {
                selectedObject.Trigger ();
            }
        }
        //If you have a object that you need to hold down a button to 
intract with
    } else if (Input.GetButton ("Jump") && selectedObject != null || 
OVRInput.Get (OVRInput.Button.PrimaryTouchpad) && selectedObject != null) {
        selectedObject.Pulse ();
        //When you are not pressing down the touchpad button, the selected 
object can be updated
    } else if (pointerOver != null) {
        if (pointerOver.GetComponent<PropBase> ()) {
            selectedObject = pointerOver.GetComponent<PropBase> ();
        } else {
            selectedObject = null;
        }
    } else {
        selectedObject = null;
    }

   }

}

そして、選択したいオブジェクトにこのスクリプトを添付しました:

public class PickUp : PropBase
{

private Rigidbody rb;

void Start()
{
    rb = GetComponent<Rigidbody>();
}

public virtual void Store(Transform NewParent)
{
    //The following stops the object being effected by physics while it's in 
the players hand
    rb.isKinematic = true;
    //And fixes it to the new parent it is given by the player script to 
follow.
    transform.parent = NewParent;
    //It then resets it's position and rotation to match it's new parent 
object
    transform.localRotation = Quaternion.identity;
    transform.localPosition = Vector3.zero;
}
public virtual void Release(Vector3 ThrowDir, float ThrowForce)
{
    //On Release the object is made to be effected by physics again.
    rb.isKinematic = false;
    //Free itself from following it's parent object
    transform.parent = null;
    //And applies a burst of force for one frame to propel itself away from 
the player.
    rb.AddForce(ThrowDir * ThrowForce, ForceMode.Impulse);
    }
}

私が見たいのは、レイの端がキャストされる場所に応じて球の位置が変化することです。

また、このスクリプトをプレーヤー コントローラにアタッチしました。これにより、ポイントをポイントしてタッチパッド ボタンを押すことでポイントに移動できます。

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

public class ClickToMove : MonoBehaviour
{

private Vector3 targetPos; //This Vector3 will store the position where we 
click to move.

private bool Moving = false; /*This bool keeps track of whether we are in 
the process of moving or not.*/

private GameObject targetInstance;

/*The variables we want to customize. Added info headers to these for the 
Unity Editor.*/

[Header("Our Go controller object")]

public GameObject goController;

[Header("Movement Speed")]

public float speed = 1;

[Header("Stop When This Far Away From Target")]

public float haltDistance = 0;

[Header("Optional Target Object")]

public GameObject targetObj;

void Update()

{

    MoveToTarget(); /*Here we simply run our MoveToTarget method in the 
Update method.*/

    //That way we don't clutter up the Update method with too much code.

}

void MoveToTarget() //Here we do the cluttering instead.

{

    var ray = new Ray(goController.transform.position, 
goController.transform.forward); /*Create a ray going from the goController 
position and in the Forward direction of the goController.*/

    RaycastHit hitInfo; //Store info about what the ray hits.

    Physics.Raycast(ray, out hitInfo, 100);

    if (OVRInput.GetUp(OVRInput.Button.PrimaryTouchpad)) /*If we release the 
trigger..*/

    {

        targetPos = hitInfo.point; /*Make our targetPos assume the 
positional value of the hit point.*/

        if (targetObj) /*If we have specified a Target Object to mark where 
we click*/

        //If we didn't, then we don't want to try to instantiate it.

        {

            if (targetInstance) /*If there is already a Target Object in the 
scene.*/

            {

                Destroy(targetInstance); //Destroy it.

            }

            targetInstance = Instantiate(targetObj, targetPos, 
transform.rotation); //Create our Target object at the position we clicked.

        }

        Moving = true; //And finally we set Moving to True.

    }

    if (Moving == true) //Since Moving is now true

    {

        transform.position = Vector3.MoveTowards(transform.position, new 
Vector3(targetPos.x, transform.position.y, targetPos.z), speed * 
Time.deltaTime); /*Transform our x and z position to move towards the 
targetPos.*/

        /*Note that our y position is kept at default transform position 
since we only want to move along the ground plane.*/

    }

    if (Vector3.Distance(transform.position, targetPos) <= haltDistance + 1) 
 /*Check proximity to targetPos. Mainly useful to keep your player from 
  setting a target position right next to say a building and then end up 
  clipping  through half of it.*/

    {

        if (targetInstance) //If we created a Target Object..

        {

            Destroy(targetInstance); //Then we want to destroy it when we 
reach it.

        }

        Moving = false; //Since we have now arrived at our target 
//destination.

    }

}

}

誰かが私を正しい方向に向けたり、これを手伝ってくれたりしたら、とても感謝しています!

前もって感謝します。

4

1 に答える 1