我有一艘可以射击目标的船,但右侧的大炮永远不应该尝试射击船左侧的目标。因此,我使用 SignedAngle
函数创建了扇区,这对于测试来说效果很好,但它也有点损坏,正如您从下面的可视化中看到的那样。
我尝试过使用 boxcast
但遗憾的是它也不适用于此用例。
上图可视化了我的脚本所做的事情,但这不是我的问题的解决方案。由于靠近船侧和前部的目标将在扇区之外,为了澄清我的意思,请参见图 3。
第二张图片显示了当我们增加角度时会发生什么,我们现在可以检测到更多目标,但是我们有 2 个用红色标记的不正确的大扇区,它们不应该在那里。
最后,这就是我认为它应该看起来的样子,它仍然是一个圆锥体,但最大的不同是它从一个宽底部开始,因此它解决了我在当前 SignedAngle 函数中遇到的问题,该函数从单个角度确定所有内容点在中间。
这是根据目标所在的扇区将目标分配到正确列表的脚本:
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");
}
}
}
任何有关如何解决此问题的帮助都将不胜感激!
谢谢。
最佳答案
我能想到几个选项。
- 您可以使用 4 个(或更多,也用于上下范围)点来测量角度,而不是我之前建议的中心点。
你的代码,对于右舷,会更像(我想,我倾向于航海,所以我可能对标签大声笑是错误的):
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;
}
- 您可以尝试改编来自 this "ConeCast" 的内容有人做的扩展方法。它仍然存在来自中心点的问题,但您可以调整它以开始转换,例如,在船的更左侧并检查目标是否在船的右侧(将目标转换为全局定位到船舶的局部引用系并检查 x/y 是否 >0/<0)。不过,这只是将一种手动计算换成另一种。
- 从rustyBucketBay's answer窃取一点,您可以使用较大的 SphereCast 圆柱体,并使用一些三角函数根据此处所示角度的余弦值排除距离船舶小于一定距离的船舶:
但同样,这只是用一种计算换取另一种计算。
- 您可以创建一个锥形圆柱体模型,不渲染它但给它一个 MeshCollider,然后当对象进入对象时(
OnColliderEnter
,我想?)您可以将它们添加到那个方向的当他们退出时列出并删除(OnColliderExit
也许吧?)。不过,您可能需要对它何时完全位于锥形圆柱体内进行更多检查,因为我认为OnColliderExit
(或它的任何名称)在模型停止与实际网格碰撞时被触发,无论无论是在对象内部还是外部。
我不太确定我是否喜欢其中任何一个,但令我惊讶的是没有可以采用近平面和远平面尺寸的本地“ConeCast”……但后来我想我我只是对 Unity 说“我不想做,你来做”哈哈。
关于C# Unity 3D - 有没有办法制作自定义光线转换形状?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73722227/