【问题标题】:2D colliders on XZ planeXZ 平面上的二维对撞机
【发布时间】:2019-11-21 17:47:38
【问题描述】:

我正在 Unity3D 中构建一个 3d 游戏,当用户处于顶视图时,用户可以在地面上绘图。

线条是使用LineRenderer 组件绘制的。

我想让用户能够选择他绘制的线条,以便他可以删除它们。但不幸的是,我没有找到一个好的方法来做到这一点。如果我使用 3D 对撞机,唯一适合的就是 BoxCollider,但它太大了(我只想要对撞机就行了)。

我不能使用 2D 对撞机,因为它们只能在 XY 平面上工作。

我尝试将线转换为网格并仅使用MeshCollider,但线太复杂,MeshCollider 无法将其正确放置在线上。

你知道我该怎么做吗?

附言

我正在使用 Ray casts 选择游戏中的对象。

【问题讨论】:

    标签: c# unity3d


    【解决方案1】:

    如果MeshCollider 过于复杂,但BoxCollider 不够精确,请尝试沿线段使用多个BoxColliders。

    可以在此处找到实现:

    https://answers.unity.com/questions/1546512/detect-mouse-click-on-line-renderer.html

    如果链接断开,这里是代码:

     using UnityEngine;
     using System.Collections;
     using System.Collections.Generic;
    
     [RequireComponent(typeof(LineRenderer))]
     public class LineCollider : MonoBehaviour
     {
         LineRenderer line;
         public void Start() {
             AddCollider(6); //Increase the count of parts(6) if you want to get more detailed collider
         }
         public void AddCollider(int part)
         {
             try
             {
                 line = GetComponent<LineRenderer>();
                 var start = line.GetPosition(0);
                 var end = line.GetPosition(line.positionCount - 1);
                 var a = (line.positionCount - 1) / part;
                 for (int i = 1; i<=part; i++)
                 {
                     if (i == 1)
                         AddColliderToLine(start, line.GetPosition(Mathf.CeilToInt(a * 1)));
                     else if (i == part)
                         AddColliderToLine(line.GetPosition(Mathf.CeilToInt(a * (i - 1))), end);
                     else
                         AddColliderToLine(line.GetPosition(Mathf.CeilToInt(a * (i - 1))), line.GetPosition(Mathf.CeilToInt(a * i)));
                 }            
             }
             catch
             {
                 Destroy(gameObject);
             }
         }
    
         private void AddColliderToLine(Vector3 start, Vector3 end)
         {
             var startPos = start;
             var endPos = end;
             BoxCollider col = new GameObject("Collider").AddComponent<BoxCollider>();
             col.transform.parent = line.transform;
             float lineLength = Vector3.Distance(startPos, endPos);
             col.size = new Vector3(lineLength, 0.175f, 0.25f);
             Vector3 midPoint = (startPos + endPos) / 2;
             col.transform.position = midPoint;
             float angle = (Mathf.Abs(startPos.y - endPos.y) / Mathf.Abs(startPos.x - endPos.x));
             if ((startPos.y < endPos.y && startPos.x > endPos.x) || (endPos.y < startPos.y && endPos.x > startPos.x))
             {
                 angle *= -1;
             }
             angle = Mathf.Rad2Deg * Mathf.Atan(angle);
             col.transform.Rotate(0, 0, angle);
         }
     }
    

    作为替代方案,更性能但更难实现:将线条写入纹理并对您点击的像素进行采样 - 每条线条应具有不同的颜色。当线条重叠绘制时,这也可以确保您有一些 z 顺序。

    请在此处查看我的答案以获得想法:How does Java / OS detect click co-ordinates on a viewport?

    【讨论】:

    • 使用如此糊状的碰撞器会不会降低效率?因为场景中可能有很多线条
    • 这也不准确,为了准确起见,我需要创建很多对撞机(位置 count-1)
    • 与少数meshcollider相比,许多Boxcollider的性能都非常好。
    • 作为替代方案:再次绘制线条(内部到纹理中)并为每条线条使用特定颜色。有一张地图,您可以在其中存储颜色对线条的依赖性。颜色充当标识。例如,#05Af02 是“第 5 行”。然后,您可以编写自己的“光线投射”,在您单击的像素处对纹理进行采样,并为您提供线条的 id。这将是最高效的方式。
    • 这听起来很有趣,我会尝试搜索更多相关内容
    猜你喜欢
    • 1970-01-01
    • 2018-06-20
    • 1970-01-01
    • 1970-01-01
    • 2020-06-25
    • 2014-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多