Unity:3D 运动/碰撞检测失败(AddForce、MovePosition、transform.localPosition)

4
问题: 如果我让移动正确工作,那么碰撞网格就无法被检测到。如果我让碰撞网格被检测到,那么移动就不能正常工作。 项目简介: 我有一个三维环境,其中包含不可移动的对象(带有碰撞器网格),以及一个可移动的游戏对象(具有x2盒子碰撞器的刚体),我正在使用触觉设备(基本上是3D操纵杆)通过UDP连接在运行Unity应用程序时控制它们。我已经组装了一个C++应用程序,并且在Unity应用程序运行时运行。触觉设备和Unity之间的通信非常好。我正在使用从触觉设备传递的位置信息作为移动游戏对象的变量。再次强调,位置数据可以很好地到达Unity;在Unity中使用位置数据的适当条件和函数的方法是我目前遇到的问题。

我尝试过的方法: 如果我使用 transform.localPosition (hapticDevicePosition);则移动效果很好,但会忽略所有碰撞器并穿过它们。我在网上阅读并了解到,transform.localPosition基本上会将我的对象移到其他对象的顶部而不考虑物理学问题。我还了解到,我可能可以引入一条射线,就像在我的对象前面0.000001这样的射线,以便如果射线与任何其他对象交互,则防止移动。这可能是仍然能够使用transform.localPosition的一种方式?我不确定,而且我从未使用过射线,所以设置脚本可能会很困难。

我尝试了AddForce。这个行为非常奇怪。它只给我2个力量输出而不是3个...也就是说,我只能在3个轴中的2个轴上移动。我不明白为什么它会这样行事。碰撞器被检测到,但是移动效果奇怪。

我尝试了rb.MovePosition (rb.position + posX + posY + posZ) 以及各种组合的*Time.timeDelay 和 *speed。这也不能正常工作。碰撞器被检测到,但是移动要么根本不起作用,要么没有正确工作。

结论: 我已经花了近4个小时调试我的脚本,有些尝试并没有成功,所以它们的注释还在(请查看下面附上的代码)。我会继续阅读更多的在线解释,尝试不同的代码,并在这里更新,如果我找到了解决方案。如果任何人有一些提示或建议,在此期间,我将非常感激。

