西西軟件園多重安全檢測(cè)下載網(wǎng)站、值得信賴的軟件下載站!
軟件
軟件
文章
搜索

首頁編程開發(fā)其它知識(shí) → WP7編程中XNA游戲平面矩形碰撞檢測(cè)

WP7編程中XNA游戲平面矩形碰撞檢測(cè)

相關(guān)軟件相關(guān)文章發(fā)表評(píng)論 來源:本站整理時(shí)間:2011/3/26 21:22:05字體大小:A-A+

作者:佚名點(diǎn)擊:255次評(píng)論:3次標(biāo)簽: XNA

  • 類型:系統(tǒng)其它大小:6.1M語言:中文 評(píng)分:10.0
  • 標(biāo)簽:
立即下載

碰撞檢測(cè)在幾乎任何游戲都是很關(guān)鍵的一個(gè)部分,而碰撞檢測(cè)又決定了游戲的流暢性,它對(duì)流暢性的影響如何之大的原因,在于碰撞檢測(cè)算法越是精確到位,游戲?qū)?huì)運(yùn)行得越緩慢。在碰撞檢測(cè)方面,很明顯需要在準(zhǔn)確性和性能之間進(jìn)行權(quán)衡。

實(shí)現(xiàn)碰撞檢測(cè)最簡(jiǎn)單和快速的方式是通過包圍盒算法。當(dāng)用一個(gè)包圍盒算法時(shí),就需要在屏幕上的每個(gè)物體(紋理圖像)周圍“畫“一個(gè)盒子(矩形塊),然后檢查這些盒子是否相交,如果產(chǎn)生相交(怎么聽起來這么耳熟?),就即可判斷出是產(chǎn)生碰撞了。經(jīng)典的碰撞游戲可以看看如今某I設(shè)備上風(fēng)靡全球的小鳥

 

通過物理算法和碰撞檢測(cè)等實(shí)現(xiàn)這只小鳥欺負(fù)小豬的傳說,這點(diǎn)是很值得借鑒滴。

本篇學(xué)習(xí)文章將會(huì)有兩個(gè)紋理圖,一個(gè)圖片做為碰撞塊例如上圖的小鳥,另一個(gè)圖片做為需要在某一地方去檢測(cè)是否與之產(chǎn)生碰撞的紋理,例如上圖的小豬或者城墻。這兩張圖片分別是這樣的:

我是用來檢測(cè)是否有人撞到我的。。。。。

  我沒事喜歡撞人。。。。。。

好了。素材己經(jīng)有了,下面就到了如何為這兩個(gè)紋理圖像添加各種出場(chǎng)的告白動(dòng)作了。首先,還是國(guó)際慣例一把,先給出效果圖:

 

看上圖效果,天上掉下了好多尖尖的小塊呀,快逃命呀,不過小人跑不夠快,被一個(gè)尖尖的小塊砸到了,頓時(shí)滿臉是血,屏幕都被染紅了。悲催咯。。。。

要實(shí)現(xiàn)這個(gè)功能首先我們需要得到小人的碰撞點(diǎn),和每一個(gè)三角形的碰撞點(diǎn)。以獲得小人碰撞點(diǎn)為例,需要得到小人所在的x 坐標(biāo)和y坐標(biāo),并且得到小人的寬度和高度。當(dāng)我們獲取到這個(gè)數(shù)據(jù)的時(shí)候,就可以為小人添加一個(gè)包圍圈也叫矩形檢測(cè)塊:

// 獲得小人的磁撞大小和碰撞的地點(diǎn) 
            //公式為:得到小人所在的x、y 地點(diǎn),然后在那個(gè)x、y點(diǎn)的區(qū)域高寬
            Rectangle personRectangle =
                new Rectangle((int)personPosition.X, (int)personPosition.Y,
                personTexture.Width, personTexture.Height); 

當(dāng)?shù)玫竭@個(gè)矩形塊時(shí)。再依次獲取得到每個(gè)三角形的矩形和其位置使用矩形自帶的函數(shù)Intersects 來檢測(cè)兩個(gè)矩形之者是否產(chǎn)生交接:

 // 與上面獲得小人的碰撞點(diǎn)類似
                Rectangle blockRectangle =
                    new Rectangle((int)blockPositions[i].X, (int)blockPositions[i].Y,
                    blockTexture.Width, blockTexture.Height);

                // 如果小人與其中某一個(gè)碰撞紋理的碰撞點(diǎn)產(chǎn)生碰撞
                if (personRectangle.Intersects(blockRectangle))

  personHit = true;   //這時(shí)的碰撞檢測(cè)將生效  

如上,如果產(chǎn)生交接即在調(diào)用Draw 的時(shí)候改變屏幕的顏色,即可產(chǎn)生碰撞時(shí)的效果,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;     //撞擊點(diǎn)紋理圖像


        // Person 
        Vector2 personPosition;     //小人2D坐標(biāo)
        const int PersonMoveSpeed = 5;  //小人移動(dòng)速度 

        // Blocks
        List<Vector2> blockPositions = new List<Vector2>(); //撞擊點(diǎn)集合
        float BlockSpawnProbability = 0.1f;     //控制撞擊點(diǎn)的下降個(gè)數(shù)
        const int BlockFallSpeed = 10;  //撞擊點(diǎn)下降速度 

        Random random = new Random();
         
        bool personHit = false;         //是否產(chǎn)生碰撞
         
        Rectangle safeBounds; 
        const float SafeAreaPortion = 0.05f;
        Viewport viewport;  //獲得當(dāng)前窗口的寬高對(duì)象

        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;    //小人的坐標(biāo)縱向在屏幕居中
            personPosition.Y = safeBounds.Height - personTexture.Height;    //小人的坐標(biāo)豎向在屏幕底下居中
         
            // 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)    //隨機(jī)循環(huán)Double 型如果隨機(jī)的double 小于0.01f這樣做是避免產(chǎn)生的撞擊 點(diǎn)太多
            { 
                float x = (float)random.NextDouble() *//在屏幕隨機(jī)出現(xiàn) 
                    (graphics.GraphicsDevice.Viewport.Width - blockTexture.Width);//為了不超出屏幕 
                Vector2 v = new Vector2(x, 1);
                blockPositions.Add(v);
            }

            // 獲得小人的磁撞大小和碰撞的地點(diǎn) 
            //公式為:得到小人所在的x、y 地點(diǎn),然后在那個(gè)x、y點(diǎn)的區(qū)域高寬
            Rectangle personRectangle =
                new Rectangle((int)personPosition.X, (int)personPosition.Y,
                personTexture.Width, personTexture.Height);

            // Update each block
            personHit = false;  //默認(rèn)為不碰撞狀態(tài)
            for (int i = 0; i < blockPositions.Count; i++)  //循環(huán)所有在集合里面的碰撞紋理
            {
                // 使里面的所有元素全部下降
                blockPositions[i] =
                    new Vector2(blockPositions[i].X,    //X坐標(biāo)不變
                                blockPositions[i].Y + BlockFallSpeed);  //豎坐標(biāo)為當(dāng)前的Y座標(biāo)每次加上下降的速度常量 

                // 與上面獲得小人的碰撞點(diǎn)類似
                Rectangle blockRectangle =
                    new Rectangle((int)blockPositions[i].X, (int)blockPositions[i].Y,
                    blockTexture.Width, blockTexture.Height);

                // 如果小人與其中某一個(gè)碰撞紋理的碰撞點(diǎn)產(chǎn)生碰撞
                if (personRectangle.Intersects(blockRectangle))
                    personHit = true;   //這時(shí)的碰撞檢測(cè)將生效

                // 如果有碰撞紋理超屏幕
                if (blockPositions[i].Y > graphics.GraphicsDevice.Viewport.Height)
                {   
                    //從集合里面移出該碰撞點(diǎn)
                    blockPositions.RemoveAt(i);
                     
                    //當(dāng)刪除了其中一個(gè)碰撞點(diǎn)時(shí),下一個(gè)碰撞點(diǎn)的索引將跟當(dāng)前移除的碰撞點(diǎn)是一樣的,所以循環(huán)變量自動(dòng)減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)  //當(dāng)產(chǎn)生碰撞
            {
                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);
        }

     輕輕松松的調(diào)用幾個(gè)現(xiàn)成的方法和利用刷新機(jī)制就可以實(shí)現(xiàn)這個(gè)碰撞檢測(cè)功能。當(dāng)然碰撞檢測(cè)還不止這么簡(jiǎn)單,還可以更詳細(xì)的使用逐點(diǎn)檢測(cè)的方法檢測(cè)碰撞。

    相關(guān)評(píng)論

    閱讀本文后您有什么感想? 已有人給出評(píng)價(jià)!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過難過
    • 5 囧
    • 3 圍觀圍觀
    • 2 無聊無聊

    熱門評(píng)論

    最新評(píng)論

    發(fā)表評(píng)論 查看所有評(píng)論(3)

    昵稱:
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字?jǐn)?shù): 0/500 (您的評(píng)論需要經(jīng)過審核才能顯示)