您的位置:首页 > 其它

XNA-2D碰撞-使用像素偵測

2014-07-23 14:42 411 查看

2008/12/14 15:51 | 閱讀數 :8076|
2 人推薦我要推薦
|One Comment | 文章分類 :XNA
| 訂閱

上一篇使用XNA-2D碰撞-使用矩形偵測的缺點就是對於不規則的物體沒輒!而遊戲裡常常都是不規則的物體,所以我們來試試看用像素偵測的方式,

如此不論圖形長什麼樣子都可以準確的偵測出來。

首先我們要將會碰撞的物體其背景變成透明的,png檔案有支援透明背景,我們就用png圖檔來試驗!

像素碰撞的想法如下

未碰撞:





碰撞:





其實還是要有一個碰撞矩形,而當此矩形發生碰撞後,取得重疊的區域,再檢查此區域內兩張圖的每一個像素,若出現有一個點是兩張圖都不透明,則發生碰撞。

因為要取得圖形的顏色,我們在有一個Color[]的陣列,並在初始化的時候將圖形的顏色資訊填入,片段程式碼如下:

view source

print?

1
protected
Color[] pixelColors;
2
3
public
IPixelCollideObject(Texture2D image)
4
:

base
(image) {
5
collideRectangle =
new

Rectangle((
int
)position.X, (
int
)position.Y, image.Width, image.Height);
6
pixelColors =
new

Color[image.Width * image.Height];
7
image.GetData<Color>(pixelColors);
8
}
Texture2D.GetData可以讓我們取得圖片的資訊。

接著就是主要的判段程式碼:

view source

print?

01
public
bool
CollideCheck(ICollideable obj) {
02
if
(collodeable) {
03
PixelCollideObject o = obj
as

PixelCollideObject;
04
if
(o !=
null
) {
05
Rectangle intersect = Rectangle.Intersect(collideRectangle, o.collideRectangle);
06
if
(!intersect.IsEmpty) {
07
for
(
int

y = intersect.Top; y < intersect.Bottom; y++) {
08
for
(
int

x = intersect.Left; x < intersect.Right; x++) {
09
Color colorA = pixelColors[(x - collideRectangle.Left) + (y - collideRectangle.Top) * collideRectangle.Width];
10
Color colorB = o.pixelColors[(x - o.collideRectangle.Left) + (y - o.collideRectangle.Top) * o.collideRectangle.Width];
11
if
(colorA.A != 0 && colorB.A != 0)
return
true
;
12
}
13
}
14
}
15
}
16
}
17
return
false
;
18
}
取得重疊區域使用Rectangle.Intersect函式,他是一個靜態的函式,傳入兩個矩形,將重疊部分回傳,若無重疊則回傳Rectangle.Empty。

迴圈則是由左而又由上而下檢查每個像素,若兩張圖在重疊區域有都不是透明的點的話,就表示發生碰撞了!

範例下載:WindowsGame1.rar

XNA-像素碰撞Per-Pixel Collision(程式範例)

繼續上次矩形碰撞Rectangle Collision的範例程式,將它修改成使用像素偵測的方法去檢驗是否有碰撞到,這個碰撞的方法會比內建的矩形碰撞較準確,至於它大致做的方法在之前的文章如何實現碰撞偵測?有提到過,主要參考到XNA開發者俱樂部的Collision
Series 2:2D Per-Pixel Collision。

此範例也是運用鍵盤的上、下、左、右鍵來移動人物圖片,最主要就是看它與磚塊圖片碰撞的地方,會比矩形偵測來的準確。

程式範例:

view source

print?

