旋转到面对光标的箭头只需要在两个给定方向形成的角度内这样做
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.up
而 boundaryDirectionRight
可能是 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 angle从boundaryDirectionLeft
到目标方向,从boundaryDirectionLeft
到boundaryDirectionRight
同理,从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);
此时directionAngle
是target
从boundaryDirectionLeft
顺时针旋转多少度,boundaryAngle
是boundaryDirectionRight
是多少,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
:
来限制 directionAngle
和 currentAngle
之间的 angular 差异
float deltaAngle = Mathf.Clamp(directionAngle-currentAngle,
-maxRotationSpeed * Time.deltaTime,
maxRotationSpeed * Time.deltaTime);
现在我们可以顺时针旋转变换 deltaAngle
度(在世界 space 中):
transform.Rotate(0f,0f,deltaAngle,Space.World);
我有一个 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.up
而 boundaryDirectionRight
可能是 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 angle从boundaryDirectionLeft
到目标方向,从boundaryDirectionLeft
到boundaryDirectionRight
同理,从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);
此时directionAngle
是target
从boundaryDirectionLeft
顺时针旋转多少度,boundaryAngle
是boundaryDirectionRight
是多少,currentAngle
与我们当前面对的方向相同。
所以,现在,我们需要知道如何正确地 clamp 0 和 boundaryAngle
之间的角度。距离 boundaryAngle
太远的任何东西实际上更接近左边界,应该被夹在左边界。事实上,因为一切都在 0 到 360 之间,任何高于 boundaryAngle+(360f-boundaryAngle)/2f
的东西都更靠近左边。所以,我们只需将高于该值的值设置为与 boundaryDirectionLeft
:
if (directionAngle > boundaryAngle + (360f - boundaryAngle)/2f)
{
directionAngle = 0f;
}
所以,现在我们可以用 boundaryAngle
的高位夹紧 directionAngle
(它已经在 0f
处夹紧了底部,所以我们可以在这里使用 Mathf.Min
):
directionAngle = Mathf.Min(directionAngle, boundaryAngle);
现在我们可以使用 maxRotationSpeed
:
directionAngle
和 currentAngle
之间的 angular 差异
float deltaAngle = Mathf.Clamp(directionAngle-currentAngle,
-maxRotationSpeed * Time.deltaTime,
maxRotationSpeed * Time.deltaTime);
现在我们可以顺时针旋转变换 deltaAngle
度(在世界 space 中):
transform.Rotate(0f,0f,deltaAngle,Space.World);