游戏世界中的向量计算

5 篇文章 0 订阅

前言

在游戏中,向量计算是少不了的,这是必须的,因为每一个物体都带有一个向量,这个向量在数值上等于他们的坐标,也就是Transform组件的position属性,其实position也可以看作一个向量,实际上,每个游戏物体的position就存储在一个Vector变量里。

什么是向量

向量,这是一个既有大小也有方向的量。也许会有人觉得很疑惑,为什么我在前言里说,物体的position也是一个向量,在大多数人看来,这就是一个坐标。其实不是这样,它也是一个向量,他的方向是从原点指向自身,大小是从自身到世界原点的距离,所以我这么说读者应该会理解,为什么说物体的position属性也是一个向量,这个依据不建立在它的值是存储在一个Vector变量里的。也许不熟悉的读者在这里会有点头晕,接下来我着重介绍向量的计算,通过对向量计算的介绍和讲解,去区分开坐标和向量的区别。

  • 向量的计算
    我们随即在世界中创建一个物体,就像这样:

在这里插入图片描述
为了能简单的说明问题,我这里取2D世界来做演示,并且忽略掉负半轴。

我们创建了一个A物体,他的坐标标识为(Xa, Ya);
那么怎么标识,他就是一个向量,(Xa - 0, Ya - 0);这就是它在世界空间中表示的向量,当然我这里不写出符号,这个已经是高中知识了。所以如果把A所在的位置看作一个向量,那么他的大小就是和世界原点的距离,方向是从世界原点指向自己,就是这样:
在这里插入图片描述
额。。。箭头没花完,,意思对就行哈。
所以我希望读者能理解我再开头说的话。这也是非常重要的。

  • 空间中任意两点的向量
    我们随机创建一个物体B:
    在这里插入图片描述
    老样子,物体B的坐标为(Xb, Yb);那么我们如何去计算一个有 B 指向 A 的向量,很简单,用 B 物体的坐标 - A 物体的坐标, 也就可以得出一个有 B 指向 A 的向量。
    也就是这样:

在这里插入图片描述

看到这里也许大部分读者会说这太简单了,自己经常用这个操作去计算和目标的方向。当然确实很简单,这两个物体坐标相减就好了,而且这种表示严格意义上来说他表示的向量不是 (Xa - Xb, Ya - Yb),他表示的其实是(Xa - Xb, Ya - Yb) + (Xb, Yb), 这点读者必须分清楚。

  • 基于向量的移动
    从理论上出发,我们可以得到一个结论,一个物体的坐标 + 一个向量 == 移动的物体,这肯定是没问题的,上面我们算出了,由 B 指向 A 的方向向量,接下来我们通过代码的形式,让 B 向 A 运动,下面是代码:
	Vector2 aPos;
	Vector2 bPos;
		
	void Move()
	{
		bPos = Normalize(aPos - bPos) + bPos;//一般情况下我们取方向的法向量,可以保持一个相对稳定速度的移动
	}

读者一定要明白为什么可以这么做,下面我讲解原因:
这很好理解, (Xa - Xb, Ya - Yb)得出的向量,你也以理解为一个标量,这时我们把这个向量拆开为两个 Float 类型的值,Xa - Xb 和 Ya - Yb, 当你不再把它看作一个向量的时候,他就是一个差值,Xa - Xb, 就是 A 物体和 B 物体之间的在 X 轴上的差, Y也一样,是在Y轴上的差,每次的更新,B 物体的坐标都会加上一个他们之间的差值,所以会实现一个移动的效果,这点很好理解,运用到3D世界中也是一样的。

也许你会觉得这是一个是个人都知道的东西,没什么好讲的,所以接下来我会讲一些我自己在项目中会使用到的实用计算。

标准正交基的构建

所谓标准正交基就是三个相互垂直的单位向量,最常见的标注正交基就是物体的3个坐标轴,X ,Y, Z,那么,如何在任意的角度去构建一个标准正交基呢?
还是一样。不过这次实在空间坐标中随机创建两个物体:
废话不多说直接上代码:

		Vector3 targetDir;
		Vector3 aPos;
		Vector3 bPos;
		void GetXYZ()
		{
			targetDir = Vector3.Normalize(aPos - bPos);
			//1
			Vector3 up = this.Step(0.99, targetDir.y) * Vector3.Up + (1 - this.Step(0.99f, targetDir)) * Vector3.forward;
			Vector3 right = Vector3.Normalize(Vector.Cross(up + targetDir));
			up = Vector3.Cross(right, targetDir);
			
			Debug.DrawRay(Vector3.zero, right, Color.red);
			Debug.DrawRay(Vector3.zero, up, Color.green);
			Debug.DrawRay(Vector3.zero, targetDir, Color.blue);
			
		}
		int Step(float a, float x)
		{
			return x >= a ? 0 : 1; 
		}

这里我是用Unity实现的,这个代码可以让你看到,你构建的直角坐标系,也许你会说这也没用,是因为这些东西过于基础,或者你在你过去的项目中没用用到,在这里写出只是为了在我后续更新的文章中方便读者的理解,而且这些知识在项目中也是有用的。
这里着重说一下“1”处代码,可能有读者会不理解,这里这么处理的原因主要是因为,我们计算出的 targetDir 的方向是任意的,所以我们要防止它与我们参与辅助计算的向量重合,具体读者可以自己试试。

  • 函数讲解
public static Vector3 Cross(Vector3 a, Vector3 b);

这个函数会返回同时垂直于a, b向量的一个向量,如果a 和 b 原本就是互相垂直的那么,返回的向量也就是垂直的,简单的来说也就是向量的叉乘,这是一个重要的方法所以放在最后说,同时这个函数并不会很消耗性能,所以读者可以放心使用,Dot()函数也是一样的,不会对性能造成太大影响,但是CPU计算Cos 与 Sin 时是很耗时的。这点读者需要注意。

结尾

这篇文章会在后期继续修正。由于是公司电脑,所以使用时间不是那么充裕。希望对大家有所帮助。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值