001
using
System;
002
using
System.Collections.Generic;
003
using
System.Linq;
004
using
Microsoft.Xna.Framework;
005
using
Microsoft.Xna.Framework.Audio;
006
using
Microsoft.Xna.Framework.Content;
007
using
Microsoft.Xna.Framework.GamerServices;
008
using
Microsoft.Xna.Framework.Graphics;
009
using
Microsoft.Xna.Framework.Input;
010
using
Microsoft.Xna.Framework.Media;
011
using
Microsoft.Xna.Framework.Net;
012
using
Microsoft.Xna.Framework.Storage;
013
014
namespace
Per_Pixel_Collision
015
{
016
public

class
Game1 :Microsoft.Xna.Framework.Game
017
{
018
GraphicsDeviceManager graphics;
019
SpriteBatch spriteBatch;
020
Texture2D block;
021
Texture2D person;
022
Vector2 blockpos;
023
Vector2 personpos;
024
Color[] blockTextureData;
025
Color[] personTextureData;
026
int

movespeed = 3;
027
bool

personHit =
false
;
028
029
public

Game1()
030
{
031
graphics =
new
GraphicsDeviceManager(
this
);
032
Content.RootDirectory =
"Content"
;
033
}
034
035
protected

override
void

Initialize()
036
{
037
blockpos =
new
Vector2(0, 0);
038
personpos =
new
Vector2(50, 0);
039
base
.Initialize();
040
}
041
042
protected

override
void

LoadContent()
043
{
044
spriteBatch =
new
SpriteBatch(GraphicsDevice);
045
spriteBatch =
new
SpriteBatch(GraphicsDevice);
046
block = Content.Load<Texture2D>(
"Block"
);
047
blockTextureData =
new
Color[block.Width * block.Height];
048
block.GetData(blockTextureData);
049
person = Content.Load<Texture2D>(
"Person"
);
050
personTextureData =
new
Color[person.Width * person.Height];
051
person.GetData(personTextureData);
052
}
053
054
protected

override
void

UnloadContent()
055
{
056
}
057
058
protected

override
void

Update(GameTime gameTime)
059
{
060
KeyboardState keyboard = Keyboard.GetState();
061
if

(keyboard.IsKeyDown(Keys.Up))
062
{
063
personpos =
new
Vector2(personpos.X, personpos.Y - movespeed);
064
}
065
if

(keyboard.IsKeyDown(Keys.Down))
066
{
067
personpos =
new
Vector2(personpos.X, personpos.Y + movespeed);
068
}
069
if

(keyboard.IsKeyDown(Keys.Left))
070
{
071
personpos =
new
Vector2(personpos.X - movespeed, personpos.Y);
072
}
073
if

(keyboard.IsKeyDown(Keys.Right))
074
{
075
personpos =
new
Vector2(personpos.X + movespeed, personpos.Y);
076
}
077
Rectangle personRectangle =
new
Rectangle((
int
)personpos.X, (
int
)personpos.Y,
person.Width, person.Height);
078
Rectangle blockRectangle =
new
Rectangle((
int
)blockpos.X, (
int
)blockpos.Y,
block.Width, block.Height);
079
if

(IntersectPixels(personRectangle,personTextureData,blockRectangle, blockTextureData ))
080
{
081
personHit =
true
;
082
}
083
else
084
{
085
personHit =
false
;
086
}
087
base
.Update(gameTime);
088
}
089
090
protected

override
void

Draw(GameTime gameTime)
091
{
092
if

(personHit ==
true
)
093
GraphicsDevice.Clear(Color.Red);
094
else
095
GraphicsDevice.Clear(Color.CornflowerBlue);
096
spriteBatch.Begin();
097
spriteBatch.Draw(block, blockpos, Color.White);
098
spriteBatch.Draw(person, personpos, Color.White);
099
spriteBatch.End();
100
base
.Draw(gameTime);
101
}
102
103
public

bool
IntersectPixels(Rectangle rectangleA, Color[] dataA, Rectangle rectangleB, Color[] dataB)
104
{
105
int

top = Math.Max(rectangleA.Top, rectangleB.Top);
106
int

bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
107
int

left = Math.Max(rectangleA.Left, rectangleB.Left);
108
int

right = Math.Min(rectangleA.Right, rectangleB.Right);
109
110
for

(
int
y = top; y < bottom; y++)
111
{
112
for

(
int
x = left; x < right; x++)
113
{
114
Color colorA = dataA[(x - rectangleA.Left) + (y - rectangleA.Top) * rectangleA.Width];
115
Color colorB = dataB[(x - rectangleB.Left) + (y - rectangleB.Top) * rectangleB.Width];
116
if

((colorA.A != 0 ) && (colorB.A != 0))
117
{
118
return

true
;
119
}
120
}
121
}
122
return

false
;
123
}
124
}
125
}
24~25行宣告的變數是用來存放兩圖片RGBA的資訊。

47~48行和50~51行運用讀取圖片完的寬和高來決定存放該圖所需要的陣列大小,並且取出兩圖片RGBA的資訊。

79行判斷是否碰撞到的函數IntersectPixels需要傳入的參數為兩圖片的Rectange型態和兩圖片Color型態的資訊。

105~108行則是找出兩圖片交集的矩形範圍是多少乘多少。

110行迴圈最主要檢查交集圖片中每個點是否有碰撞到。

114~115行得到交集圖片各點的RGBA的資料。

116行運用圖片的alpha值來判斷是否有碰撞到,如果交集圖片的某點alpha值都不是0那就代表碰到了。




這樣表示沒有碰撞到



這樣才表示有碰撞到
122行交集圖片沒有碰撞在一起的點,所以回傳false。

最後附上專案檔Per-Pixel Collision.rar


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: