旋转到面对光标的箭头只需要在两个给定方向形成的角度内这样做

Arrow rotating to face cursor needs to only do so while inside an angle made by two given directions

我有一个 2d 箭头旋转以始终面向目标(在这种情况下目标是光标),枢轴是我的玩家角色。我需要限制这个箭头只跟随目标,如果它在玩家的角度内,一个例子是 90 度,所以只有当光标在屏幕的右上角时它才会跟随。

我曾使用矢量方向和方法,例如 Vector2D.angle,但它们似乎都有一些我无法解决的限制,Vector2D.angles 限制是它用于的第 3 个位置计算角度是世界中心 (0, 0),我的播放器是移动的,所以不起作用。 所以我想我问的是是否有一种方法可以存储角度,然后检查其中是否有东西。

这是我用来旋转箭头的代码,脚本还有更多内容,但我删除了不必要的部分:

    public float speed;
    public Transform target;

 void Update()
    {
        Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 direction = target.position - transform.position;
            target.position = mousePosition;
        float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
Quaternion rotation = Quaternion.AngleAxis(angle, Vector3.forward);
        transform.rotation = Quaternion.Slerp(transform.rotation, rotation, speed * Time.deltaTime);

抱歉,如果格式不正确,这是我第一次在这里发帖,如果你能帮助我,我将感谢你一百万次,我已经坚持了好几天了。

被要求澄清问题,所以这是一次尝试:

这张图片显示了我的意思的一个例子,箭头围绕圆心旋转,(它在旋转所以它总是指向我的光标)。我需要的是一种限制它的方法,以便它仅在特定角度(图中的红线)内指向光标,这就是我遇到的问题。我找不到存储此阈值的方法,我似乎也找不到将光标方向与其进行比较的方法。

我认为如果可以为Vector2D.angle选择自定义中心是可能的,但似乎并非如此。

我希望这能澄清我的问题,我可能只是很愚蠢并且忽略了一些明显的事情,但我真的找不到使这成为可能的方法。 再次感谢。

重要fields/inputs

首先,我们需要知道世界的边界方向space:

public Vector2 boundaryDirectionLeft;
public Vector2 boundaryDirectionRight;

重要的一点是从boundaryDirectionLeft顺时针到boundaryDirectionRight的角度是箭头应该留在里面的区域。对于您的图片,boundaryDirectionLeft 可能是 Vector2.upboundaryDirectionRight 可能是 new Vector2(1f,-1f).

在应用任何旋转之前,我们还需要知道箭头朝向哪个局部方向。例如,如果箭头始终指向局部红色箭头轴(局部右方向),则为 Vector2.right:

public Vector2 localArrowDirection;

最后,我们需要一个最高的旋转速度,这样我们就不会在旋转时使箭头扭曲。一个好的开始值可能是 360f,每秒 360 度。尝试使用不同的值进行试验以找到您喜欢的值:

public float maxRotationSpeed;

更新程序

Update中,确定目标的方向:

Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 direction = mousePosition - transform.position;

然后,我们需要知道箭头当前指向的位置。我们可以使用 Transform.TransformVector 找到本地 localArrowDirection 在世界 space:

中指向的位置
Vector2 currentDirection = transform.TransformVector(localArrowDirection);

然后,确定signed angleboundaryDirectionLeft到目标方向,从boundaryDirectionLeftboundaryDirectionRight同理,从boundaryDirectionLeft到同理当前朝向:

float directionAngle = Vector2.SignedAngle(boundaryDirectionLeft, direction);
float boundaryAngle = Vector2.SignedAngle(boundaryDirectionLeft, boundaryDirectionRight);
float currentAngle = Vector2.SignedAngle(boundaryDirectionLeft, currentDirection);

这些值的范围是 [-180,180],但我们希望它们在 [0,360) 范围内表示,以便稍后进行数学计算,因此我们可以添加 360f 并在其上使用 Mathf.Repeat总和:

directionAngle = Mathf.Repeat(directionAngle+360f, 360f);
boundaryAngle = Mathf.Repeat(boundaryAngle+360f, 360f);
currentAngle = Mathf.Repeat(currentAngle+360f, 360f);

此时directionAngletargetboundaryDirectionLeft顺时针旋转多少度,boundaryAngleboundaryDirectionRight是多少,currentAngle 与我们当前面对的方向相同。

所以,现在,我们需要知道如何正确地 clamp 0 和 boundaryAngle 之间的角度。距离 boundaryAngle 太远的任何东西实际上更接近左边界,应该被夹在左边界。事实上,因为一切都在 0 到 360 之间,任何高于 boundaryAngle+(360f-boundaryAngle)/2f 的东西都更靠近左边。所以,我们只需将高于该值的值设置为与 boundaryDirectionLeft:

成 0 度角
if (directionAngle > boundaryAngle + (360f - boundaryAngle)/2f)
{
    directionAngle = 0f;
}

所以,现在我们可以用 boundaryAngle 的高位夹紧 directionAngle(它已经在 0f 处夹紧了底部,所以我们可以在这里使用 Mathf.Min):

directionAngle = Mathf.Min(directionAngle, boundaryAngle);

现在我们可以使用 maxRotationSpeed:

来限制 directionAnglecurrentAngle 之间的 angular 差异
float deltaAngle = Mathf.Clamp(directionAngle-currentAngle,
                               -maxRotationSpeed * Time.deltaTime, 
                               maxRotationSpeed * Time.deltaTime);

现在我们可以顺时针旋转变换 deltaAngle 度(在世界 space 中):

transform.Rotate(0f,0f,deltaAngle,Space.World);