WP7进阶】——XNA游戏平面矩形碰撞检测
?碰撞檢測在幾乎任何游戲都是很關鍵的一個部分,而碰撞檢測又決定了游戲的流暢性,它對流暢性的影響如何之大的原因,在于碰撞檢測算法越是精確到位,游戲將會運行得越緩慢。在碰撞檢測方面,很明顯需要在準確性和性能之間進行權衡。
實現碰撞檢測最簡單和快速的方式是通過包圍盒算法。當用一個包圍盒算法時,就需要在屏幕上的每個物體(紋理圖像)周圍“畫“一個盒子(矩形塊),然后檢查這些盒子是否相交,如果產生相交(怎么聽起來這么耳熟?),就即可判斷出是產生碰撞了。經典的碰撞游戲可以看看如今某I設備上風靡全球的小鳥
?
通過物理算法和碰撞檢測等實現這只小鳥欺負小豬的傳說,這點是很值得借鑒滴。
?
本篇學習文章將會有兩個紋理圖,一個圖片做為碰撞塊例如上圖的小鳥,另一個圖片做為需要在某一地方去檢測是否與之產生碰撞的紋理,例如上圖的小豬或者城墻。這兩張圖片分別是這樣的:
我是用來檢測是否有人撞到我的。。。。。
?
??我沒事喜歡撞人。。。。。。
好了。素材己經有了,下面就到了如何為這兩個紋理圖像添加各種出場的告白動作了。首先,還是國際慣例一把,先給出效果圖:
?
看上圖效果,天上掉下了好多尖尖的小塊呀,快逃命呀,不過小人跑不夠快,被一個尖尖的小塊砸到了,頓時滿臉是血,屏幕都被染紅了。悲催咯。。。。
要實現這個功能首先我們需要得到小人的碰撞點,和每一個三角形的碰撞點。以獲得小人碰撞點為例,需要得到小人所在的x 坐標和y坐標,并且得到小人的寬度和高度。當我們獲取到這個數據的時候,就可以為小人添加一個包圍圈也叫矩形檢測塊:
//?獲得小人的磁撞大小和碰撞的地點?????????????//公式為:得到小人所在的x、y?地點,然后在那個x、y點的區域高寬
????????????Rectangle?personRectangle?=
????????????????new?Rectangle((int)personPosition.X,?(int)personPosition.Y,
????????????????personTexture.Width,?personTexture.Height);?
? ?
當得到這個矩形塊時。再依次獲取得到每個三角形的矩形和其位置使用矩形自帶的函數Intersects?來檢測兩個矩形之者是否產生交接:
?//?與上面獲得小人的碰撞點類似????????????????Rectangle?blockRectangle?=
????????????????????new?Rectangle((int)blockPositions[i].X,?(int)blockPositions[i].Y,
????????????????????blockTexture.Width,?blockTexture.Height);
????????????????//?如果小人與其中某一個碰撞紋理的碰撞點產生碰撞
????????????????if?(personRectangle.Intersects(blockRectangle))
?? personHit?=?true;???//這時的碰撞檢測將生效??
? ? ? ? ? ? ? ? ??
如上,如果產生交接即在調用Draw 的時候改變屏幕的顏色,即可產生碰撞時的效果,DEMO源碼為:
?///?<summary>????///?This?is?the?main?type?for?your?game
????///?</summary>
????public?class?Game1?:?Microsoft.Xna.Framework.Game
????{
????????GraphicsDeviceManager?graphics;
????????SpriteBatch?spriteBatch;
????????Texture2D?personTexture;????//小人紋理圖像
????????Texture2D?blockTexture;?????//撞擊點紋理圖像
????????//?Person?
????????Vector2?personPosition;?????//小人2D坐標
????????const?int?PersonMoveSpeed?=?5;??//小人移動速度?
????????//?Blocks
????????List<Vector2>?blockPositions?=?new?List<Vector2>();?//撞擊點集合
????????float?BlockSpawnProbability?=?0.1f;?????//控制撞擊點的下降個數
????????const?int?BlockFallSpeed?=?10;??//撞擊點下降速度?
????????Random?random?=?new?Random();
?????????
????????bool?personHit?=?false;?????????//是否產生碰撞
?????????
????????Rectangle?safeBounds;?
????????const?float?SafeAreaPortion?=?0.05f;
????????Viewport?viewport;??//獲得當前窗口的寬高對象
????????public?Game1()
????????{
????????????graphics?=?new?GraphicsDeviceManager(this);
????????????Content.RootDirectory?=?"Content";?
????????????//?Frame?rate?is?30?fps?by?default?for?Windows?Phone.
????????????TargetElapsedTime?=?TimeSpan.FromTicks(333333);
????????}
????????///?<summary>
????????///?Allows?the?game?to?perform?any?initialization?it?needs?to?before?starting?to?run.
????????///?This?is?where?it?can?query?for?any?required?services?and?load?any?non-graphic
????????///?related?content.??Calling?base.Initialize?will?enumerate?through?any?components
????????///?and?initialize?them?as?well.
????????///?</summary>
????????protected?override?void?Initialize()
????????{
????????????//?TODO:?Add?your?initialization?logic?here
??????????????viewport?=?graphics.GraphicsDevice.Viewport;
????????????safeBounds?=?new?Rectangle(
????????????????(int)(viewport.Width?*?SafeAreaPortion),????//40
????????????????(int)(viewport.Height?*?SafeAreaPortion),???//24
????????????????(int)(viewport.Width?*?(1?-?2?*?SafeAreaPortion)),??//720
????????????????(int)(viewport.Height?*?(1?-?2?*?SafeAreaPortion)));????//432
????????????//?Start?the?player?in?the?center?along?the?bottom?of?the?screen
????????????
????????????base.Initialize();
????????}
????????///?<summary>
????????///?LoadContent?will?be?called?once?per?game?and?is?the?place?to?load
????????///?all?of?your?content.
????????///?</summary>
????????protected?override?void?LoadContent()
????????{?
????????????spriteBatch?=?new?SpriteBatch(GraphicsDevice);
????????????blockTexture?=?Content.Load<Texture2D>("Block");
????????????personTexture?=?Content.Load<Texture2D>("Person");
????????????personPosition.X?=?(safeBounds.Width?-?personTexture.Width)?/?2;????//小人的坐標縱向在屏幕居中
????????????personPosition.Y?=?safeBounds.Height?-?personTexture.Height;????//小人的坐標豎向在屏幕底下居中
?????????
????????????//?TODO:?use?this.Content?to?load?your?game?content?here
????????}
????????///?<summary>
????????///?UnloadContent?will?be?called?once?per?game?and?is?the?place?to?unload
????????///?all?content.
????????///?</summary>
????????protected?override?void?UnloadContent()
????????{
????????????//?TODO:?Unload?any?non?ContentManager?content?here
????????}
????????///?<summary>
????????///?Allows?the?game?to?run?logic?such?as?updating?the?world,
????????///?checking?for?collisions,?gathering?input,?and?playing?audio.
????????///?</summary>
????????///?<param?name="gameTime">Provides?a?snapshot?of?timing?values.</param>
????????protected?override?void?Update(GameTime?gameTime)
????????{
????????????//?Allows?the?game?to?exit
????????????if?(GamePad.GetState(PlayerIndex.One).Buttons.Back?==?ButtonState.Pressed)
????????????????this.Exit();
????????????TouchCollection?touch?=?TouchPanel.GetState();
????????????if?(touch.Count>0)
????????????{
????????????????if?(touch[0].Position.X?>?viewport.Width?/?2)
????????????????{
????????????????????personPosition.X?+=?PersonMoveSpeed;
????????????????}
????????????????else
????????????????{
????????????????????personPosition.X?-=?PersonMoveSpeed;
????????????????}
????????????}?
????????????double?ran?=?random.NextDouble();
????????????//?TODO:?Add?your?update?logic?here
????????????if?(ran?<?BlockSpawnProbability)????//隨機循環Double?型如果隨機的double?小于0.01f這樣做是避免產生的撞擊?點太多
????????????{?
????????????????float?x?=?(float)random.NextDouble()?*//在屏幕隨機出現?
????????????????????(graphics.GraphicsDevice.Viewport.Width?-?blockTexture.Width);//為了不超出屏幕?
????????????????Vector2?v?=?new?Vector2(x,?1);
????????????????blockPositions.Add(v);
????????????}
????????????//?獲得小人的磁撞大小和碰撞的地點?
????????????//公式為:得到小人所在的x、y?地點,然后在那個x、y點的區域高寬
????????????Rectangle?personRectangle?=
????????????????new?Rectangle((int)personPosition.X,?(int)personPosition.Y,
????????????????personTexture.Width,?personTexture.Height);
????????????//?Update?each?block
????????????personHit?=?false;??//默認為不碰撞狀態
????????????for?(int?i?=?0;?i?<?blockPositions.Count;?i++)??//循環所有在集合里面的碰撞紋理
????????????{
????????????????//?使里面的所有元素全部下降
????????????????blockPositions[i]?=
????????????????????new?Vector2(blockPositions[i].X,????//X坐標不變
????????????????????????????????blockPositions[i].Y?+?BlockFallSpeed);??//豎坐標為當前的Y座標每次加上下降的速度常量?
????????????????//?與上面獲得小人的碰撞點類似
????????????????Rectangle?blockRectangle?=
????????????????????new?Rectangle((int)blockPositions[i].X,?(int)blockPositions[i].Y,
????????????????????blockTexture.Width,?blockTexture.Height);
????????????????//?如果小人與其中某一個碰撞紋理的碰撞點產生碰撞
????????????????if?(personRectangle.Intersects(blockRectangle))
????????????????????personHit?=?true;???//這時的碰撞檢測將生效
????????????????//?如果有碰撞紋理超屏幕
????????????????if?(blockPositions[i].Y?>?graphics.GraphicsDevice.Viewport.Height)
????????????????{???
????????????????????//從集合里面移出該碰撞點
????????????????????blockPositions.RemoveAt(i);
?????????????????????
????????????????????//當刪除了其中一個碰撞點時,下一個碰撞點的索引將跟當前移除的碰撞點是一樣的,所以循環變量自動減1?
????????????????????i--;
????????????????}
????????????}
????????????base.Update(gameTime);
????????}
????????///?<summary>
????????///?This?is?called?when?the?game?should?draw?itself.
????????///?</summary>
????????///?<param?name="gameTime">Provides?a?snapshot?of?timing?values.</param>
????????protected?override?void?Draw(GameTime?gameTime)
????????{
????????????GraphicsDevice.Clear(Color.CornflowerBlue);
????????????GraphicsDevice?device?=?graphics.GraphicsDevice;
????????????//?TODO:?Add?your?drawing?code?here
????????????if?(personHit)??//當產生碰撞
????????????{
????????????????device.Clear(Color.Red);
????????????}
????????????else
????????????{
????????????????device.Clear(Color.CornflowerBlue);
????????????}
????????????spriteBatch.Begin();
????????????//?Draw?person
????????????spriteBatch.Draw(personTexture,?personPosition,?Color.White);
????????????//?Draw?blocks
????????????foreach?(Vector2?blockPosition?in?blockPositions)
????????????????spriteBatch.Draw(blockTexture,?blockPosition,?Color.White);
????????????spriteBatch.End();
????????????base.Draw(gameTime);
????????}
}?
? ???輕輕松松的調用幾個現成的方法和利用刷新機制就可以實現這個碰撞檢測功能。當然碰撞檢測還不止這么簡單,還可以更詳細的使用逐點檢測的方法檢測碰撞。
?本文轉自 terry_龍 51CTO博客,原文鏈接:http://blog.51cto.com/terryblog/527186,如需轉載請自行聯系原作者
總結
以上是生活随笔為你收集整理的WP7进阶】——XNA游戏平面矩形碰撞检测的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网路游侠:用防篡改和WAF保护网站安全
- 下一篇: 2017.11.7 Python 制作E