c# - 眼珠Go : Picking up/Moving object

标签 c# unity-game-engine virtual-reality oculus oculusgo

我对 Unity 非常陌生,正在为 Oculus Go 构建 VR 应用程序。我想通过将 Controller 的光线指向对象来拾取和移动对象,然后通过按下触发按钮来拾取或释放它。我希望对象保持固定在射线位置的末端,而不是突然到达 Controller 上。我使用这个脚本创建了一条射线,基本上允许 Controller 拾取它,但是这个脚本将对象移动到 Controller 的位置,因此我只能在一个圆圈内(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);
    }
}

我希望看到的是球体的位置根据光线末端的转换位置而变化。

我还将此脚本附加到播放器 Controller ,这允许它通过指向某个点并按下触摸板按钮来移动到该点。

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.

    }

}

}

如果有人能指出我正确的方向或帮助我,我将不胜感激!

提前致谢。

最佳答案

好的,根据您更新的问题,现在可以尝试回答。

首先 - 您是否尝试过不将 BaseProp localPosition 重置为 Controller 的? 尝试注释显示

的行
transform.localPosition = Vector3.zero;

这仍然会定向对象并将其作为 Controller 的父级,但会将其锁定在相对于父级设置时刻的位置。

您当前使用“holdingRef”对象作为该对象出现的位置。您可能想使用“controllerRef”。

要改变对象出现的距离,您可以将对象位置设置为:

controllerRef.position+ distance*controllerRef.forward

因为这是您发射光线转换的方向。通过查询hit.distance可以得到命中距离。

如果由于任何原因对您不起作用,则光线转换击中碰撞体的点在 HitInfo 中可用,因此使用 hit.point 您可以提取击中位置并相对于该点定位对象。 hitinfo 的另一个非常有用的属性是 .normal,它使您能够获得命中发生的方向。 您可以将该信息与 Store 方法一起传递。

关于c# - 眼珠Go : Picking up/Moving object,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53042819/

相关文章:

c# - Samsung Gear VR - 将武器附加到玩家身上

youtube - 在360度和2D视频之间切换?

c# - 访问 process.MainModule.FileName 时出现拒绝访问异常

c# - DateTimeFormatInfo.InvariantInfo 不一致的日期模式?

android - 如何在 unity hub 上为 android 激活构建和运行

c# - UNET 多人游戏,让两个玩家与游戏对象交互,在主机和客户端上同步更改

c# - .NET Core EndRequest 中间件

c# - 有符号与无符号整数的长度/计数

unity-game-engine - 如何在Unity中进行没有物理的碰撞检测?

unity3d - 使用 Unity 构建的 Oculus Go VR 应用程序中的 Web 浏览器