谢谢!

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

 public class FalconPegControl_2 : MonoBehaviour {

     // Define needed variables
     private TestUDPConnection udpListener;

     public Vector3 realObjectCurrentPos;
     private Vector3 realObjectLastPos;

     public Vector3 realObjectCurrentRot;
     private Vector3 realObjectLastRot;

     public Vector3 realObjectPosChange;
     public Vector3 realObjectRotChange;

     private Quaternion rotation;
     //public float pi = 3.14f;

     private Rigidbody rb;
     private int control = 0;
     public bool collisionOccurred = false;

     //public float thrust = 1000; 

     //public CalibrationManager calibrationManager;

     // Use this for initialization
     void Start () {
         udpListener = GetComponentInParent<TestUDPConnection>();
         collisionOccurred = false;
         rb = GetComponent<Rigidbody> ();
         SharedRefs.falconPegControl = this;
     }

     public void OffControl ()
     {
         control = 0;
     }

     public void CollisionDuplicateFix ()
     {
         collisionOccurred = true;
     }

     // Update is called once per frame
     void FixedUpdate () {

         //WITHOUT UNITY AXIS CONVERSION:
         //realObjectCurrentPos[0] = udpListener.xPosReal; //[m]
         //realObjectCurrentPos[1] = udpListener.yPosReal; //[m]
         //realObjectCurrentPos[2] = udpListener.zPosReal; //[m]

         //===============================
         //Unity axis conversions:
         //CHAI3D --> Unity
         //(x, y, z) --> (x, -z, y)
         //CHAI3D: realObjectCurrentPos[0], [1], [2] is CHIA3D (x, y, z)
         //Also, to compensate for the workspace available to the Falcon Device (~0.04, ~0.06, ~0.06)
         //adding a value of x10 allows it to reach the default hemisphere successfully
         //updated comment: the sign values that work (-, +, -)
         //===============================

         //Unity conversion for rotation (using Falcon devices)
         //Since one falcon is for translation and the other is for rotation,
         //the rotation information is a conversion of translational information
         //in other words, max range of (~0.04, ~0.06, ~0.06) has been converted into a max range of (90, 90, 90)
         //using basic algebra (i.e., (90/0.04))
         //thus giving the user the full range of 180 degrees (from 90 degrees to -90 degrees)

         realObjectCurrentPos[0] = udpListener.xPosReal * (-5); //[m]
         realObjectCurrentPos[1] = udpListener.zPosReal * (5); //[m]
         realObjectCurrentPos[2] = udpListener.yPosReal * (-5); //[m]


         realObjectCurrentRot [0] = udpListener.xRot * (90f / 0.04f); //degrees
         realObjectCurrentRot [1] = udpListener.yRot * (90f / 0.06f); //degrees
         realObjectCurrentRot [2] = udpListener.zRot * (90f / 0.06f); //degrees


         if (Input.GetKeyDown ("1")) {
             control = 1;
             SharedRefs.stopWatch.startTimer ();
         }

         if (Input.GetKeyDown ("space")) 
         {
             OffControl ();
         }

         if (control==1)
         {

             Vector3 posUnity = new Vector3 (realObjectCurrentPos[0], realObjectCurrentPos[1], realObjectCurrentPos[2]);
             rb.AddForce (posUnity);

             //Vector3 tempVect = new Vector3(realObjectCurrentPos[0], realObjectCurrentPos[1], realObjectCurrentPos[2]);                 
             //Vector3 startPoint = new Vector3 (0f, 0.0225f, 0f);
             //tempVect = tempVect * speed * Time.deltaTime;

             //transform.localPosition = realObjectCurrentPos; //[m]



             //var unityX = Vector3.Scale (posTemp, Vector3.right);
             //var unityY = Vector3.Scale (posTemp, Vector3.up);
             //var unityZ = Vector3.Scale (posTemp, Vector3.forward);

             //Vector3 unityX = new Vector3 (Vector3.Scale (posTemp, Vector3.right), Vector3.Scale (posTemp, Vector3.up), Vector3.Scale (posTemp, Vector3.forward));
             //Vector3 unityY = new Vector3 (Vector3.Scale (posTemp, Vector3.up));
             //Vector3 unityZ = new Vector3 (Vector3.Scale (posTemp, Vector3.forward));

             //rb.MovePosition (rb.position + unityX + unityY + unityZ);
             //transform.localPosition = (startPoint + tempVect); //[m]

             transform.localRotation = Quaternion.Euler(realObjectCurrentRot); //[m]

             realObjectLastPos = realObjectCurrentPos;//[m]
             realObjectLastRot = realObjectCurrentRot;//[m]

             realObjectPosChange = realObjectCurrentPos - realObjectLastPos; //[m]
             realObjectRotChange = realObjectCurrentRot - realObjectLastRot;


         }
         else if (control==0) 
         {
             Vector3 stop = new Vector3 (0, 0, 0);
             rb.constraints =  RigidbodyConstraints.FreezePositionZ | RigidbodyConstraints.FreezeRotationZ;
             rb.constraints =  RigidbodyConstraints.FreezePositionX | RigidbodyConstraints.FreezeRotationX;
             rb.constraints =  RigidbodyConstraints.FreezePositionX | RigidbodyConstraints.FreezeRotationX;
             rb.velocity = (stop);
         }
     }
 }

