`
ijavagos
  • 浏览: 1189531 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

【WP7进阶】——XNA游戏平面矩形碰撞检测

 
阅读更多

碰撞检测在几乎任何游戏都是很关键的一个部分,而碰撞检测又决定了游戏的流畅性,它对流畅性的影响如何之大的原因,在于碰撞检测算法越是精确到位,游戏将会运行得越缓慢。在碰撞检测方面,很明显需要在准确性和性能之间进行权衡。

实现碰撞检测最简单和快速的方式是通过包围盒算法。当用一个包围盒算法时,就需要在屏幕上的每个物体(纹理图像)周围“画“一个盒子(矩形块),然后检查这些盒子是否相交,如果产生相交(怎么听起来这么耳熟?),就即可判断出是产生碰撞了。经典的碰撞游戏可以看看如今某I设备上风靡全球的小鸟

通过物理算法和碰撞检测等实现这只小鸟欺负小猪的传说,这点是很值得借鉴滴。

本篇学习文章将会有两个纹理图,一个图片做为碰撞块例如上图的小鸟,另一个图片做为需要在某一地方去检测是否与之产生碰撞的纹理,例如上图的小猪或者城墙。这两张图片分别是这样的:

我是用来检测是否有人撞到我的。。。。。

我没事喜欢撞人。。。。。。

好了。素材己经有了,下面就到了如何为这两个纹理图像添加各种出场的告白动作了。首先,还是国际惯例一把,先给出效果图:

看上图效果,天上掉下了好多尖尖的小块呀,快逃命呀,不过小人跑不够快,被一个尖尖的小块砸到了,顿时满脸是血,屏幕都被染红了。悲催咯。。。。

要实现这个功能首先我们需要得到小人的碰撞点,和每一个三角形的碰撞点。以获得小人碰撞点为例,需要得到小人所在的x 坐标和y坐标,并且得到小人的宽度和高度。当我们获取到这个数据的时候,就可以为小人添加一个包围圈也叫矩形检测块:

//获得小人的磁撞大小和碰撞的地点
//公式为:得到小人所在的x、y地点,然后在那个x、y点的区域高宽
RectanglepersonRectangle=
newRectangle((int)personPosition.X,(int)personPosition.Y,
personTexture.Width,personTexture.Height);

当得到这个矩形块时。再依次获取得到每个三角形的矩形和其位置使用矩形自带的函数Intersects来检测两个矩形之者是否产生交接:

//与上面获得小人的碰撞点类似
RectangleblockRectangle=
newRectangle((int)blockPositions[i].X,(int)blockPositions[i].Y,
blockTexture.Width,blockTexture.Height);

//如果小人与其中某一个碰撞纹理的碰撞点产生碰撞
if(personRectangle.Intersects(blockRectangle))

personHit=true;//这时的碰撞检测将生效

如上,如果产生交接即在调用Draw 的时候改变屏幕的颜色,即可产生碰撞时的效果,DEMO源码为:

///<summary>
///Thisisthemaintypeforyourgame
///</summary>
publicclassGame1:Microsoft.Xna.Framework.Game
{
GraphicsDeviceManagergraphics;
SpriteBatchspriteBatch;
Texture2DpersonTexture;//小人纹理图像
Texture2DblockTexture;//撞击点纹理图像


//Person
Vector2personPosition;//小人2D坐标
constintPersonMoveSpeed=5;//小人移动速度

//Blocks
List<Vector2>blockPositions=newList<Vector2>();//撞击点集合
floatBlockSpawnProbability=0.1f;//控制撞击点的下降个数
constintBlockFallSpeed=10;//撞击点下降速度

Randomrandom=newRandom();

boolpersonHit=false;//是否产生碰撞

RectanglesafeBounds;
constfloatSafeAreaPortion=0.05f;
Viewportviewport;//获得当前窗口的宽高对象

publicGame1()
{
graphics=newGraphicsDeviceManager(this);
Content.RootDirectory="Content";
//Framerateis30fpsbydefaultforWindowsPhone.
TargetElapsedTime=TimeSpan.FromTicks(333333);
}

///<summary>
///Allowsthegametoperformanyinitializationitneedstobeforestartingtorun.
///Thisiswhereitcanqueryforanyrequiredservicesandloadanynon-graphic
///relatedcontent.Callingbase.Initializewillenumeratethroughanycomponents
///andinitializethemaswell.
///</summary>
protectedoverridevoidInitialize()
{
//TODO:Addyourinitializationlogichere
viewport=graphics.GraphicsDevice.Viewport;
safeBounds=newRectangle(
(int)(viewport.Width*SafeAreaPortion),//40
(int)(viewport.Height*SafeAreaPortion),//24
(int)(viewport.Width*(1-2*SafeAreaPortion)),//720
(int)(viewport.Height*(1-2*SafeAreaPortion)));//432

//Starttheplayerinthecenteralongthebottomofthescreen

base.Initialize();
}

///<summary>
///LoadContentwillbecalledoncepergameandistheplacetoload
///allofyourcontent.
///</summary>
protectedoverridevoidLoadContent()
{
spriteBatch=newSpriteBatch(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:usethis.Contenttoloadyourgamecontenthere
}

///<summary>
///UnloadContentwillbecalledoncepergameandistheplacetounload
///allcontent.
///</summary>
protectedoverridevoidUnloadContent()
{
//TODO:UnloadanynonContentManagercontenthere
}

///<summary>
///Allowsthegametorunlogicsuchasupdatingtheworld,
///checkingforcollisions,gatheringinput,andplayingaudio.
///</summary>
///<paramname="gameTime">Providesasnapshotoftimingvalues.</param>
protectedoverridevoidUpdate(GameTimegameTime)
{
//Allowsthegametoexit
if(GamePad.GetState(PlayerIndex.One).Buttons.Back==ButtonState.Pressed)
this.Exit();

TouchCollectiontouch=TouchPanel.GetState();
if(touch.Count>0)
{
if(touch[0].Position.X>viewport.Width/2)
{
personPosition.X+=PersonMoveSpeed;
}
else
{
personPosition.X-=PersonMoveSpeed;
}
}

doubleran=random.NextDouble();
//TODO:Addyourupdatelogichere
if(ran<BlockSpawnProbability)//随机循环Double型如果随机的double小于0.01f这样做是避免产生的撞击点太多
{
floatx=(float)random.NextDouble()*//在屏幕随机出现
(graphics.GraphicsDevice.Viewport.Width-blockTexture.Width);//为了不超出屏幕
Vector2v=newVector2(x,1);
blockPositions.Add(v);
}

//获得小人的磁撞大小和碰撞的地点
//公式为:得到小人所在的x、y地点,然后在那个x、y点的区域高宽
RectanglepersonRectangle=
newRectangle((int)personPosition.X,(int)personPosition.Y,
personTexture.Width,personTexture.Height);

//Updateeachblock
personHit=false;//默认为不碰撞状态
for(inti=0;i<blockPositions.Count;i++)//循环所有在集合里面的碰撞纹理
{
//使里面的所有元素全部下降
blockPositions[i]=
newVector2(blockPositions[i].X,//X坐标不变
blockPositions[i].Y+BlockFallSpeed);//竖坐标为当前的Y座标每次加上下降的速度常量

//与上面获得小人的碰撞点类似
RectangleblockRectangle=
newRectangle((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>
///Thisiscalledwhenthegameshoulddrawitself.
///</summary>
///<paramname="gameTime">Providesasnapshotoftimingvalues.</param>
protectedoverridevoidDraw(GameTimegameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
GraphicsDevicedevice=graphics.GraphicsDevice;
//TODO:Addyourdrawingcodehere
if(personHit)//当产生碰撞
{
device.Clear(Color.Red);
}
else
{
device.Clear(Color.CornflowerBlue);
}


spriteBatch.Begin();

//Drawperson
spriteBatch.Draw(personTexture,personPosition,Color.White);

//Drawblocks
foreach(Vector2blockPositioninblockPositions)
spriteBatch.Draw(blockTexture,blockPosition,Color.White);

spriteBatch.End();

base.Draw(gameTime);
}

}

轻轻松松的调用几个现成的方法和利用刷新机制就可以实现这个碰撞检测功能。当然碰撞检测还不止这么简单,还可以更详细的使用逐点检测的方法检测碰撞。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics