本帖最后由 邮递时光 于 2023-5-15 08:05 编辑
向量基础
向量最基本的定义就是一个方向。向量有一个方向和大小,你可以把向量想像成一个藏宝图上的指示:“向左走10步,向北走3步,然后向右走5步”;“左”就是方向,“10步”就是向量的长度。那么这个藏宝图的指示一共有3个向量。
由于向量表示的是方向,起始于何处并不会改变它的值,下图中尽管v和w向量的起始位置不同,但是向量v和w是相等的
向量运算
在游戏开发中,常常会使用到向量运算,比如给定一个起始点的位置和一个方向的向量,想要计算出终点。
加法运算
将两个向量的对应分量相加,得到一个新的向量。例如,若向量 u = (1, 2) 和向量 v = (3, 1),则 u + v = (4, 3)
向量相加相当于从原点沿着(1, 2)走,然后再沿着(3, 1)走,最后走到(4, 3)
在编辑器中的代码如下:
let u = new Vector(1, 2, 0);
let v = new Vector(3, 1, 0);
let w = u.add(v);
减法运算
将两个向量的对应分量相减,得到一个新的向量。例如,若向量 u = (1, 2) 和向量 v = (3, 1),则 A - B = (-2, 1)
向量相减相当于相当于从原点沿着(1, 2)走,然后再沿着(3, 1)的反方向走(也就是(-3, -1)),最后走到(-2, 1)
let u = new Vector(1, 2, 0);
let v = new Vector(3, 1, 0);
let w = u.subtract(v);
值得一提的是,向量的相加的顺序顺序是可以调换的,比如图左先走u再走v和图右先走v再走u结果是一样的,最终的结果都是(4, 3)
乘法运算
将一个向量的每个分量乘以一个标量,得到一个新的向量。例如,若向量 u = (3, 4) 和标量 k = 2,则u * k = (6, 8)
let u = new Vector(3, 4, 0);
const k = 2;
let w = u.multiply(k);
除法运算
将一个向量的每个分量除以一个标量,得到一个新的向量。例如,若向量 u = (6, 8) 和标量 k = 2,则u / k = (3, 4)
let u = new Vector(6, 8, 0);
const k = 2;
let w = u.divide(k);
单位向量
单位向量是指具有长度为1的向量,因为长度为1,单位向量就只表示一个方向,需要特定长度的向量时只需要把向量乘以所需要的长度k可以得到长度为k的向量。
如何把一个向量变为单位向量?
将一个向量标准化的过程被称为“向量归一化”,要将一个向量归一化,我们需要将它的长度除以向量的模长。
单位向量 = 向量 / 向量模长
其中,向量模长可以通过使用勾股定理求得
向量模长 = sqrt(x^2 + y^2)
其中x和y分别是向量在每个轴上的分量
比如:向量u = (3, 4),向量u的模长m为sqrt(3 ^ 2 + 4 ^ 2) = 5
那么向量u的单位向量就是 u / m = (3 / 5, 4 / 5);
在编辑器中,我们可以通过 u.normalize() 来归一化这个向量
let u= new Vector(3, 4, 0);
u.normalize();
可以通过 u.magnitude来得到向量的模长
let u= new Vector(3, 4, 0);
let m = u.magnitude
如何通过两个点来计算向量指向?
从两个点中获取方向向量的方法是通过从一个点到另一个点的向量进行计算。
假设我们有点a和点b,我们可以计算出从a到b的向量u。
这个向量的方向就是从a指向b的方向,长度为ab的距离。
要计算向量u,我们可以使用以下公式:
向量u = 点b的位置 - 点a的位置
let pointA = new Vector(1, 2, 0);
let pointB = new Vector(3, 4, 0);
// u为a到b的向量
let u = pointB.subtrat(pointA);
使用向量运算的注意事项
比如说玩家想从他当前的位置往前射一条长度为100的射线,用了下面的代码
let player = Gameplay.getCurrentPlayer();
// 获取玩家当前位置
let beginPos = player.character.worldLocation;
// 获取玩家面朝方向
let dir = player.character.forwardVector;
// 获取射线终点
let endPos = beginPos.add(dir.multiply(100));
Gameplay.lineTrace(beginPos, endPos, true, true);
但是我们发现射线并没有射出去,原因时因为使用add, subtract, multiply和divide的时候,为了不产生新的向量对象,是会返回修改后的自身对象的。
也就是说,在计算射线终点时,beginPos.add(dir.multiply(100)); 会把beginPos也一同修改,为了避免这个问题,我们可以使用clone来获得一个新的向量对象,再进行计算。
let player = Gameplay.getCurrentPlayer();
// 获取玩家当前位置
let beginPos = player.character.worldLocation;
// 获取玩家面朝方向
let dir = player.character.forwardVector;
// 获取射线终点
// 为了不修改beginPos,先使用clone进行克隆,再计算
let endPos = beginPos.clone().add(dir.multiply(100));
Gameplay.lineTrace(beginPos, endPos, true, true);
|