此外,根据@阿里巴巴的评论进行了更新: 我还没有时间测试其他方法,但是通过使用AddForce并玩弄拖动和力量修改器变量,我能够控制所有三个轴(实际上是6DOF,因为我还有来自第二个外部设备的旋转控制),而且我对我的游戏对象的控制比以前更好(具体是由于拖动和力量修改器变量的调整)。这可能是最好的解决方案,但我最初需要根据我正在使用的外部设备的位置改变我的位置。我正在添加一个基本的、简化的、调整过的代码,它使用AddForce并允许对拖动和我的力量修改器变量进行按键控制调整,以防其他初学者也看到这个线程。同时,我将尝试使其他功能(MovePosition等)正常工作,并更新结果。
基本拖动/变量测试代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Real_Controller : MonoBehaviour {

    // Define needed variables
    private TestUDPConnection udpListener;
    public Vector3 realObjectCurrentPos;
    public Vector3 realObjectCurrentRot;
    private Quaternion rotation;
    private Rigidbody rb;
    private float increaseForce = 23;

    // Use this for initialization
    void Start () {
        udpListener = GetComponentInParent<TestUDPConnection>();
        rb = GetComponent<Rigidbody> ();
        rb.drag = 1.24f;
    }

    // Update is called once per frame
    void FixedUpdate () {

        if (Input.GetKeyDown ("q")) 
        {
            rb.drag -= 0.1f;
            Debug.Log ("drag is: " + rb.drag);
        }

        if (Input.GetKeyDown ("w")) 
        {
            rb.drag += 0.1f;
            Debug.Log ("drag is: " + rb.drag);
        }

        if (Input.GetKeyDown ("a")) {
            increaseForce -= 1f;
            Debug.Log ("increased force is: " + increaseForce);
        }

        if (Input.GetKeyDown ("s")) {
            increaseForce += 1f;
            Debug.Log ("increase force is: " + increaseForce);
        }



        realObjectCurrentPos[0] = udpListener.xPosReal * (-increaseForce); //[m]
        realObjectCurrentPos[1] = udpListener.zPosReal * (increaseForce); //[m]
        realObjectCurrentPos[2] = udpListener.yPosReal * (-increaseForce); //[m]



        Vector3 forceDirection = realObjectCurrentPos - transform.localPosition;
        rb.AddForce (forceDirection * forceDirection.magnitude);



        realObjectCurrentRot [0] = udpListener.xRot * (90f / 0.04f); //degrees
        realObjectCurrentRot [1] = udpListener.yRot * (90f / 0.06f); //degrees
        realObjectCurrentRot [2] = udpListener.zRot * (90f / 0.06f); //degrees


        transform.localRotation = Quaternion.Euler(realObjectCurrentRot); //[m]


    }
}

问候,我可以问一下你的RigidBody和物理参数是什么吗?它使用重力吗?另外,在使用AddForce时,哪个轴不会改变? - S.Fragkos
感谢您的评论。刚体参数:1质量,0阻力,0角阻力,关闭重力,关闭动力学,插值无,碰撞检测离散,无约束。当使用AddForce时,只有x轴不起作用(但使用简单的transform.localposition时,所有三个轴都有效)。 - user70711
1个回答

2

不要将gameObject放置在控制器的确切位置,您可以尝试向您想要gameObject处于的位置方向施加力:

最初的回答:

 if (control==1)
 {
     Vector3 forceDirection = realObjectCurrentPos - transform.localPosition;

     rb.AddForce (forceDirection);

     transform.localRotation = Quaternion.Euler(realObjectCurrentRot)
 }

这里施加的力与gameObject位置和真实物体之间的距离成线性关系,因此基本上表现为弹簧的行为。您应该尝试将力乘以不同的因子并进行测试:

最初的回答:

 rb.AddForce (forceDirection * 0.5f);

最初的回答:或者进行二次缩放:
 rb.AddForce (forceDirection * forceDirection.magnitude);

Whatever feels best


感谢您的评论,@Ali Baba。我相信我已经尝试过这个方法,但它会锁定其中一个轴的运动。我将再次尝试并很快更新结果。 - user70711
再次你好。为了简化问题,我将基础代码添加到一个干净的3D环境中,其中一个基础立方体作为我的刚体,另一个基础立方体作为非刚体碰撞器。 使用rb.AddForce在所有三个轴上都有效,但移动非常笨拙。也许我的原始3D环境有问题,我会检查一下,但我仍然不能在特定应用程序中使用rb.AddForce(无论是否进行了比例/大小调整)。尽管如此,这已经是一个进步,所以谢谢你。如果我能够使它正常工作,我认为movePosition会更好用。 - user70711
1
很高兴听到它至少有点作用。你还应该尝试增加刚体的阻力。通过调整参数,你可能可以使它正常运行,但它仍然可能不足以满足你的目标。干杯! - Ali Baba
谢谢你的建议。我会调整拖拽并尝试其他变量,看看效果如何。如果我使用AddForce找到了好的参数,或者如果我最终使用MovePosition等其他函数,我会进行更新。 - user70711
所以,AddForce选项在测试中起作用了。感谢您的帮助。现在我正在迁移到movePosition选项,同时通过一个单独的应用程序生成碰撞模型,这将与其同时运行。最终,这更符合我的项目要求。 - user70711
@user70711 请查看这里 - Ruzihm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接