旋转到面对光标的箭头只需要在两个给定方向所成的角度内旋转即可 [英] Arrow rotating to face cursor needs to only do so while inside an angle made by two given directions
问题描述
我有一个旋转的2d箭头,始终指向目标(在这种情况下,目标是光标),枢轴是我的玩家角色.我需要限制此箭头仅在目标位于播放器角度范围内时跟随目标,例如90度,因此仅当光标在屏幕的右上方时才跟随目标.
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.
我曾经使用过矢量方向和方法,例如Vector2D.angle,但是它们似乎都存在一些限制,我无法解决,Vector2D.angles限制是它用于计算角度的第三个位置是世界中心(0,0),我的播放器是移动设备,因此无法正常工作. 因此,我想我要问的是是否有存储角度的方法,然后检查其中是否有东西.
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);
对不起,如果格式不好,这是我第一次在这里发布,如果您能帮助我,谢谢您一百万次,我已经坚持了好几天.
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.
我认为有可能为Vector2D.angle选择一个自定义中心,但是事实并非如此.
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.
推荐答案
重要字段/输入
首先,我们需要了解世界空间中的边界方向:
Important fields/inputs
First, we need to know the boundary directions in world space:
public Vector2 boundaryDirectionLeft;
public Vector2 boundaryDirectionRight;
重要的一点是,从boundaryDirectionLeft
到boundaryDirectionRight
的顺时针方向形成的角度是箭头应保留在内部的区域.对于您的图片,boundaryDirectionLeft
可能是Vector2.up
,而boundaryDirectionRight
可能是new Vector2(1f,-1f)
.
The important piece is that the angle made clockwise from boundaryDirectionLeft
to boundaryDirectionRight
is the region the arrow shall remain inside. In the case of your image, boundaryDirectionLeft
could be Vector2.up
and boundaryDirectionRight
could be something like new Vector2(1f,-1f)
.
我们还需要知道在应用任何旋转之前箭头所面向的局部方向.例如,如果箭头始终指向局部红色箭头轴(局部向右方向),则为Vector2.right
:
We also need to know which local direction the arrow is facing before any rotation is applied. E.g., if the arrow is always pointing with the local red arrow axis (the local right direction), this would be Vector2.right
:
public Vector2 localArrowDirection;
最后,我们需要最高的旋转速度,因此在旋转时,我们不会扭曲箭头.首先,一个很好的值可能是360f
,即每秒360度.尝试尝试不同的值以找到您喜欢的值:
And lastly, we need a top speed for our rotation, so we don't warp the arrow around when it's time to rotate. A good value to start with might be 360f
, 360 degrees per second. Try experimenting with different values to find one that you like:
public float maxRotationSpeed;
更新过程
在Update
中,确定指向目标的方向:
The update procedure
In Update
, determine the direction to the target:
Vector2 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 direction = mousePosition - transform.position;
然后,我们需要知道箭头当前指向的位置.我们可以使用 Transform.TransformVector
来查找本地localArrowDirection
指向的位置在世界空间中:
Then, we need to know where the arrow is currently pointing. We can use Transform.TransformVector
to find where the local localArrowDirection
is pointing in world space:
Vector2 currentDirection = transform.TransformVector(localArrowDirection);
然后,确定从boundaryDirectionLeft
到目标的符号角方向,从boundaryDirectionLeft
到boundaryDirectionRight
,并且从boundaryDirectionLeft
到当前朝向:
Then, determine the signed angle from boundaryDirectionLeft
to the target direction, the same from boundaryDirectionLeft
to boundaryDirectionRight
, and the same from boundaryDirectionLeft
to the current facing direction:
float directionAngle = Vector2.SignedAngle(boundaryDirectionLeft, direction);
float boundaryAngle = Vector2.SignedAngle(boundaryDirectionLeft, boundaryDirectionRight);
float currentAngle = Vector2.SignedAngle(boundaryDirectionLeft, currentDirection);
这些值的范围是[-180,180],但是我们希望它们在[0,360]范围内表示,以便以后简化数学运算,因此我们可以添加360f
并使用
These values range from [-180,180], but we want them expressed in the range [0,360) to make the math easier later, so we can add 360f
and use Mathf.Repeat
on that sum:
directionAngle = Mathf.Repeat(directionAngle+360f, 360f);
boundaryAngle = Mathf.Repeat(boundaryAngle+360f, 360f);
currentAngle = Mathf.Repeat(currentAngle+360f, 360f);
在这一点上,directionAngle
是target
从boundaryDirectionLeft
到顺时针的度数,而boundaryAngle
是boundaryDirectionRight
的度数,并且currentAngle
对于我们当前的方向是相同的面对.
At this point directionAngle
is how many clockwise degrees from boundaryDirectionLeft
that target
is, and boundaryAngle
is how many boundaryDirectionRight
is, and currentAngle
is the same for what direction we're currently facing.
因此,现在,我们需要知道如何正确 clamping 0至boundaryAngle
之间的角度. boundaryAngle
上方的任何位置实际上都更靠近左侧边界,应将其钳位到左侧边界.实际上,由于所有内容都在0到360之间,因此任何高于boundaryAngle+(360f-boundaryAngle)/2f
的内容都靠近左侧.因此,我们将高于此值的任何值设置为与boundaryDirectionLeft
:
So, now, we need to know how to properly clamp the angle between 0 and boundaryAngle
. Anything too far above boundaryAngle
is actually closer to the left boundary and should be clamped to the left boundary. In fact, since everything is between 0 and 360, anything higher than boundaryAngle+(360f-boundaryAngle)/2f
is closer to the left. So, we just set anything higher than that to be 0 degrees away from boundaryDirectionLeft
:
if (directionAngle > boundaryAngle + (360f - boundaryAngle)/2f)
{
directionAngle = 0f;
}
因此,现在我们可以将directionAngle
钳位到boundaryAngle
的高位(它已经被底部钳位在0f
,因此我们可以在此处使用Mathf.Min
):
So, now we can clamp directionAngle
with a high of boundaryAngle
(it is already bottom clamped at 0f
, so we can use Mathf.Min
here):
directionAngle = Mathf.Min(directionAngle, boundaryAngle);
现在,我们可以使用maxRotationSpeed
限制directionAngle
和currentAngle
之间的角度差:
Now we can limit the angular difference between directionAngle
and currentAngle
using our maxRotationSpeed
:
float deltaAngle = Mathf.Clamp(directionAngle-currentAngle,
-maxRotationSpeed * Time.deltaTime,
maxRotationSpeed * Time.deltaTime);
现在,我们可以在世界空间中顺时针旋转变换deltaAngle
度:
Now we can rotate the transform deltaAngle
degrees clockwise (in world space):
transform.Rotate(0f,0f,deltaAngle,Space.World);
这篇关于旋转到面对光标的箭头只需要在两个给定方向所成的角度内旋转即可的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!