遊戲世界中的向量計算

前言

在遊戲中,向量計算是少不了的,這是必須的,因爲每一個物體都帶有一個向量,這個向量在數值上等於他們的座標,也就是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 時是很耗時的。這點讀者需要注意。

結尾

這篇文章會在後期繼續修正。由於是公司電腦,所以使用時間不是那麼充裕。希望對大家有所幫助。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章