再论向量在游戏中的应用(1) 使用点积和叉积求夹角问题

废话

这两天因为一个tight sprite in image问题 有机会又系统学习了一遍向量. 加深了不少理解. 这里总结一下 这两天得到的收获.
因为相关的数学东西比较多. 所以拆分出几篇文章来分别聊聊.

温故知新

在之前遇到过一个问题就是要根据玩家点击鼠标的位置,相应的对控制角色进行转向. 其中也提到 先通过 Vector2.Angle 取得一个角度后(比如 50度),再通过Vector3.Cross 求出 两个向量之间的叉积 判断出 到底是 旋转 50度 还是 310度

向量 点积

那 Vector2.Angle 如何判断的 两个向量之间的夹角?

摘自Wiki

Unity中的相关代码

1
2
3
4
5
6
7
8
9
10
11
12
/// <summary>
/// <para>Returns the unsigned angle in degrees between from and to.</para>
/// </summary>
/// <param name="from">The vector from which the angular difference is measured.</param>
/// <param name="to">The vector to which the angular difference is measured.</param>
public static float Angle(Vector2 from, Vector2 to)
{
float num = Mathf.Sqrt(from.sqrMagnitude * to.sqrMagnitude);
if ((double) num < 1.00000000362749E-15)
return 0.0f;
return Mathf.Acos(Mathf.Clamp(Vector2.Dot(from, to) / num, -1f, 1f)) * 57.29578f;
}

Unity Answer中有对Vector3.Angle的详细解释

其中涉及到几个点

  • 为什么还需要Mathf.Clamp一下结果
  • 57.29578f (弧度转角度的 Magic Number) => 180度 = PI

向量 叉积

这个之前已经有理解,但是理解的不是很深刻.

向量的叉积 符合

右手定则 : 是 食指 指向 初始向量(from)的方向 向 目标向量(to) 握拳. 则此时 拇指的方向 也就是 最终 两个向量 叉积的方向 (向屏幕里,或者向屏幕外)

之前的写法

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
6
7
var angle = Vector2.Angle(Vector2.up,toVector2);
var cross = Vector3.Cross(Vector2.up,toVector2);

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

这样就是 食指 指向Vector2.up(2D的Y轴)方向 然后向 toVector2方向 握拳, 如果此时此时 拇指 朝向屏幕外呢 就应该用360度 减去 angle值 (angle是0~180度的值,比如此时angle是30,那么最终结果应该是330)

向量叉乘的基础理解

叉积的理解在2D 向量中 应该是 至关重要的. 只要叉积理解透了. 后续的几个问题 都很容易理解.

向量叉乘 反交换律

a x b = - b x a

A 叉乘 B 等于 负的 B 叉乘 A

这个用 右侧定则应该很容理解.

比如还是上面的例子,用右手定则 从toVector2 反向 朝着Vector2.up握拳,就正好差了一个负号. 这也是为什么 我之前结果是正确的,但是写法有些不妥的原因.

向量叉乘 零向量

a x a = 0

A 叉乘 A 等于 0

就是自己叉乘自己是一个0向量.

向量叉乘 判断两侧

a x b 相当于拿刀子沿着 a 方向切一刀 如果 axb 小于0 则 b在 a的 右侧, 大于0 则 b在 a的 左侧

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