【问题标题】:unity restrict moving object on a planeunity 限制平面上的移动物体
【发布时间】:2018-05-31 18:40:26
【问题描述】:

我想限制一个平面上的移动物体(平面可能是也可能不是正方形)这里是原型:

我在平面上附加了一个网格对撞机,希望用它来限制球体的运动,球体将随机移动,想法是当球移动到边缘时,速度会被反射,所以它不会下落带着这个下飞机:

public class BallScript : MonoBehaviour {

    // Use this for initialization
    void Start () {
        GetComponent<Rigidbody>().velocity = new Vector3(0.1f,0,0.1f);

    }

    private void OnCollisionExit(Collision collision)
    {
        GetComponent<Rigidbody>().velocity = -GetComponent<Rigidbody>().velocity;
    }
}

但是球一直掉在边缘,

我无法制作边缘对撞机,因为飞机的形状要到运行时才能确定。

有没有办法做到这一点?

【问题讨论】:

  • 当你说边缘对撞机时,你的意思是this
  • 不,我注意到有一个精确的 2d 边缘对撞机,但不是 3d,我的意思是在平面边缘周围建造一种“墙”,以使用对撞机将球保持在里面
  • 嗯,你试过RayCast吗?
  • @TheGinxx009 你的意思是从球上投射光线并检测飞机的边缘面吗?
  • 你可以使用SqrMagnitudeRayCast来实现

标签: c# unity3d


【解决方案1】:

当对象不再与其他对象发生碰撞时,将调用OnCollisionExit 函数。在您的情况下,它不会在球位于平面边缘时调用,而是在球不再接触平面时调用。

最安全的方法是使用 BoxCollider。我建议你只使用 Unity 的 Cube 原语,它带有 BoxCollider。其上的网格将很有用,并且在调整 BoxCollider 大小时应充当视觉指南。

1.Go to GameObject ---> 3D Object ---> Cube 并创建新的立方体对象。查看飞机的形状,您将需要 6 个 BoxCollider,这意味着您需要 6 个立方体。

2。调整大小、移动和旋转每一个,直到它们覆盖平面的每一侧。

3.创建新层并将其命名为“边界”。选择每个立方体并将图层设置为“边界”。

4.Got to Edit ---> Project Settings ---> Physics 并使用层碰撞矩阵,确保“边界”不会与“边界”发生碰撞。

5。禁用或删除每个立方体的MeshRenderer,仅此而已。

您问题中的代码是不必要的,但如果您仍希望它反映,请使用OnCollisionEnter 并检查球何时撞到墙上。

附在球上:

Rigidbody rb;
public float force = 50;

void Start()
{
    rb = GetComponent<Rigidbody>();
}
void OnCollisionEnter(Collision col)
{
    if (col.collider.CompareTag("Boundary"))
        rb.AddForce(col.contacts[0].normal * force, ForceMode.Impulse);
}

【讨论】:

  • 感谢您的建议,但是平面的大小(即平面的边界形状)要到运行时才能确定,实际上它可能会在运行时发生变化。因此,我无法在编辑器中编辑边界,并且使用代码在运行时编辑它似乎需要做很多工作并且面向错误,我正在寻找一种避免这种情况的方法。也许 Raycast 是一个承诺者,现在就试试吧。
  • 光线投射是另一种实现此目的的方法,但光线投射会使球飞出该平面的机会很高。 “平面的边界形状)直到运行时才确定”没关系,您仍然可以通过代码在我的答案中进行所有操作。创建新的游戏对象,然后将 BoxCollider 附加到它并调整大小/旋转它们。
【解决方案2】:

所以这只是一个想法,因为 OP 同意将此作为答案

 public Layer[] layerPriorities =
{
    Layer.Enemy,
    Layer.Walkable
};

 [SerializeField] float distanceToBackground = 100f;

public delegate void OnLayerChange(Layer newLayer); // declare new delegate type
//lets use event for the protection of the layerchanges
public event OnLayerChange onlayerChange; // instantiate a observer set

//Look for and return priority layer hit
    foreach (Layer layer in layerPriorities)
    {
        var hit = RaycastForLayer(layer);
        if (hit.HasValue)
        {
            raycastHit = hit.Value;
            if(layerHit != layer){ //if layer has changed
                layerHit = layer;
                onlayerChange(layer); //call the delegate
            }
            layerHit = layer;
            return;
        }
    }
    // otherwise return background hit
    raycastHit.distance = distanceToBackground;
    layerHit = Layer.RaycastEndStop;

}
//? is a nullable parameter
RaycastHit? RaycastForLayer(Layer layer)
{
    /*(Use a bitshift) <<*/
    int layerMask = 1 << (int)layer; // lets do masking formation
    Ray ray = viewCamera.ScreenPointToRay(Input.mousePosition);

    RaycastHit hit; //used as an out parameter
    bool hasHit = Physics.Raycast(ray, out hit, distanceToBackground, layerMask);
    if (hasHit)
    {
        return hit;
    }
    return null;
}

并为此创建一个枚举

public enum Layer
{
    Walkable = 8,
    RaycastEndStop = -1 //lowest priority
}

作为Layer.Enemy,,您可以将其设置为NotWalkable,这取决于您。

所以这里缺少的小部分只是计算球到平面边缘的距离,而不是点击它。这就是我要告诉你的关于SqrMagnitude

【讨论】:

  • 你从屏幕的点击位置射出射线,在我的情况下,我应该从球上射出射线,我会稍微向下倾斜射线以确保射线可以击中飞机的侧面,对吧?
  • 是的,但我猜不是倾斜,而是使用 SqrMagnitude 。哈哈哈或者是的,这取决于你。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-24
  • 2019-11-14
  • 2022-12-20
  • 1970-01-01
  • 1970-01-01
  • 2017-05-09
相关资源
最近更新 更多