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?
Texture2D.GetData可以讓我們取得圖片的資訊。
接著就是主要的判段程式碼:
view source
print?
取得重疊區域使用Rectangle.Intersect函式,他是一個靜態的函式,傳入兩個矩形,將重疊部分回傳,若無重疊則回傳Rectangle.Empty。
迴圈則是由左而又由上而下檢查每個像素,若兩張圖在重疊區域有都不是透明的點的話,就表示發生碰撞了!
範例下載:WindowsGame1.rar
XNA-像素碰撞Per-Pixel Collision(程式範例)
繼續上次矩形碰撞Rectangle Collision的範例程式,將它修改成使用像素偵測的方法去檢驗是否有碰撞到,這個碰撞的方法會比內建的矩形碰撞較準確,至於它大致做的方法在之前的文章如何實現碰撞偵測?有提到過,主要參考到XNA開發者俱樂部的Collision
Series 2:2D Per-Pixel Collision。
此範例也是運用鍵盤的上、下、左、右鍵來移動人物圖片,最主要就是看它與磚塊圖片碰撞的地方,會比矩形偵測來的準確。
程式範例:
view source
print?
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
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 | } |
接著就是主要的判段程式碼:
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 | } |
迴圈則是由左而又由上而下檢查每個像素,若兩張圖在重疊區域有都不是透明的點的話,就表示發生碰撞了!
範例下載: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 | } |
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
相关文章推荐
- XNA中关于2D图形像素碰撞
- [翻译]XNA系列教程 2D碰撞教程2:像素检测
- XNA系列教程 2D碰撞教程2:像素检测
- 2D像素级碰撞检测
- 使用 HitArea 类在 XNA 中测试碰撞,WPXNA(六)
- 2D空间中使用Quadtree四叉树进行碰撞检测优化
- XNA-像素碰撞Per-Pixel Collision(程式范例)
- XNA系列教程 2D 碰撞教程 1: 矩形检测
- 在2D空间中使用四叉树实现碰撞检测
- 完美的像素碰撞检测(使用cocos2dx)
- 像素完美碰撞检测(使用cocos2d-x)
- 在2D空间中使用四叉树实现碰撞检测
- 快速教程:在2D空间中使用四叉树实现碰撞检测
- [翻译]XNA系列教程2D碰撞教程3:转换物体的碰撞检测
- XNA系列教程 2D碰撞教程3:转换物体的碰撞检测
- 使用 JavaScript 和 canvas 做精确的像素碰撞检测
- 【Unity&2D】使用Unity制作2D像素游戏用到的使用插件
- 使用TBarCode SDK创建指定模块像素宽度的2D条码图像
- unity, 如果碰撞使用2d物理,为防止颤动,需将更新position的代码写在FixedUpdate里
- [翻译]XNA系列教程 2D 碰撞教程 1: 矩形检测