我需要数学方面的帮助来检测旋转精灵上的 "side" 碰撞
I need help on the math for detecting the "side" of collision on a rotating sprite
所以我正在制作一个 2D space shmup 以海军方式处理战斗。所以你射击了船的舷侧,你的盾牌和船体分为 4 个部分:前舷、右舷、左舷和后部。我不是最擅长数学的,但我设法找到了一个脚本来检测我的多边形对撞机被碰撞或射弹击中的一侧。这一切都很好。
问题是我的精灵旋转以在 2D 中转向 space。因此,当我与某物发生碰撞时,例如与我的船头发生碰撞时,如果我的船头朝上,则可以正确检测到碰撞。但是如果船旋转并且机头现在在左侧并且我与机头上的东西发生碰撞,则脚本会将机头碰撞检测为左舷碰撞。有人可以帮我更正数学以解释我的船的旋转吗?
Collision2DExtension.cs
using UnityEngine;
namespace PixelsoftGames
{
public static class Collision2DExtensions
{
public static Collision2DSideType GetContactSide(Vector2 max, Vector2 center, Vector2 contact)
{
Collision2DSideType side = Collision2DSideType.None;
float diagonalAngle = Mathf.Atan2(max.y - center.y, max.x - center.x) * 180 / Mathf.PI;
float contactAngle = Mathf.Atan2(contact.y - center.y, contact.x - center.x) * 180 / Mathf.PI;
if (contactAngle < 0)
{
contactAngle = 360 + contactAngle;
}
if (diagonalAngle < 0)
{
diagonalAngle = 360 + diagonalAngle;
}
if (
((contactAngle >= 360 - diagonalAngle) && (contactAngle <= 360)) ||
((contactAngle <= diagonalAngle) && (contactAngle >= 0))
)
{
side = Collision2DSideType.Starboard;
}
else if (
((contactAngle >= 180 - diagonalAngle) && (contactAngle <= 180)) ||
((contactAngle >= 180) && (contactAngle <= 180 + diagonalAngle))
)
{
side = Collision2DSideType.Port;
}
else if (
((contactAngle >= diagonalAngle) && (contactAngle <= 90)) ||
((contactAngle >= 90) && (contactAngle <= 180 - diagonalAngle))
)
{
side = Collision2DSideType.Forward;
}
else if (
((contactAngle >= 180 + diagonalAngle) && (contactAngle <= 270)) ||
((contactAngle >= 270) && (contactAngle <= 360 - diagonalAngle))
)
{
side = Collision2DSideType.Rear;
}
return side.Opposite();
}
static bool ranOnce = false;
public static Collision2DSideType GetContactSide(this Collision2D collision)
{
Vector2 max = collision.collider.bounds.max;
Vector2 center = collision.collider.bounds.center;
Vector2 contact = collision.GetContact(0).point;
if (!ranOnce)
{
ranOnce = true;
Debug.Log("Max: " + max);
Debug.Log("Center: " + center);
Debug.Log("Contact: " + contact);
}
return GetContactSide(max, center, contact);
}
}
}
Collision2DSideTypeExtensions.cs
namespace PixelsoftGames
{
public static class Collision2DSideTypeExtensions
{
public static Collision2DSideType Opposite(this Collision2DSideType sideType)
{
Collision2DSideType opposite;
if (sideType == Collision2DSideType.Port)
{
opposite = Collision2DSideType.Starboard;
}
else if (sideType == Collision2DSideType.Starboard)
{
opposite = Collision2DSideType.Port;
}
else if (sideType == Collision2DSideType.Forward)
{
opposite = Collision2DSideType.Rear;
}
else if (sideType == Collision2DSideType.Rear)
{
opposite = Collision2DSideType.Forward;
}
else
{
opposite = Collision2DSideType.None;
}
return opposite;
}
}
}
Collision2DSideType
public enum Collision2DSideType { None, Port, Starboard, Forward, Rear }
在 GetContactSide 方法中,您永远无法获得精灵的旋转,就像您的精灵角度始终为 0
一个解决方案是将精灵的角度作为参数添加到方法中,并将该角度添加到条件中以确定它是精灵的哪一侧
它看起来像这样:
public static class Collision2DExtensions
{
public static Collision2DSideType GetContactSide(Vector2 max, Vector2 center, Vector2 contact, float angle)
{
...
if (
((contactAngle >= (360 - diagonalAngle) + angle) && (contactAngle <= 360 + angle)) ||
((contactAngle <= diagonalAngle + angle) && (contactAngle >= 0 + angle))
)
...
`
我认为你应该针对每个条件都这样做
所以我正在制作一个 2D space shmup 以海军方式处理战斗。所以你射击了船的舷侧,你的盾牌和船体分为 4 个部分:前舷、右舷、左舷和后部。我不是最擅长数学的,但我设法找到了一个脚本来检测我的多边形对撞机被碰撞或射弹击中的一侧。这一切都很好。
问题是我的精灵旋转以在 2D 中转向 space。因此,当我与某物发生碰撞时,例如与我的船头发生碰撞时,如果我的船头朝上,则可以正确检测到碰撞。但是如果船旋转并且机头现在在左侧并且我与机头上的东西发生碰撞,则脚本会将机头碰撞检测为左舷碰撞。有人可以帮我更正数学以解释我的船的旋转吗?
Collision2DExtension.cs
using UnityEngine;
namespace PixelsoftGames
{
public static class Collision2DExtensions
{
public static Collision2DSideType GetContactSide(Vector2 max, Vector2 center, Vector2 contact)
{
Collision2DSideType side = Collision2DSideType.None;
float diagonalAngle = Mathf.Atan2(max.y - center.y, max.x - center.x) * 180 / Mathf.PI;
float contactAngle = Mathf.Atan2(contact.y - center.y, contact.x - center.x) * 180 / Mathf.PI;
if (contactAngle < 0)
{
contactAngle = 360 + contactAngle;
}
if (diagonalAngle < 0)
{
diagonalAngle = 360 + diagonalAngle;
}
if (
((contactAngle >= 360 - diagonalAngle) && (contactAngle <= 360)) ||
((contactAngle <= diagonalAngle) && (contactAngle >= 0))
)
{
side = Collision2DSideType.Starboard;
}
else if (
((contactAngle >= 180 - diagonalAngle) && (contactAngle <= 180)) ||
((contactAngle >= 180) && (contactAngle <= 180 + diagonalAngle))
)
{
side = Collision2DSideType.Port;
}
else if (
((contactAngle >= diagonalAngle) && (contactAngle <= 90)) ||
((contactAngle >= 90) && (contactAngle <= 180 - diagonalAngle))
)
{
side = Collision2DSideType.Forward;
}
else if (
((contactAngle >= 180 + diagonalAngle) && (contactAngle <= 270)) ||
((contactAngle >= 270) && (contactAngle <= 360 - diagonalAngle))
)
{
side = Collision2DSideType.Rear;
}
return side.Opposite();
}
static bool ranOnce = false;
public static Collision2DSideType GetContactSide(this Collision2D collision)
{
Vector2 max = collision.collider.bounds.max;
Vector2 center = collision.collider.bounds.center;
Vector2 contact = collision.GetContact(0).point;
if (!ranOnce)
{
ranOnce = true;
Debug.Log("Max: " + max);
Debug.Log("Center: " + center);
Debug.Log("Contact: " + contact);
}
return GetContactSide(max, center, contact);
}
}
}
Collision2DSideTypeExtensions.cs
namespace PixelsoftGames
{
public static class Collision2DSideTypeExtensions
{
public static Collision2DSideType Opposite(this Collision2DSideType sideType)
{
Collision2DSideType opposite;
if (sideType == Collision2DSideType.Port)
{
opposite = Collision2DSideType.Starboard;
}
else if (sideType == Collision2DSideType.Starboard)
{
opposite = Collision2DSideType.Port;
}
else if (sideType == Collision2DSideType.Forward)
{
opposite = Collision2DSideType.Rear;
}
else if (sideType == Collision2DSideType.Rear)
{
opposite = Collision2DSideType.Forward;
}
else
{
opposite = Collision2DSideType.None;
}
return opposite;
}
}
}
Collision2DSideType
public enum Collision2DSideType { None, Port, Starboard, Forward, Rear }
在 GetContactSide 方法中,您永远无法获得精灵的旋转,就像您的精灵角度始终为 0
一个解决方案是将精灵的角度作为参数添加到方法中,并将该角度添加到条件中以确定它是精灵的哪一侧
它看起来像这样:
public static class Collision2DExtensions
{
public static Collision2DSideType GetContactSide(Vector2 max, Vector2 center, Vector2 contact, float angle)
{
...
if (
((contactAngle >= (360 - diagonalAngle) + angle) && (contactAngle <= 360 + angle)) ||
((contactAngle <= diagonalAngle + angle) && (contactAngle >= 0 + angle))
)
... `
我认为你应该针对每个条件都这样做