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

14t*_*nch 6 c# angle unity-game-engine

I have a 2d arrow rotating to always face the a target (the target in this case is the cursor), the pivot is my player character. I need to restrict this arrow to only follow the target if it is inside an angle of the player, an example would be 90 degrees, so it would only follow if the cursor is in the top right part of the screen.

I have worked with vector directions and methods such as Vector2D.angle, but they all seem to have some restriction i can't workaround, Vector2D.angles restriction is that the 3rd position it uses to calculate the angle is the world center(0, 0), my player is mobile so that doesn't work. So i think what im asking is if theres a way to store an angle, and then check if something is within that.

Here is the code i use for rotating my arrow, theres more to the script but i removed the unnecesary parts:

    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);

Run Code Online (Sandbox Code Playgroud)

Sorry if this is formatted poorly, its my first time posting here, thank you a million times if you are able to help me, i have been stuck on this for days.

Was asked to clarify question so here is an attempt:

例

This picture shows an example of what i mean, the arrow is rotating around the center of the circle, (it is rotating so it always points towards my cursor). What i need is a way to restrict it so it only points towards the cursor if it is within a specific angle (red lines in picture), that's what im having trouble with. I can't find a way to store this threshold and i can't seem to find a way to compare the cursors direction with it.

I think it would be possible if it was possible to choose a custom center for Vector2D.angle, but that doesn't seem to be the case.

I hope this clarifies what my question, i may just very well be stupid and overlooking something obvious but i really can't find a way to make this possible. thanks again.

Ruz*_*ihm 1

重要字段/输入

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

public Vector2 boundaryDirectionLeft;
public Vector2 boundaryDirectionRight;
Run Code Online (Sandbox Code Playgroud)

boundaryDirectionLeft重要的是,从到顺时针形成的角度boundaryDirectionRight是箭头应保留在内部的区域。就您的图像而言,boundaryDirectionLeft可能是Vector2.up并且boundaryDirectionRight可能是类似的东西new Vector2(1f,-1f)

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

public Vector2 localArrowDirection;
Run Code Online (Sandbox Code Playgroud)

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

public float maxRotationSpeed;
Run Code Online (Sandbox Code Playgroud)

更新程序

在 中Update,确定到目标​​的方向:

Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 direction = mousePosition - transform.position;
Run Code Online (Sandbox Code Playgroud)

然后,我们需要知道箭头当前指向哪里。我们可以用它Transform.TransformVector来查找本地localArrowDirection在世界空间中指向的位置:

Vector2 currentDirection = transform.TransformVector(localArrowDirection);
Run Code Online (Sandbox Code Playgroud)

然后,确定from到目标方向的带符号角度boundaryDirectionLeft,同样 fromboundaryDirectionLeftboundaryDirectionRight,以及同样 fromboundaryDirectionLeft到当前面向方向:

float directionAngle = Vector2.SignedAngle(boundaryDirectionLeft, direction);
float boundaryAngle = Vector2.SignedAngle(boundaryDirectionLeft, boundaryDirectionRight);
float currentAngle = Vector2.SignedAngle(boundaryDirectionLeft, currentDirection);
Run Code Online (Sandbox Code Playgroud)

这些值的范围为 [-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);
Run Code Online (Sandbox Code Playgroud)

此时,距离该点directionAngle顺时针旋转多少度, 和是多少度, 和我们当前面向的方向相同。boundaryDirectionLefttargetboundaryAngleboundaryDirectionRightcurrentAngle

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

if (directionAngle > boundaryAngle + (360f - boundaryAngle)/2f)
{
    directionAngle = 0f;
}
Run Code Online (Sandbox Code Playgroud)

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

directionAngle = Mathf.Min(directionAngle, boundaryAngle);
Run Code Online (Sandbox Code Playgroud)

现在我们可以使用我们的 来限制directionAngle和之间的角度差异:currentAnglemaxRotationSpeed

float deltaAngle = Mathf.Clamp(directionAngle-currentAngle,
                               -maxRotationSpeed * Time.deltaTime, 
                               maxRotationSpeed * Time.deltaTime);
Run Code Online (Sandbox Code Playgroud)

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

transform.Rotate(0f,0f,deltaAngle,Space.World);
Run Code Online (Sandbox Code Playgroud)

  • 你是英雄!这完全有道理,你为我节省了更多研究时间,非常感谢! (3认同)
  • @14thcowboyoframranch 我意识到我没有考虑到某些情况,所以我在一些地方大幅改变了答案。希望这可以帮助! (2认同)
  • 再次感谢,编辑后的内容几乎解决了我之前遇到的所有问题,除了光标退出boundaryAngle时的行为,它总是旋转到右边界,而不是仅仅停留在光标离开的边界。如果您看到此评论并且有时间,我绝对会很高兴您能给我一种改变这种行为的方法。我知道我现在发表评论有点晚了,无论如何,谢谢你真的救了我。 (2认同)
  • @14thcowboyoframranch 哎呀!我发现了我犯的错误。我错误地输入了 `if (directionAngle > DirectionAngle + (360f - borderAngle)/2f)` 而不是正确的条件 `if (directionAngle > borderAngle + (360f - borderAngle)/2f)`。这意味着它在应该有的情况下却从未评估为“true”。使用现在正确的条件再试一次! (2认同)
  • 伙计,你真是一个神,这比完美更有效! (2认同)