旋转到面对光标的箭头只需要在两个给定方向所成的角度内旋转即可 [英] Arrow rotating to face cursor needs to only do so while inside an angle made by two given directions

查看:68
本文介绍了旋转到面对光标的箭头只需要在两个给定方向所成的角度内旋转即可的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个旋转的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;

重要的一点是,从boundaryDirectionLeftboundaryDirectionRight的顺时针方向形成的角度是箭头应保留在内部的区域.对于您的图片,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到目标的符号角方向,从boundaryDirectionLeftboundaryDirectionRight,并且从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);

在这一点上,directionAngletargetboundaryDirectionLeft到顺时针的度数,而boundaryAngleboundaryDirectionRight的度数,并且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限制directionAnglecurrentAngle之间的角度差:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