2D游戲中常見的碰撞檢測處理(僅碰撞體)【持續更新】


 


寫在前面

嗯...打算開始每天寫點啥了,不知道能堅持多久。

准備以一周為單位來進行更新,周一~周三寫一些圖形方面的內容,四~六是和圖形沒有什么太大關聯的內容(意會就好),周日作為一個更新重點試着寫一些亂七八糟的東西。

那么就這樣開始更新了w~

 


在現今的游戲中,碰撞檢測可以說是一個基礎的不能再基礎的技術。它關乎能否正確判斷玩家的攻擊有沒有擊中目標,判斷玩家有沒有踩在地板上,判斷某兩個物體有沒有碰撞在一起,進而衍生出其它的各種行為。

而碰撞檢測是建立在碰撞體上的。碰撞體是對一個物體“邊界”的確切描述,它描述了每個需要進行碰撞檢測的物體的邊界,並依靠數學方法判斷這些邊界是否相交,進而產生碰撞檢測的結果。

(“老鷹用爪子抓到了兔子”)

如上圖所示,代表老鷹爪子的兩個藍色圓和代表兔子的淡黃色圓“相交”了,由此我們判定鷹抓到了兔子,進行一系列的后續操作。在這個過程中,我們不在意鷹的爪子具體是什么樣子的,而只在意它的邊界在哪里。在這個例子中,邊界就是一個單純的圓形。

在電子游戲發展早期,碰撞體和實際的輪廓之間還存在着巨大的差異,只是能夠概括其大概的邊界而已。盡管現在我們有許多豐富的手段來讓我們的碰撞體盡可能的接近真實的外形,但多數情況下並不會這么做——歸根結底,這么做沒給游戲的真實程度帶來什么太大的提升,反而還糟蹋了游戲的運行速度。

那讓我們從一個最基本的開始吧。

1)圓形碰撞體

圓形碰撞體可以說是最簡單的一種碰撞體,其計算速度也是最快的,算法也非常容易理解。

回想一下初中數學中關於兩圓“相交”的定義:兩圓圓心的距離大於半徑和,我們就可以按照它來判斷兩圓是否相交。

 

1 bool IsHit(double x1, double y1, double x2, double y2, double r1, double r2)
2 {
3     //勾股定理
4     return ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) < (r1+r2)*(r1+r2);
5 }

 

它也可以非常方便的擴展到三維球。這種碰撞體擁有最簡單的計算過程,在運動速度夠快(或形狀夠圓)的情況下也不會有太大的違和感;在彈幕游戲和射擊游戲以及大量其它游戲中應用廣泛。

 

2)"軸對齊"包圍盒、Axis-Aligned Bounding Box (AABB)

這玩意好像也沒什么統一的譯名,所以在這里稱為“軸對齊”包圍盒,不過說AABB的話知道的人應該都知道是什么東西。除了用圓(球)來表示一個物體的邊界,另外一種容易被人們想到的模型就是“盒子”——長方形(體)。但是會在空間中能隨便轉的盒子好像計算起來稍微有那么一點難算,也不好表示它到底怎么轉了之類,於是人們就想到干脆別讓它轉,只能“立着”,就產生了AABB包圍盒。

這么說好像有點越說越亂了...總之看圖。

對於這種包圍盒,我們可以很方便的通過min點和MAX點(見右上方藍色方塊)的位置來完全確定這樣一個盒子,同時通過一些比較大小的操作就可以確定兩個盒子是否相交。

(懶得貼代碼了w)

 

 3)逐像素碰撞檢測

為了追求和形狀最完美的貼合,人們展示了計算機可怕的計算力 —— 一種近乎於“暴力枚舉”的方法。人們假設組成每個畫面上的物體的是許許多多的像素點(雖然事實上這多半是真實情況),然后逐個像素的去比較它和其他的形狀是否發生了碰撞。

從一個比較簡單但是足夠說清楚事的例子開始吧。假設有兩個大小為3x3的物體a和b(這個大小在屏幕上就是一個點),組成它們的像素分別是a1~a9,b1~b9:

Pixel by pixel checking.

為了“逐像素”地判斷a和b是否發生碰撞,我們需要每個像素每個像素的比較。來看看人們是怎么粗暴地解決這個問題的:

1)比較a1和b1位置是否相同

2)比較a1和b2位置是否相同

3)比較a1和b3位置是否相同

...

10)比較a2和b2位置是否相同(b1已經比過了)

11)比較a2和b3

...

45)比較a9和b9

就這樣足足45次計算算出了兩個3x3的物體是否碰撞。事實上這種方法有着巨大的開銷,只有在非常必要的時候(其他方法都會誤判)才有可能把它祭出來。不過它有着無可比擬的精細程度,在不追求實時渲染的情況下(比如一些工業生產、模擬、科研場景中),才稍微有點用它的必要性。

 

4)方向包圍盒(Oriented Bounding Box, OBB)

方向包圍盒OBB是一種被廣泛使用的碰撞體。它也是一個長方形,但是它可以在空間中自由旋轉。同時,我們只需要稍微復雜一點的方法就可以計算出兩個OBB包圍盒是否相交,加上它可以自由旋轉帶來的非常少的冗余部分(本不屬於那個物體的 “碰撞面積” ),讓它成為了最廣泛使用的碰撞體。

 

明天會有啥?

碰撞體的復合 & 碰撞檢測上的小技巧。

 


隨記 - 2016 / 4 / 7 星期四

第一天更新,感覺那個圖還是蠻費時間的...之后大部分圖可能直接從網上找了。

===

Unity似乎用不了GLSL。可以試試NV的Cg,原因嗎...只能說雖然身在ms但是對HLSL沒有什么好感。

用Cg跟着教程隨便寫了個Show Screen Space Normal的shader,感覺還是挺平易近人的。

 

P.S. Unity添加shader的方法:

想要和場景中的燈光交互需要用Unity的SurfaceShader,還沒有仔細研究,感覺unity自帶的standardShader這個材質能干的事情夠多了。

unity也提供了傳統的shader接口,包括VS(頂點着色器), FS(片斷着色器); GS(幾何體“着色”器)/HS(外殼“着色”器)/TS(細分“着色”器)/DS(域“着色”器)是否支持還沒細看。想使用的話需要使用Unlit(無光) Shader。

似乎也支持進行GPU的通用計算(CS, Computed Shader),沒有看。

 

具體的添加方法:  Assets > Create > Shader > Unlit Shader / Surface Shader.

詳細的看官網: http://docs.unity3d.com/Manual/ShadersOverview.html

 

(附上那個蠢極了的ShowScreenSpaceNormal)

 1 Shader "Unlit/simpleShowNormals"
 2 {
 3     Properties
 4     {
 5         _MainTex ("Texture", 2D) = "white" {}
 6     }
 7     SubShader
 8     {
 9         Tags { "RenderType"="Opaque" }
10         LOD 100
11 
12         Pass
13         {
14             CGPROGRAM
15             #pragma vertex vert
16             #pragma fragment frag
17 
18             struct appdata
19             {
20                 float3 normal : NORMAL;
21                 float4 vertex : POSITION;
22                 float2 uv : TEXCOORD0;
23             };
24 
25             struct v2f
26             {
27                 fixed3 normal3 : COLOR0;
28                 float2 uv : TEXCOORD0;
29                 UNITY_FOG_COORDS(1)
30                 float4 vertex : SV_POSITION;
31             };
32 
33             sampler2D _MainTex;
34             float4 _MainTex_ST;
35             
36             v2f vert (appdata v)
37             {
38                 v2f o;
39                 o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
40                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
41                 o.normal3 = mul(UNITY_MATRIX_MVP, v.normal) * 0.5 + 0.5;
42                 return o;
43             }
44             
45             fixed4 frag (v2f i) : SV_Target
46             {
47                 return fixed4(i.normal3, 1);
48             }
49             ENDCG
50         }
51     }
52 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM