求两向量在0~360度之间的角度值及实际应用

实际应用

QQ20180629-235018-HD

问题

先从实际问题出发,这样可以更好的理解问题.

项目需要控制角色在地图中随意移动,角色素材是8方向的. 那问题就是

如何根据点击的鼠标位置来决定使用哪个方向的图集?

分解问题

  • 首先8方向图集 360/8 = 45 也就是每45度一个图集. 然要注意起始角度并不是0度.

    不是0~45度 是图集A, 而应该是 -22.5~22.5 是图集A ,22.5 ~ 67.5(22.5+45) 是图集B 以此类推

  • 根据当前Touch(PosB),和上次Touch(PosA) 做一个向量AB , 只要求的该向量AB和Up向量(Vector2.up)之间的夹角即可

方法

方法一:

1
2
3
4
5
6
7
var angle = Vector2.Angle(toVector2,Vector2.up);
var cross = Vector3.Cross(toVector2,Vector2.up);

if (cross.z < 0)
{
angle = 360 - angle;
}

方法二:

1
2
3
4
5
var angle = Vector2.SignedAngle(toVector2, Vector2.up);
if (angle < 0)
{
angle = 360 + angle;
}

方法一

方法一是之前一直使用的,方法二是后来发现API中有的.也许是新加入的?(2017.1).

先从方法一说起.

首先是

1
var angle = Vector2.Angle(Vector2.up, toVector2);

取得角度这个方法,这个是无符号的.官网的API文档说的很清楚了

The angle returned is the unsigned acute angle between the two vectors. This means the smaller of the two possible angles between the two vectors is used. The result is never greater than 180 degrees.

也就是能取到的是最小夹角,比如返回一个30度. 你无法知道是30度还是330度(360-30).

这个就需要使用到 叉乘来判断了.

向量叉乘公式

首先 叉乘 只能用于3D向量,但是确实又允许Vector3.Cross(Vector2.up, toVector2)这么写.

这个就可以把 Vector2.uptoVector2看成x-y平面的向量,其z=0.

那么他的叉积就是和z轴共线的向量

叉乘公式

因为,Vector2.uptoVector2的z均为零,所以

两向量叉乘得到向量为(0,0,z)

同时又根据上面的公式 c的模=a的模 x b的模 x sin@.

c的模 也就是 z

然后再根据正弦函数

Sin取值范围

可以知道. 当sin@<0 时候 也就是此时得到角度是大于180的.

比如上面angle给出来的是30度, 那么就需要用 360-30 得到 330度.

方法二

WX20180630-011249

直接进到其API的实现就可以看到了

  • 红框部分就是 var angle = Vector2.Angle(Vector2.up, toVector2);
  • 篮框部分就是 z

叉积向量

x = y1z2 - z1y2
y = z1x2 - x1z2
z = x1y2 - y1x2

因为z1和z2都是0,所以叉积就是向量(0,0,x1y2 - y1x2)

换句话说就是 方法二 其实就是封装后的 方法一

坚持原创技术分享,您的支持将鼓励我继续创作!