Collision Detection and Management with Sensors for Box2D XNA and Windows Phone 7

So here is yet another simple concept game that could be fun if implemented using an Accelerometer and better graphics. For now, I am using the Keyboard so you need to have Windows Phone 7 Beta tools. Make sure when you launch the phone you press Page Up on your keyboard to be able to use the keys. Download the Assets Here

Here is the Video

As for the code, The new thing is we implemented the IContactListener interface.  The contact listener supports several events: begin, end, pre-solve, and post-solve. For now we will be interested in the BeginContact Event. BeginContact is called when two fixtures begin to overlap (The Purple Ball overlaps the blue ball). Notice how we are checking to see if the fixtures are Sensors. Why? Because the objective of the game is when the purple ball touches any blue balls we need to remove them. So if we determine that one of the Fixtures is a Sensor we Set the data to the string value of “Remove”.

public void BeginContact(Contact contact)
       {
         //check to see if one of the contacts is a sensor if so then we set its data to a value and remove it
           var fixtureA = contact.GetFixtureA();
           var fixtureB = contact.GetFixtureB();
 
 
           if(fixtureA.IsSensor())
           {
               fixtureA.GetBody().SetUserData("Remove");
           }
           if (fixtureB.IsSensor())
           {
               fixtureB.GetBody().SetUserData("Remove");
           }
       }

Notice how we have the coins set as sensors. Why? Well we don’t want the coins to have an effect on the purple ball. So when we set it as a Sensor we can still get contact information.

 
        private void CreateCoins()
        {
            var bodyDef = new BodyDef();
            bodyDef.type = BodyType.Static;
 
 
            var coinShape = new CircleShape();
            coinShape._radius = coinTexture.Width/2f*scale;
 
            var coinFixture = new FixtureDef();
            coinFixture.isSensor = true;
            coinFixture.shape = coinShape;
 
            for(var i=0;i<10;i++)
            {
                var coinBody = _physicsWorld.CreateBody(bodyDef);
                coinBody.CreateFixture(coinFixture);
                coinBody.Position = new Vector2((float)r.NextDouble()*7.5f +.6f , (float)r.NextDouble() * 4.0f + .5f);
                coinBodies.Add(coinBody);
            }
 
 
        }

Finally the code that removes the ball.

var node = _physicsWorld.GetBodyList();
while(node!=null)
{
    var body = node;
    node = node.GetNext(); 
 
    var coinStatus = (string)body.GetUserData();
    if (coinStatus != "Remove") continue;
    DestroyCoinBody(body);
  
}

private void DestroyCoinBody(Body b)
   {
       _physicsWorld.DestroyBody(b);
       coinBodies.Remove(b);
     
   }

The Full Code

public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
 
        private Texture2D border1Texture;
        private Texture2D border2Texture;
        private Texture2D ballPlayerTexture;
        private Texture2D coinTexture;
 
        private World _physicsWorld;
 
        private Body ballBody;
        private const float scale = 0.01f;
        private static Random r = new Random((int)DateTime.Now.Ticks);
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
 
            // Frame rate is 30 fps by default for Windows Phone.
            TargetElapsedTime = TimeSpan.FromTicks(333333);
            graphics.IsFullScreen = true;
            graphics.SupportedOrientations = DisplayOrientation.LandscapeRight;
            graphics.ApplyChanges();
 
 
        }
 
        private List<Body> coinBodies;
        protected override void Initialize()
        {
 
            _physicsWorld = new World(new Vector2(0, 10), true);
            coinBodies = new List<Body>();
            base.Initialize();
        }
 
       protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
 
            border1Texture = Content.Load<Texture2D>("border1");
            border2Texture = Content.Load<Texture2D>("border2");
            ballPlayerTexture = Content.Load<Texture2D>("ballGame");
            coinTexture = Content.Load<Texture2D>("ballPlayer");
            _physicsWorld.ContactListener = new GameContactListener();
            CreateBall();
            CreateWalls();
            CreateCoins();
 
        }
 
      
        private void CreateCoins()
        {
            var bodyDef = new BodyDef();
            bodyDef.type = BodyType.Static;
 
 
            var coinShape = new CircleShape();
            coinShape._radius = coinTexture.Width/2f*scale;
 
            var coinFixture = new FixtureDef();
            coinFixture.isSensor = true;
            coinFixture.shape = coinShape;
 
            for(var i=0;i<10;i++)
            {
                var coinBody = _physicsWorld.CreateBody(bodyDef);
                coinBody.CreateFixture(coinFixture);
                coinBody.Position = new Vector2((float)r.NextDouble()*7.5f +.6f , (float)r.NextDouble() * 4.0f + .5f);
                coinBodies.Add(coinBody);
            }
 
 
        }
 
       
        private void CreateBall()
        {
            var ballDef = new BodyDef();
            ballDef.type = BodyType.Dynamic;
 
 
            var ballShape = new CircleShape();
            ballShape._radius = ballPlayerTexture.Width/2f*scale;
 
            var ballFixture = new FixtureDef();
            ballFixture.shape = ballShape;
            ballFixture.density = 1.0f;
 
            ballBody = _physicsWorld.CreateBody(ballDef);
            ballBody.Position = new Vector2(2.0f, 2.0f);
            ballBody.CreateFixture(ballFixture);
 
 
        }
 
       
        private void CreateWalls()
        {
            var bodyDef = new BodyDef();
            bodyDef.type = BodyType.Static;
 
           
            var bodyShape = new PolygonShape();
            bodyShape.SetAsEdge(new Vector2(0, .2f), new Vector2(8.0f, .2f));
 
 
 
            var topBody = _physicsWorld.CreateBody(bodyDef);
            topBody.CreateFixture(bodyShape, 0.0f);
 
 
 
            var bottomBody = _physicsWorld.CreateBody(bodyDef);
            bodyShape.SetAsEdge(new Vector2(0, 4.6f), new Vector2(8.0f, 4.6f));
            bottomBody.CreateFixture(bodyShape, 0.0f);
 
 
 
            var leftBody = _physicsWorld.CreateBody(bodyDef);
            bodyShape.SetAsEdge(new Vector2(.2f, 0), new Vector2(.2f, 4.8f));
            leftBody.CreateFixture(bodyShape, 0.0f);
 
 
            var rightBody = _physicsWorld.CreateBody(bodyDef);
            bodyShape.SetAsEdge(new Vector2(7.8f, 0), new Vector2(7.8f, 4.8f));
            rightBody.CreateFixture(bodyShape, 0.0f);
 
        }
        
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
 
            _physicsWorld.Step(1/60f, 10, 10);
            _physicsWorld.ClearForces();
            var node = _physicsWorld.GetBodyList();
            while(node!=null)
            {
                var body = node;
                node = node.GetNext(); 
 
                var coinStatus = (string)body.GetUserData();
                if (coinStatus != "Remove") continue;
                DestroyCoinBody(body);
              
            }
 
            HandleKeyDown();
            base.Update(gameTime);
        }
        private void DestroyCoinBody(Body b)
        {
            _physicsWorld.DestroyBody(b);
            coinBodies.Remove(b);
          
        }
        private KeyboardState prevKeyboardState;
        private void HandleKeyDown()
        {
            var state = Keyboard.GetState();
            Vector2 force = new Vector2();
            if(state.IsKeyDown(Keys.Left) && prevKeyboardState.IsKeyDown(Keys.Left))
            {
                force += new Vector2(-10, 0);
 
            }
            if (state.IsKeyDown(Keys.Right) && prevKeyboardState.IsKeyDown(Keys.Right))
            {
                force += new Vector2(10, 0);
            }
            if (state.IsKeyDown(Keys.Up) && prevKeyboardState.IsKeyDown(Keys.Up))
            {
                force += new Vector2(0, -10);
            }
            if (state.IsKeyDown(Keys.Down) && prevKeyboardState.IsKeyDown(Keys.Down))
            {
                force += new Vector2(0, 10);
            }
            prevKeyboardState = state;
            if(force!=Vector2.Zero)
            {
                ballBody.ApplyForce(force, ballBody.GetWorldCenter());
            }
 
        }
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.White);
 
            spriteBatch.Begin();
            
            
            spriteBatch.Draw(ballPlayerTexture, ballBody.Position/scale, null, Color.White, ballBody.Rotation,
                             new Vector2(ballPlayerTexture.Width/2f, ballPlayerTexture.Height/2f), 1, SpriteEffects.None,
                             0);
            foreach (var coinBody in coinBodies)
            {
                spriteBatch.Draw(coinTexture, coinBody.Position/scale, null, Color.White, coinBody.Rotation,
                                 new Vector2(coinTexture.Width/2f, coinTexture.Height/2f), 1, SpriteEffects.None, 0);
            }
            spriteBatch.Draw(border1Texture, new Vector2(0, 0), Color.White);
            spriteBatch.Draw(border1Texture, new Vector2(0, 460), Color.White);
            spriteBatch.Draw(border2Texture,new Vector2(20,0),null,Color.White,MathHelper.PiOver2,Vector2.Zero,1,SpriteEffects.None,0);
            spriteBatch.Draw(border2Texture, new Vector2(800, 0), null, Color.White, MathHelper.PiOver2, Vector2.Zero, 1, SpriteEffects.None, 0);
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
    public class GameContactListener:IContactListener
    {
 
      
        /**
         * Just Implement the BeginContact because we are Interested in knowing when the Fixtures overlap
         */
        public void BeginContact(Contact contact)
        {
          //check to see if one of the contacts is a sensor if so then we set its data to a value and remove it
            var fixtureA = contact.GetFixtureA();
            var fixtureB = contact.GetFixtureB();
 
 
            if(fixtureA.IsSensor())
            {
                fixtureA.GetBody().SetUserData("Remove");
            }
            if (fixtureB.IsSensor())
            {
                fixtureB.GetBody().SetUserData("Remove");
            }
        }
 
        public void EndContact(Contact contact)
        {
          
        }
 
        public void PostSolve(Contact contact, ref ContactImpulse impulse)
        {
           
        }
 
        public void PreSolve(Contact contact, ref Manifold oldManifold)
        {
          
        }
 
      
    }
Tags: , ,
Categories: Windows Phone 7 | WP7 | XNA

Permalink E-mail | Kick it! | DZone it! | del.icio.us Comments (0) Post RSSRSS comment feed

Comments

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading