之所以把这两个东西放在一篇笔记里面
是因为 position2d 和 vector2d 很多地方是相同的
因为 2D向量 和 2D点 的表示是可以互相转换的 —— 都是 (x, y)
只是点(position2d) 更偏重于表示,只有一些简单的运算
而 向量(vector2d) 除了表示之外,同时有比较多的计算规则
3D向量除了多一个维度之外, 运算方法和2D有所不同 而且更多一些运算
比如 向量叉乘对于 2D 向量是没有意义的,对于3D向量才有意义,可以用来求两向量的法向量
所以这个还是再单独开一篇笔记写吧!
( 看来没有人注意到我 3D 图形学已经忘得差不多的事实原因吧... (  ̄へ ̄ ) )
【position2d】
先来看比较简单的 position2d 模板
X 和 Y 的类型可以由使用者自行定义
这个聪明的办法, 比较容易让一套代码却使用不同精度的运算类型
于是可以直接 typedef position2d
typedef position2d
( 毕竟方脑壳的博主以前都是酱紫写的 class POINTF, class POINTI, 然后分别再写实现... )
三个构造函数
0. 无参构造函数, X 和 Y 初始化为 0
1. 传入 X, Y两个值, 分别对 X 和 Y 进行赋值
2. 传入另一个同类型的点 other , 使用 other 的 X 和 Y 分别对当前 X Y 赋值
position2d 中重载了一些常用的运算符
实现都很简单,和 2D 向量基本上是一样的,就不加赘述了
要注意一下的是返回值的问题
( 比如 博主一开始学 C 语言的时候就知道赋值运算符是有返回值的 )
( 但是第一次写重载的时候还是忘的死死地... )
"==" 和 "!=" 的返回值是 bool 型这个应该是忘不掉的 ( 毕竟忘了这个就不剩啥了 )
"+=" , "-=" 和 "=" 的返回值是自身的引用 即: return *this; ( 所以 C 里面可以这样写 : a = b = 0; )
"+" 和 "-" 返回值是一个新的 position2d ( 这样才可以实现 a = b + c )
另外,代码里面有一处错误 —— 加法运算符里将 "+" 写成了 "-", 大家注意一下就好了
position2d operator+(const position2d& other) const
{
return position2d(X+other.X, Y+other.Y); // REVISED - 原代码"return position2d(X-other.X, Y-other.Y);" 中, 加法错写为减法
}
向量里面很多运算是很基本的,和 position2d很相像
而且向量的知识在我大天朝只是高中的内容, 所以大多数的计算方法对于我们来说还是很简单的
( 不少老外读研究生的时候 两位数的乘法还会算错有木有? )
所以一些简单的部分就一笔带过了
vector2d里面对乘法的重载就是向量的缩放,即分别对 X 和 Y 乘上一个值
除法亦然,但是除法好像没有检测除数是否为 0 ,这也不一定算是一个BUG
因为过度的检测会消耗宝贵的运算时间,而且对于内部使用的代码,可以保持一定的信任
vector2d operator*(const vector2d& other) const { return vector2d(X * other.X, Y * other.Y); }
vector2d& operator*=(const vector2d& other) { X*=other.X; Y*=other.Y; return *this; }
vector2d operator*(const T v) const { return vector2d(X * v, Y * v); }
vector2d& operator*=(const T v) { X*=v; Y*=v; return *this; }
vector2d operator/(const vector2d& other) const { return vector2d(X / other.X, Y / other.Y); }
vector2d& operator/=(const vector2d& other) { X/=other.X; Y/=other.Y; return *this; }
vector2d operator/(const T v) const { return vector2d(X / v, Y / v); }
vector2d& operator/=(const T v) { X/=v; Y/=v; return *this; }
getLength() 用以获取向量的模长,返回一个 64位浮点数, 也就是一个double, 和 sqrt() 的返回值类型是一致的
// 返回向量的模长
f64 getLength() const { return sqrt(X*X + Y*Y); }
dotProduct() 返回向量的点积
( 别问我什么是点积,博主不识数 )
// 返回与另一向量的点积结果
T dotProduct(const vector2d& other) const
{
return X*other.X + Y*other.Y;
}
getDistanceFrom() 将向量看作一个二维点, 求两个点之间的距离
( 别问我怎么求距离,博主连数都不识! )
// 返回两个点之间的距离 - 这个函数里, 向量被看作一个二维空间上的点
f64 getDistanceFrom(const vector2d& other) const
{
f64 vx = X - other.X; f64 vy = Y - other.Y;
return sqrt(vx*vx + vy*vy);
}
normalize() 将当前向量单位化, 即是方向不变,长度变为 1
( 别问我怎么单位化, 你忘了博主不识数的么? )
// 单位化一个向量
void normalize()
{
f64 len = getLenght();
X /= len;
Y /= len;
}
稍微复杂一点的是向量的旋转,要用到一些三角函数的知识
vector2d 中对旋转后的向量坐标是酱紫算的 :set(X*cs - Y*sn, X*sn + Y*cs);
在线性代数里,2D向量旋转也可以用 (二维向量 × 二维矩阵) 的方法来计算
先使用从三角函数推到向量旋转的公式 ( 博主装B,前方高能,选择性绕行 (゚Д゚*)ノ )
//////////////////////////////////////////////////////// 装B buff 开始 ////////////////////////////////////////////////////////
将向量 a = (xa, ya) 绕原点逆时针旋转 β 角度, 得到向量 b = (xb, yb)
( 假设向量 a 长度为 L ,向量 a 与 x 轴正半轴夹角为 α )
存在等量关系 xa = L * cosα ya = L * sinα
xb = L * cos(α + β)
= L * ( cosα * cosβ - sinα * sinβ )
= L * cosα * cosβ - L * sinα * sinβ ( 下一步等量替换 )
= xa * cosβ - ya * sinβ
yb = L * sin(α + β)
= L * ( sinα * cosβ + cosα * sinβ )
= L * sinα * cosβ + L * cosα * sinβ ( 下一步等量替换 )
= ya * cosβ + xa * sinβ
所以运算结果和 模长L 以及 向量 a 原来的角度都无关
看看是不是和 vector2d 中的运算方法是一样的?
//////////////////////////////////////////////////////// 装B buff 结束 ////////////////////////////////////////////////////////
void rotateBy(f64 degrees, const vector2d& center)
{
degrees *=gradPI2; // 将角度转换为弧度
T cs = (T)cos(degrees);
T sn = (T)sin(degrees);
X -= center.X; // 将 center作为圆心
Y -= center.Y;
set( X * cs - Y * sn, X * sn + Y * cs ); // 旋转后向量的运算
X += center.X;
Y += center.Y;
}
首先 C 和 C++ 中计算 sine 和 cosine 使用的是弧度制
所以要先将角度转换为弧度
源码中为什么要先 减去 center 的坐标,运算完之后再加回来呢?
是因为旋转公式是围绕原点 (0, 0) 旋转的
所以先减去 center 之后再围绕 (0, 0) 旋转,然后在 加 center 就相当于围绕 center 旋转了
对于2D向量来说,向量就是一个 1×2 的矩阵, 旋转矩阵是一个 2×2 的矩阵
[ x, y ] × | cosβ sinβ | = [ x * cosβ - y * sinβ , x * sinβ + y * cosβ ]
| -sinβ cosβ |
游戏编程对程序员数学是有一定要求的 ( 根据做的内容和使用的工具而异 )
点和向量的使用是游戏数学中最基础也是最简单的部分
其实博主的数学也不是很好,大家多多交流学习吧!
( 今晚突然好想看星空, 贴一张星空吧 Ծ‸ Ծ )