Unity:3D 运动/碰撞检测失败(AddForce、MovePosition、transform.localPosition)
Posted
技术标签:
【中文标题】Unity:3D 运动/碰撞检测失败(AddForce、MovePosition、transform.localPosition)【英文标题】:Unity: 3D movement/Collision detection failure (AddForce, MovePosition, transform.localPosition) 【发布时间】:2019-09-02 00:04:06 【问题描述】:问题: 如果我让运动正常工作,则不会检测到碰撞网格。如果我检测到碰撞网格,则运动无法正常工作。
项目简介: 我有一个 3D 环境,其中包含不可移动对象(带有碰撞器网格)和可移动游戏对象(带有 x2 盒碰撞器的刚体),我通过 C++ 应用程序中的 UDP 连接使用触觉设备(基本上是 3D 操纵杆)进行控制在 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);
另外,从@Ali Baba 的 cmets 更新: 我还没有时间测试其他方法,但是通过使用 AddForce 并使用拖动和力修改器变量,我能够控制所有三个轴(实际上是 6DOF,因为我也有来自第二个的旋转控制外部设备)并且我对我的游戏对象的控制也比以前更好(特别是由于拖动和力修改器变量的调整)。这可能是最好的解决方案,但我最初需要根据我正在使用的外部设备的位置来改变我的位置。我正在添加一个基本的、精简的、调整过的代码,它使用 AddForce 并允许对拖动和我的力修饰符变量进行 keycontrol 调整,以防其他初学者也看到这个线程。同时,我将尝试让其他功能(MovePosition 等)工作并更新结果。
Slim,基本的拖拽/变量测试代码:
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 时,哪个轴不会改变? 感谢您的 cmets。刚体参数:1质量,0阻力,0 a.drag,重力关闭,运动学关闭,无插值,碰撞检测离散,无约束。它的 x 轴在使用 AddForce 时不起作用(不过,这三个轴都可以使用简单的 transform.localposition)。 【参考方案1】:您可以尝试在您希望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);
感觉最好的
【讨论】:
感谢您的 cmets @阿里巴巴。我相信我已经尝试过了,它使我无法在其中一个轴上运动。我会继续重试并很快更新结果。 你好。为了简化事情,我将基本代码添加到一个干净的 3D 环境中,其中一个基本立方体作为我的刚体,另一个基本立方体作为非刚性对撞机。使用 rb.AddForce 在所有三个轴上都有效,但移动非常笨拙。也许我将查看的原始 3D 环境有问题,但我仍然无法为我的特定应用程序使用 rb.AddForce(有或没有比例/幅度调整)。不过,这比以前有所改进,所以谢谢。我认为 movePosition 会更好地工作,如果我能设法使其工作。 很高兴听到它至少可以工作一点。您还应该尝试增加刚体阻力。使用参数可能会使其正常工作,但对于您的目标可能仍然不够好。干杯 感谢您的建议。我将调整拖动并使用其他一些变量进行播放,看看效果如何。如果我使用 AddForce 计算出好的参数,或者如果我最终得到另一个函数来工作,比如 MovePosition,我会更新。 因此,AddForce 选项适用于测试。谢谢您的帮助。我现在正在迁移到 movePosition 选项,同时通过一个单独的应用程序生成碰撞模型,该应用程序将同时运行。最终,这更符合我的项目要求。以上是关于Unity:3D 运动/碰撞检测失败(AddForce、MovePosition、transform.localPosition)的主要内容,如果未能解决你的问题,请参考以下文章