Oculus Go: собирание / перемещение объекта - PullRequest
0 голосов
/ 29 октября 2018

Я очень плохо знаком с Unity и создаю приложение для виртуальной реальности для Oculus Go. Я хочу выбрать и переместить объект, наведя луч от контроллера на объект, а затем выбрав или отпустив его, нажав кнопку запуска. Я хочу, чтобы объект оставался неподвижным в конце положения луча, а не внезапно попадал на контроллер. Я использовал этот скрипт для создания луча и в основном позволяю контроллеру поднять его, но этот скрипт перемещает объект в положение контроллера, и в результате я могу перемещать объект только по кругу (на 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.

    }

}

}

Если бы кто-нибудь мог указать мне правильное направление или помочь мне в этом, я был бы очень признателен!

Заранее спасибо.

1 Ответ

0 голосов
/ 29 октября 2018

Хорошо, с вашим обновленным вопросом теперь можно попытаться ответить.

Во-первых, вы пытались не сбрасывать локальную позицию BaseProp на контроллер? Попробуйте прокомментировать строку с надписью

transform.localPosition = Vector3.zero;

Это по-прежнему будет ориентировать объект и привязывать его к контроллеру, но заблокирует его в положении относительно момента родительского контроля.

В настоящее время вы используете объект «holdingRef» как место, где этот объект появляется. Вы можете использовать вместо этого «controllerRef».

Чтобы изменить расстояние, на котором появляется объект, вы можете установить положение объекта:

controllerRef.position+ distance*controllerRef.forward

Поскольку это направление, в котором вы запускаете свои лучевые трансляции. Вы можете получить расстояние удара, запросив hit.distance.

Если по какой-либо причине это не сработало для вас, сама точка лучевого вещания, попадающая в коллайдер, доступна в HitInfo, поэтому с помощью hit.point вы можете извлечь позицию удара и расположить объект относительно этой точки. Другим очень полезным атрибутом hitinfo является .normal, который позволяет вам определить направление, в котором произошло попадание. Вы можете передать эту информацию вместе с вашим методом Store.

...