如何用高效的方式實現遊戲世界中的擊中效果

2021-09-27 12:11:58 字數 2969 閱讀 8297

模擬乙個飛彈或者炮彈擊中乙個標目,是大部分遊戲經常要做得的一件事,通常我們會使用遊戲引擎中自帶的碰撞檢測事件來實現這個效果,或者是判斷距離,但這兩者都不是最優的方法,下面我會介紹一種我目前使用的方法。這裡著重以unity舉例來說,但是不限制於unity引擎,也就是適用於任何一款遊戲引擎。

1.理由

碰撞檢測是乙個很耗費效能的操作,讀者可以想象一下,為什麼引擎自帶的碰撞系統會在物體和目標發生碰撞時會有現實世界中的物理特性,比如物體上的某乙個點與目標發生碰撞就會導致物體的自身旋轉屬性發生一系列變化,這都是非常複雜的數學計算產生的結果,而且最重要的一點,cpu還要去計算到底是物體的哪乙個點和目標發生碰撞,所以這一系列的數學計算絕對都是很複雜的,所以如果你要做的是乙個或者幾個單位還可以,但是一旦單位太多的話,cpu機會計算太多的物理資料,所以這是個很耗費效能的操作,如果讀者想做乙個多單位的專案,那麼這種方法基本可以放棄。

當然還有一點在unity中,遊戲是按幀執行的,讀者可以理解為自己看到的遊戲就是又一系列***組成的,只是以極小時間間隔來這些畫面,一般幀率在24幀以上,人眼就認為這是乙個連貫不卡頓的動畫,也就是一秒鐘人眼至少要處理24張***,才能認為這是副連貫的畫面,在unity中有update函式,在虛幻中也有tick函式,來實現這個效果;

為什麼我要說這個,遊戲是按真執行的,也就是遊戲物體的位置是按幀更新的,如果乙個遊戲物體的速度太快,也就是說,每幀位置之間的距離很大,就會出現碰撞失效的方法,當然前提是目標位置剛好在物體的兩幀位置之間。

2.結論

碰撞檢測是乙個很不靠譜的方法,能不用就不用!

1.理由

除開碰撞檢測之外還可以通過距離去判斷物體是否到達目標點,一般這應該是乙個廢棄碰撞檢測方法後首選的方案,因為相對於碰撞檢測,他不需要cpu去計算那麼複雜的資料,大大降低了cpu的運算量,這個方法接收的計算量肯定是遠遠少於碰撞檢測的,也就是說它能計算更多的單位,至少比碰撞檢測多,但是他仍然不是最優的方法,要理解這一點就要去理解在遊戲引擎中的兩個位置之間的距離是如何計算的:

(這裡略過向量的講解)

我們知道,如果我們想去計算乙個物體的和另乙個物體的距離,那麼我們首先要知道這兩個物體的位置,在遊戲中也就是position屬性,然後做差,得到乙個新的向量,再取這個向量的模,下面我用c#**演示:

void

distance()

float

normofvector

(vector3 vector)

//求乙個向量的模

void

start()

注:「^」運算子在c#中適用與int型別變數,mathf.pow()為求乙個值的平方的函式
我們可以看到在這個方法中cpu要進行一次開根號的操作,作為程式設計師,我們要知道的是cpu在計算 「+,*」的速度是要比計算「-,/, sqrt」的速度快的,所以頻繁的開根號也是乙個很耗時的操作,能少用就少 用,最好不用,那麼以這個例子來說開個為什麼耗時呢?這裡不再多說,讀者可以自己去找找相關的實現 **;

2. 結論

對於這個方法來說,雖然相對碰撞比較實用,但是他需要每幀都計算乙個距離,這也是很耗費時間的操作,另外你還需要控制飛彈的運動軌跡,如果軌跡是直線,也仍需要判斷距離。

在我之前的專案中,我嘗試了一種新的方法,用插值去實現飛彈的飛行和擊中判定。

思路:如何用插值實現?

unity系統內建的vector3中提供了一種對vector3變數進行線性插值的方法,lerp()函式,它的函式原型是這樣:

public

static

vector3

lerp

(vector3 a,

vector3 b,

float t)

;

有了這個函式,我們可以先獲取開始位置和目標位置,然後用時間去判斷是否擊中目標,其中t的值是限制在0 - 1之間的數,當 t == 0時,這個函式範圍的位置是開始位置,當 t == 0.5f 時這個函式返回的位置時位於開始位置和結束位置之間的位置,當 t == 1 時函式返回的位置就是結束位置,這也是我們判斷的依據,

其中他是線性插值也是我們的重要判斷依據:

這個測試證明了它是乙個線性插值,下面是測試**:

public

float tempvalue;

public

float interval;

public

vector3 self;

public

vector3 target;

public

transform testcube;

void

update()

void

setlerpvector3()

}

我這裡也提供乙個lerp函式內部實現的版本(當然,這是以我自己的理解寫的):
public

float

lerp

(float a,

float b,

float t)

很好理解的函式對吧,vedctor3.lerp()內部就是把每個分量都呼叫這個函式進行插值;
這樣我們把判斷距離的問題轉化為了判段乙個值是否大於1的問題,大大的減少了計算量,當然你會說這麼做只適用於直線飛行的飛彈,實際上我們可以對這個位置上的值做任何改變,只要保持頭和尾都在對應的起點和終點就行了,那麼怎麼做呢?

我會在下一次更新時說明解決方法,當前前提是你得有3d數學的基礎,否則你可能會看的一頭霧水,同時我也會解決飛彈的朝向問題。

我所介紹的東西都是偏於實戰,因為這些知識都是我從實戰中摸索所來的,所以理論東西可能欠缺,只是我的理解,由於本人不喜歡吧東西講的太深奧,而往往講出一些有邏輯推理而得到的結論,往往會更有說服力,更容易讓讀者理解,所以文件基於實踐,不基於理論。

如何用XML實現高效管理資料

xml資料是web上資料交換和表達的標準形式,和關聯式資料庫相比,xml資料可以表達具有複雜結構的資料,比如樹結構的資料。正因為此,在資訊整合系統中,xml資料經常被用作資訊轉換的標準。bitscn com 管理三大領域資料 bbs.bitscn.com網管論壇 基於xml資料的特點,xml資料的高...

如何用C語言實現圈叉遊戲( )

今天情人節,還是在學習c語言 自己寫了一遍發現自己寫的沒有書上的 更簡練 就把書上的 稍微修改了一下 下面看遊戲介面 和昨天的公尺字棋差不多,有時間會結合公尺字旗的 做些修改 上 井字遊戲 也稱為圈叉遊戲 includeint main void for int i 0 i 9 winner 0 i...

sublime中如何用less實現css預編譯

實現css預編譯的方式有很多,聽說glup很流行而且功能也很強大,但是就目前的工作而言,僅要css預編譯和yuicompress就夠了,接下來切入正題 less 是一門 css 預處理語言,它擴充套件了 css 語言,增加了變數 mixin 函式等特性,使 css 更易維護和擴充套件。less 可以...