简体   繁体   English

C# Unity 3D - 有没有办法制作自定义光线投射形状?

[英]C# Unity 3D - Is there a way to make custom raycast shapes?

I have a ship that will shoot targets, but cannons on the right side should never try to shot at targets on the left side of the ship.我有一艘可以射击目标的船,但右侧的大炮永远不应该尝试向船左侧的目标射击。 Thus I have created sectors using the SignedAngle function, this works fine for testing, but its also kind of broken as you can see from the visualization below.因此,我使用SignedAngle function 创建了扇区,这可以很好地进行测试,但从下面的可视化中可以看出,它也有点损坏。 I have tried using boxcast but alas it also doesnt work for this use case.我尝试过使用boxcast ,但可惜它也不适用于这个用例。

图像1

The above image visualizes what my script does, but this is not a solution to my problem.上图可视化了我的脚本的作用,但这不是我的问题的解决方案。 As targets close to the side and front of the ship will be outside the sector, for clarification what I mean, see picture 3.由于靠近船侧和前部的目标将位于该区域之外,为了澄清我的意思,请参见图 3。 img2

This second image shows what happens when we increase the angle, we can now detect more targets, but we have 2 big incorrect sectors marked in red which shouldnt be there.第二张图显示了当我们增加角度时会发生什么,我们现在可以检测到更多目标,但是我们有 2 个大的错误扇区,用红色标记,它们不应该存在。 img3 正确

Finally, this is how I think it should look, its still a cone, but the big difference is that it starts with a wide bottom, thus it resolves the problem Im having with the current SignedAngle function which determines everything from a single point in the middle.最后,这就是我认为它应该看起来的样子,它仍然是一个圆锥体,但最大的不同是它从一个宽底部开始,因此它解决了我在当前 SignedAngle function 中遇到的问题,它从单点确定一切中间。

This is the script for assigning targets to the correct list according to which sector they are in:这是根据目标所在的扇区将目标分配到正确列表的脚本:

foreach (Transform target in EnemyListManager.instance.enemyShips.ToArray())
        {

            if (Vector3.Distance(transform.position, target.position) > ship.mainGunCaliber.range)
                continue;

            Vector3 toTarget = target.position - transform.position;
            print(Vector3.SignedAngle(hullParent.forward, toTarget, Vector3.up));

            if (Vector3.SignedAngle(hullParent.forward, toTarget, Vector3.up) >= bowMinAngle &&
                Vector3.SignedAngle(hullParent.forward, toTarget, Vector3.up) <= bowMaxAngle)
            {
                if (!bowTargets.Contains(target))
                {
                    RemoveFromOthers(target);
                    bowTargets.Add(target);
                    print("added target to Bow");
                }
                continue;
            }
            if (Vector3.SignedAngle(hullParent.forward, toTarget, Vector3.up) >= sbMinAngle &&
                Vector3.SignedAngle(hullParent.forward, toTarget, Vector3.up) <= sbMaxAngle)
            {
                if (!sbTargets.Contains(target))
                {
                    RemoveFromOthers(target);
                    sbTargets.Add(target);
                    print("added target to SB");

                }
                continue;

            }
            if (Vector3.SignedAngle(-hullParent.forward, toTarget, Vector3.up) >= aftMinAngle &&
                Vector3.SignedAngle(-hullParent.forward, toTarget, Vector3.up) <= aftMaxAngle)
            {
                if (!aftTargets.Contains(target))
                {
                    RemoveFromOthers(target);
                    aftTargets.Add(target);
                    print("added target to Aft");

                }
                continue;
            }
            if (Vector3.SignedAngle(hullParent.forward, toTarget, Vector3.up) >= psMinAngle &&
                Vector3.SignedAngle(hullParent.forward, toTarget, Vector3.up) <= psMaxAngle)
            {
                if (!psTargets.Contains(target))
                {
                    RemoveFromOthers(target);
                    psTargets.Add(target);
                    print("added target to PS");

                }

            }
        }

Any help would be appreciated on how to tackle this problem!任何帮助将不胜感激如何解决这个问题!

Thank you.谢谢你。

There are a couple options I can think of.我能想到几个选择。

  1. You can use 4 (or more, for up-down range as well) points to measure the angles from instead of the single point from the center that I'd previously suggested.您可以使用 4 个(或更多,也适用于上下范围)点来测量角度,而不是我之前建议的中心的单个点。

在此处输入图像描述

