[英]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
,但可惜它也不适用于这个用例。
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。
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 个大的错误扇区,用红色标记,它们不应该存在。
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.我能想到几个选择。
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;
}
But again, it's sort of just trading one calculation for another.但同样,它只是用一种计算换另一种计算。
OnColliderEnter
, I think?) you can add them to that direction's list and remove when they exit ( OnColliderExit
maybe?).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.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.