2011-09-17 7 views
0

PacManの複製を楽しく楽しんでいます.PackManが迷路とドットに衝突したときに検出するためにピクセル完全衝突アルゴリズムを使用していますゲームはまだ)。私はアルゴリズムを正しく使っていることは知っていますが、PacManは迷路とPacManの両方が互いに近くにないと迷路に衝突します。私は、デバッグ画面とゲームを示す証拠のために絵を描く。 Proof メインコード:Pixel Perfect Collisionが迷路とPacManとの不正確な衝突を引き起こしている

using System; 
using System.Collections.Generic; 
using System.Linq; 
using Microsoft.Xna.Framework; 
using Microsoft.Xna.Framework.Audio; 
using Microsoft.Xna.Framework.Content; 
using Microsoft.Xna.Framework.GamerServices; 
using Microsoft.Xna.Framework.Graphics; 
using Microsoft.Xna.Framework.Input; 
using Microsoft.Xna.Framework.Media; 

namespace PacMan_Bytes 
{ 
    /// <summary> 
    /// This is the main type for your game 
    /// </summary> 
    public class Game1 : Microsoft.Xna.Framework.Game 
    { 
     enum Direction 
     { 
      Left, 
      Right, 
      Up, 
      Down 
     }; 
     GraphicsDeviceManager graphics; 
     SpriteBatch spriteBatch; 
     Texture2D maze; 
     Texture2D pacman; 
     Color[] mazeclr = new Color[484 * 483]; 
     Color[] pacmanclr = new Color[20 * 27]; 
     Rectangle dest; 
     Rectangle src; 
     int frame = 2; 
     float rotation = 0.0f; 
     Direction dir; 
     public Game1() 
     { 
      graphics = new GraphicsDeviceManager(this); 
      Content.RootDirectory = "Content"; 
      graphics.PreferredBackBufferWidth = 484; 
      graphics.PreferredBackBufferHeight = 483; 
      dest = new Rectangle(50, 455, 20, 27); 
      src = new Rectangle(frame, 0, 20, 27); 
     } 

     /// <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 

      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() 
     { 
      // Create a new SpriteBatch, which can be used to draw textures. 
      spriteBatch = new SpriteBatch(GraphicsDevice); 
      maze = Content.Load<Texture2D>("maze"); 
      pacman = Content.Load<Texture2D>("pacman"); 
      maze.GetData<Color>(mazeclr); 
      // Get the colors that comprises the image for pixel perfect collision. 
      pacman.GetData<Color>(0, src, pacmanclr, 0, 20 * 27); 
     } 

     /// <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(); 
      this.TargetElapsedTime = TimeSpan.FromSeconds(1.0f/13.0f); 
      // Each frame check if the PacMan has collided with the maze. 
      bool collision = PacmanAnimator.CollidedWithMaze(dest, pacmanclr, maze.Bounds, mazeclr); 
      // If PacMan doesn't collide with the maze allow the PacMan to move. 
      if (collision == false) 
      { 
       if (Keyboard.GetState().IsKeyDown(Keys.Left)) 
       { 

        PacmanAnimator.AnimateAndMoveLeft(ref rotation, ref frame, ref src, ref dest); 
        dir = Direction.Left; 
       } 
       else if (Keyboard.GetState().IsKeyDown(Keys.Right)) 
       { 

        PacmanAnimator.AnimateAndMoveRight(ref rotation, ref frame, ref src, ref dest); 
        dir = Direction.Right; 
       } 
       else if (Keyboard.GetState().IsKeyDown(Keys.Up)) 
       { 

        PacmanAnimator.AnimateAndMoveUp(ref rotation, ref frame, ref src, ref dest); 
        dir = Direction.Up; 
       } 
       else if (Keyboard.GetState().IsKeyDown(Keys.Down)) 
       { 

        PacmanAnimator.AnimateAndMoveDown(ref rotation, ref frame, ref src, ref dest); 
        dir = Direction.Down; 
       } 
      } 
      // If collision is true move the PacMan away from the maze's border. 
      else if (collision == true) 
      { 
       if (dir == Direction.Down) 
       { 
        dest.Y -= 1; 
       } 
       else if (dir == Direction.Up) 
       { 
        dest.Y += 1; 
       } 
       else if (dir == Direction.Left) 
       { 
        dest.X += 1; 
       } 
       else if (dir == Direction.Right) 
       { 
        dest.X -= 1; 
       } 
      } 
      if (dest.X < 0) 
      { 
       dest.X = graphics.PreferredBackBufferWidth - 20; 
      } 
      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.Transparent); 

      spriteBatch.Begin(); 
      spriteBatch.Draw(maze, Vector2.Zero, Color.White); 
      spriteBatch.Draw(pacman, dest, src, Color.White, rotation, new Vector2(20/2, 24/2), SpriteEffects.None, 1); 
      spriteBatch.End(); 

      base.Draw(gameTime); 
     } 
    } 
} 

PacmanAnimatorクラス:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using Microsoft.Xna.Framework; 
using Microsoft.Xna.Framework.Audio; 
using Microsoft.Xna.Framework.Content; 
using Microsoft.Xna.Framework.GamerServices; 
using Microsoft.Xna.Framework.Graphics; 
using Microsoft.Xna.Framework.Input; 
using Microsoft.Xna.Framework.Media; 

namespace PacMan_Bytes 
{ 
    static class PacmanAnimator 
    { 
     // Animates and moves the PacMan to the left. 
     public static void AnimateAndMoveLeft(ref float rotation, ref int frame, ref Rectangle src, ref Rectangle dest) 
     { 
      switch (frame) 
      { 
       case 2: 
        { 
         frame = 40; 
         break; 
        } 
       case 40: 
        { 
         frame = 2; 
         break; 
        } 
      } 
      src.X = frame; 
      dest.X -= 7; 
      rotation = MathHelper.ToRadians(180.0f); 
     } 
     // Animates and moves the sprite to the right. 
     public static void AnimateAndMoveRight(ref float rotation, ref int frame, ref Rectangle src, ref Rectangle dest) 
     { 
      switch (frame) 
      { 
       case 2: 
        { 
         frame = 40; 
         break; 
        } 
       case 40: 
        { 
         frame = 2; 
         break; 
        } 
      } 
      src.X = frame; 
      dest.X += 7; 
      rotation = 0.0f; 
     } 
     // Moves and animates the sprite upward. 
     public static void AnimateAndMoveUp(ref float rotation, ref int frame, ref Rectangle src, ref Rectangle dest) 
     { 
      switch (frame) 
      { 
       case 2: 
        { 
         frame = 40; 
         break; 
        } 
       case 40: 
        { 
         frame = 2; 
         break; 
        } 
      } 
      src.X = frame; 
      dest.Y -= 7; 
      rotation = MathHelper.ToRadians(270.0f); 
     } 
     // Moves the sprite downward and animates it. 
     public static void AnimateAndMoveDown(ref float rotation, ref int frame, ref Rectangle src, ref Rectangle dest) 
     { 
      switch (frame) 
      { 
       case 2: 
        { 
         frame = 40; 
         break; 
        } 
       case 40: 
        { 
         frame = 2; 
         break; 
        } 
      } 
      src.X = frame; 
      dest.Y += 7; 
      rotation = MathHelper.ToRadians(90.0f); 
     } 
     // Subroutine that deals with collision. 
     public static bool CollidedWithMaze(Rectangle rectangleA, Color[] dataA, Rectangle rectangleB, Color[] dataB) 
     { 
      // Find the bounds of the rectangle intersection 
      int top = Math.Max(rectangleA.Top, rectangleB.Top); 
      int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom); 
      int left = Math.Max(rectangleA.Left, rectangleB.Left); 
      int right = Math.Min(rectangleA.Right, rectangleB.Right); 

      // Check every point within the intersection bounds 
      for (int y = top; y < bottom; y++) 
      { 
       for (int x = left; x < right; x++) 
       { 
        // Get the color of both pixels at this point 
        Color colorA = dataA[(x - rectangleA.Left) + 
             (y - rectangleA.Top) * rectangleA.Width]; 
        Color colorB = dataB[(x - rectangleB.Left) + 
             (y - rectangleB.Top) * rectangleB.Width]; 

        // If both pixels are not completely transparent, 
        if (colorA.A != 0 && colorB.A != 0) 
        { 
         // then an intersection has been found 
         return true; 
        } 
       } 
      } 

      // No intersection found 
      return false; 
     } 
    } 
} 

PSここでは下の画像とコードがあります。 PacManスプライトは透明な背景を持ち、迷路で見る黒い部分は透明です。だから私はそれが問題ではないことを知っている。ところで、このような長いポストのために申し訳ありません。 編集:コードを理解しやすくするコメントを追加しました。

// If both pixels are not completely transparent, 
if (colorA.A != 0 && colorB.A != 0) 

しかし、それは逆だ:

+0

コードスニペットを簡略化してください。 –

+1

hmmm ...私はあなたがこれを行うために完璧なピクセルの衝突を必要としないと思う...パックマンは動きを制限している...それは地図のブロックを表す単純な2D配列ではずっと簡単だろう、パクマンがブロックの中心にあるとき。 – Blau

答えて

0

いくつかの調査をした後、ピクセルの完全な衝突ではなくタイルベースの衝突を行う方が良いことがわかりました。

2

あなたの問題は、あなたがこの行で「完全に透明ではなく、」テストしようとしているということです、彼らは完全に不透明でないなら、それはテストです。

完全に透明なのは、int/floatに応じて、アルファ255または1.0fです。

+0

しかし、私はBlauに同意する傾向があります。ピクセル完全なのはこのための方法ではありません。しかし、何か理由があってもそれを試してみたいと思ったら、それはクールです。 –

関連する問題