Your code, for the starboard side, would then be more like (I think, I'm nautically inclined so I may be wrong about the labelling lol):你的代码,对于右舷,会更像(我认为,我倾向于航海,所以我可能对标签有误,哈哈):

if (Vector3.SignedAngle(markerBowStarboard.right, toTarget, Vector3.up) >= sbMinAngle &&
    Vector3.SignedAngle(markerAftStarboard.right, toTarget, Vector3.up) <= sbMaxAngle)
{
    if (!sbTargets.Contains(target))
    {
        RemoveFromOthers(target);
        sbTargets.Add(target);
        print("added target to SB");

    }
    continue;
}
  1. You could try to adapt something from this "ConeCast" extension method someone made.您可以尝试从某人制作的这种“ConeCast”扩展方法中进行调整。 It still has the issue of being from the central point, but you may be able to tweak it to start the cast, for example, further left of the ship and check that the target is on the right of the ship (convert the target global position to the local reference frame of the ship and check x/y is >0/<0).它仍然存在来自中心点的问题,但是您可以调整它以开始施法,例如,在船的更左侧并检查目标是否在船的右侧(将目标全局转换为position 到船舶的局部参考系并检查 x/y 是否 >0/<0)。 It's sort of just trading one manual calculation for another, though.不过,这有点像用一种手动计算换另一种。
  2. Stealing from rustyBucketBay's answer a bit, you could use the larger of the SphereCast cylinders and use some trig to rule out ships that are less than a distance from the ship based on the cosine of the angle illustrated here:rustyBucketBay 的答案中窃取一点,您可以使用较大的 SphereCast 圆柱体,并使用一些三角函数来排除距离小于船舶距离的船舶,基于此处所示角度的余弦:

在此处输入图像描述

But again, it's sort of just trading one calculation for another.但同样,它只是用一种计算换另一种计算。

  1. You could create a conic cylinder model, don't render it but give it a MeshCollider, and then when objects enter the object ( OnColliderEnter , I think?) you can add them to that direction's list and remove when they exit ( OnColliderExit maybe?).您可以创建一个圆锥圆柱体 model,不要渲染它,而是给它一个 MeshCollider,然后当对象进入OnColliderEnter (我认为是 OnColliderEnter ?)您可以将它们添加到该方向的列表并在它们退出时删除(可能是OnColliderExit ? )。 You may need to do some more checking on when it is fully inside the conic cylinder though, because I think OnColliderExit (or whatever it's called) is triggered when the model stops colliding with the actual mesh, regardless of whether it is inside or outside of the object.你可能需要做更多的检查,当它完全进入圆锥圆柱体时,因为我认为当 model 停止与实际网格碰撞时会触发OnColliderExit (或任何它的名称),无论它是在内部还是外部object。

I'm not super sure I like any of those that much, but I'm surprised that there isn't a native "ConeCast" that can take near- and far-plane dimensions... but then I guess I'm just saying to Unity "I don't wanna do it, you do it" lol.我不太确定我是否喜欢其中任何一个,但我很惊讶没有可以采用近平面和远平面尺寸的原生“ConeCast”......但我想我只是对 Unity 说“我不想这样做,你来做”大声笑。

Some random ideas here.这里有一些随机的想法。 I would try discard the not desired sector with 2 sphere casts of different diameter.我会尝试用 2 个不同直径的球体铸件丢弃不需要的扇区。 ( https://docs.unity3d.com/ScriptReference/Physics.SphereCast.html ). https://docs.unity3d.com/ScriptReference/Physics.SphereCast.html )。 See beam2 and beam1 and the in the image below.请参见下图中的 beam2 和 beam1 以及 。

在此处输入图像描述

You can set the length of detection with maxDistance argument of the spheres cast.您可以使用球体投射的maxDistance参数设置检测长度。 This will determine the length of the cone, so the Starboard Aim Sector length.这将确定圆锥体的长度,即右舷瞄准扇区长度。 The zone green lined is for the points that are detected by the beam2 but not beam1.带绿线的区域用于由 beam2 但不是 beam1 检测到的点。

What to do with those points?这些点怎么办? Some are inside the cone, and some are not.有些在锥体内,有些不在。 A cone is simply an infinite number of circles whose size is defined by a linear equation that takes the distance from the point.锥体只是无数个圆,其大小由一个线性方程定义,该方程取该点的距离。 So with the distance from the rays origin in the beams direction, you know the circle size of that section of the cone.因此,通过在光束方向上与光线原点的距离,您知道圆锥体该部分的圆大小。 You should then easily be able to know if your point is in/out that circle, so in/out of the cone.然后,您应该能够轻松地知道您的点是否在该圆圈内/外,因此在圆锥内/外。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM