Unity - 2D 瞄准鼠标,同时限制 min/max 旋转并考虑父旋转
Unity - 2D Aim at Mouse, while restricting min/max rotation and factoring in parent rotation
所以,我有一艘附有“挂载点”的船,可以在上面放置武器。放置后,它们会瞄准鼠标位置并具有受限的旋转范围:
See here
旋转范围基于 minAngle 和 maxAngle,并由父硬点插槽的 eulerAngles.z 和角度修改器 plus/minus 计算(在本例中为 20)。我不得不做一些奇怪的旋转巫术(请参阅代码片段中的 OneEightyToThreeSixty() )以使鼠标视角匹配与 minAngle/maxAngle.
相同的格式
angle was coming in as -180 -> 180 degrees instead 0 -> 360 like the hardpoint's rotation. Wrote a method to convert it to 360 during runtime.
我已经数不清重写这个脚本了,但最终 I'm hit with this issue.
如您所见,对于 360 度旋转的 270 度,瞄准和限制工作完全正常。但是在旋转的右上角四分之一处,一切都变得一团糟。
我尝试了很多不同的实现,但它们似乎都有这个一致的问题。我不知道我错过了什么。这是代码:
public class HardpointSlot : MonoBehaviour
{
public HardpointController ship;
public GameObject hardpoint;
public float minAngle;
public float maxAngle;
public float angle;
public float offsetAngle;
public bool switched;
void Update()
{
AimAtMouse();
}
public void AimAtMouse()
{
Vector3 dir = Input.mousePosition - Camera.main.WorldToScreenPoint(transform.position);
angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
minAngle = (transform.eulerAngles.z - 20) + 90f;
maxAngle = (transform.eulerAngles.z + 20) + 90f;
angle = OneEightyToThreeSixty(angle);
if (angle < minAngle)
{
angle = minAngle;
}
else if (angle > maxAngle)
{
angle = maxAngle;
}
hardpoint.transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
}
public float OneEightyToThreeSixty(float angle)
{
float newAngle = 0f;
if (angle >= 0 && angle <= 180)
{
return angle;
} else
{
return newAngle = 360 + angle;
}
}
}
快速回顾一下:
- 硬点需要注视鼠标,但前提是它在其目标范围范围内,这是由 baseAim 偏移量 (20) 和父硬点插槽的旋转计算得出的。
- 适用于 270 度旋转,但不适用于最后 90 度。
有什么想法吗?我是否遗漏了一些非常明显的东西?
我会采用另一种方法,利用 Vector3.SignedAngle
to get the angle from the neutral direction to the mouse direction. Then, use Mathf.Clamp
to clamp it between the boundaries and then Quaternion.AngleAxis
to create the resulting direction. Finally, use Quaternion.LookRotation
将旋转分配给硬点的变换:
public class HardpointSlot : MonoBehaviour
{
[SerializeField] HardpointController ship;
[SerializeField] GameObject hardpoint;
[SerializeField] float minAngle;
[SerializeField] float maxAngle;
[SerializeField] float angle;
void Update()
{
AimAtMouse();
}
public void AimAtMouse()
{
Vector3 dir = Camera.main.ScreenToWorldPoint(Input.mousePosition)
- transform.position;
// flatten z axis
dir.z = 0;
Vector3 neutralDir = transform.up;
float angle = Vector3.SignedAngle(neutralDir, dir, Vector3.forward);
minAngle = -20f;
maxAngle = 20f;
angle = Mathf.Clamp(angle, minAngle, maxAngle);
// rotate neutral dir by the clamped angle
dir = Quaternion.AngleAxis(angle, Vector3.forward) * neutralDir;
// set the rotation so that local up points in dir direction
// and local forward in global forward
hardpoint.transform.rotation = Quaternion.LookRotation(Vector3.forward, dir);
}
}
所以,我有一艘附有“挂载点”的船,可以在上面放置武器。放置后,它们会瞄准鼠标位置并具有受限的旋转范围: See here
旋转范围基于 minAngle 和 maxAngle,并由父硬点插槽的 eulerAngles.z 和角度修改器 plus/minus 计算(在本例中为 20)。我不得不做一些奇怪的旋转巫术(请参阅代码片段中的 OneEightyToThreeSixty() )以使鼠标视角匹配与 minAngle/maxAngle.
相同的格式angle was coming in as -180 -> 180 degrees instead 0 -> 360 like the hardpoint's rotation. Wrote a method to convert it to 360 during runtime.
我已经数不清重写这个脚本了,但最终 I'm hit with this issue.
如您所见,对于 360 度旋转的 270 度,瞄准和限制工作完全正常。但是在旋转的右上角四分之一处,一切都变得一团糟。
我尝试了很多不同的实现,但它们似乎都有这个一致的问题。我不知道我错过了什么。这是代码:
public class HardpointSlot : MonoBehaviour
{
public HardpointController ship;
public GameObject hardpoint;
public float minAngle;
public float maxAngle;
public float angle;
public float offsetAngle;
public bool switched;
void Update()
{
AimAtMouse();
}
public void AimAtMouse()
{
Vector3 dir = Input.mousePosition - Camera.main.WorldToScreenPoint(transform.position);
angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
minAngle = (transform.eulerAngles.z - 20) + 90f;
maxAngle = (transform.eulerAngles.z + 20) + 90f;
angle = OneEightyToThreeSixty(angle);
if (angle < minAngle)
{
angle = minAngle;
}
else if (angle > maxAngle)
{
angle = maxAngle;
}
hardpoint.transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
}
public float OneEightyToThreeSixty(float angle)
{
float newAngle = 0f;
if (angle >= 0 && angle <= 180)
{
return angle;
} else
{
return newAngle = 360 + angle;
}
}
}
快速回顾一下:
- 硬点需要注视鼠标,但前提是它在其目标范围范围内,这是由 baseAim 偏移量 (20) 和父硬点插槽的旋转计算得出的。
- 适用于 270 度旋转,但不适用于最后 90 度。
有什么想法吗?我是否遗漏了一些非常明显的东西?
我会采用另一种方法,利用 Vector3.SignedAngle
to get the angle from the neutral direction to the mouse direction. Then, use Mathf.Clamp
to clamp it between the boundaries and then Quaternion.AngleAxis
to create the resulting direction. Finally, use Quaternion.LookRotation
将旋转分配给硬点的变换:
public class HardpointSlot : MonoBehaviour
{
[SerializeField] HardpointController ship;
[SerializeField] GameObject hardpoint;
[SerializeField] float minAngle;
[SerializeField] float maxAngle;
[SerializeField] float angle;
void Update()
{
AimAtMouse();
}
public void AimAtMouse()
{
Vector3 dir = Camera.main.ScreenToWorldPoint(Input.mousePosition)
- transform.position;
// flatten z axis
dir.z = 0;
Vector3 neutralDir = transform.up;
float angle = Vector3.SignedAngle(neutralDir, dir, Vector3.forward);
minAngle = -20f;
maxAngle = 20f;
angle = Mathf.Clamp(angle, minAngle, maxAngle);
// rotate neutral dir by the clamped angle
dir = Quaternion.AngleAxis(angle, Vector3.forward) * neutralDir;
// set the rotation so that local up points in dir direction
// and local forward in global forward
hardpoint.transform.rotation = Quaternion.LookRotation(Vector3.forward, dir);
}
}