12 Replies - 1145 Views - Last Post: 12 May 2013 - 04:30 AM

#1 Goldfinger007  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 27
  • Joined: 17-September 12

Farseer: How can I move the player over the tiles?

Posted 10 May 2013 - 01:15 AM

Hi. I'm a beginner and it's the first time that I use Farseer in XNA.
I created 4 tiles and I want to move the player over these tiles. But collision is not working. The player can move thru the tiles. I don't want that the player moves thru the tiles. What did I wrong?
I just want to do a little platformer, like the old Mario games.

public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        World world;
        Body rectangle, rectangle2, rectangle3, rectangle4, playerrect;
        Texture2D rectangleSprite, playerSprite;
        float PosX, PosY;

        private static float _displayUnitsToSimUnitsRatio = 100f;

        public static Vector2 ToDisplayUnits(Vector2 simUnits)
        {
            return simUnits * _displayUnitsToSimUnitsRatio;
        }

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            playerSprite = Content.Load<Texture2D>("retromario");
            rectangleSprite = Content.Load<Texture2D>("retrotile");

            if (world == null)
            {
                world = new World(new Vector2(0, 1));
            }
            else
            {
                world.Clear();
            }

            playerrect = BodyFactory.CreateRectangle(world, 0.64f, 0.64f, 1.0f);
            playerrect.BodyType = BodyType.Dynamic;
            playerrect.Position = new Vector2(0.96f, 4.16f);

            rectangle = BodyFactory.CreateRectangle(world, 0.64f, 0.64f, 1.0f);
            rectangle.BodyType = BodyType.Static;
            rectangle.Position = new Vector2(0.96f, 4.16f);

            rectangle2 = BodyFactory.CreateRectangle(world, 0.64f, 0.64f, 1.0f);
            rectangle2.BodyType = BodyType.Static;
            rectangle2.Position = new Vector2(0.32f, 4.80f);

            rectangle3 = BodyFactory.CreateRectangle(world, 0.64f, 0.64f, 1.0f);
            rectangle3.BodyType = BodyType.Static;
            rectangle3.Position = new Vector2(0.96f, 4.80f);

            rectangle4 = BodyFactory.CreateRectangle(world, 0.64f, 0.64f, 1.0f);
            rectangle4.BodyType = BodyType.Static;
            rectangle4.Position = new Vector2(1.60f, 4.80f);          
        }
        
        protected override void Update(GameTime gameTime)
        {
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
            world.Step(Math.Min(elapsed, (1f / 60f)));
            KeyboardState kbState = Keyboard.GetState();

            // Move the player
            if (kbState.IsKeyDown(Keys.Left))
            {
                PosX -= 0.5f * elapsed;
            }
            if (kbState.IsKeyDown(Keys.Right))
            {
                PosX += 0.5f * elapsed;
            }
            if (kbState.IsKeyDown(Keys.Up))
            {
                PosY -= 0.5f * elapsed;
            }
            if (kbState.IsKeyDown(Keys.Down))
            {
                PosY += 0.5f * elapsed;
            }
            playerrect.Position = new Vector2(PosX, PosY);

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            spriteBatch.Begin();
            spriteBatch.Draw(playerSprite, ConvertUnits.ToDisplayUnits(playerrect.Position),
                                           null,
                                           Color.White, playerrect.Rotation, new Vector2(playerSprite.Width / 2.0f, playerSprite.Height / 2.0f), 1f,
                                           SpriteEffects.None, 0f);

            spriteBatch.Draw(rectangleSprite, ConvertUnits.ToDisplayUnits(rectangle.Position),
                                            null,
                                            Color.White, rectangle.Rotation, new Vector2(rectangleSprite.Width / 2.0f, rectangleSprite.Height / 2.0f), 1f,
                                            SpriteEffects.None, 0f);

            spriteBatch.Draw(rectangleSprite, ConvertUnits.ToDisplayUnits(rectangle2.Position),
                                            null,
                                            Color.White, rectangle2.Rotation, new Vector2(rectangleSprite.Width / 2.0f, rectangleSprite.Height / 2.0f), 1f,
                                            SpriteEffects.None, 0f);

            spriteBatch.Draw(rectangleSprite, ConvertUnits.ToDisplayUnits(rectangle3.Position),
                                            null,
                                            Color.White, rectangle3.Rotation, new Vector2(rectangleSprite.Width / 2.0f, rectangleSprite.Height / 2.0f), 1f,
                                            SpriteEffects.None, 0f);

            spriteBatch.Draw(rectangleSprite, ConvertUnits.ToDisplayUnits(rectangle4.Position),
                                            null,
                                            Color.White, rectangle4.Rotation, new Vector2(rectangleSprite.Width / 2.0f, rectangleSprite.Height / 2.0f), 1f,
                                            SpriteEffects.None, 0f);
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }


Is This A Good Question/Topic? 0
  • +

Replies To: Farseer: How can I move the player over the tiles?

#2 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 8948
  • View blog
  • Posts: 33,544
  • Joined: 12-June 08

Re: Farseer: How can I move the player over the tiles?

Posted 10 May 2013 - 05:51 AM

Where - in the update code - is your collision detection? You know, the code that says "hey - I see you are trying to move, but nope! Won't let'cha!"?
Was This Post Helpful? 0
  • +
  • -

#3 Goldfinger007  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 27
  • Joined: 17-September 12

Re: Farseer: How can I move the player over the tiles?

Posted 10 May 2013 - 06:26 AM

I don't know how to do collision detection with Farseer. I thought Farseer would do that automatically. What should I change or add to my code?
Was This Post Helpful? 0
  • +
  • -

#4 aaron1178  Icon User is offline

  • Dovakiin, Dragonborn
  • member icon

Reputation: 169
  • View blog
  • Posts: 1,297
  • Joined: 22-October 08

Re: Farseer: How can I move the player over the tiles?

Posted 10 May 2013 - 06:34 AM

Moved to XNA forum
Was This Post Helpful? 0
  • +
  • -

#5 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 8948
  • View blog
  • Posts: 33,544
  • Joined: 12-June 08

Re: Farseer: How can I move the player over the tiles?

Posted 10 May 2013 - 07:21 AM

Why would you expect it to do it automatically? The last time I checked that doesn't appear to be the code from a typical Farseer tutorial.. Why not slow down and go through one or two?


http://weblogs.asp.n...-beginners.aspx

https://farseerphysics.codeplex.com/
Was This Post Helpful? 0
  • +
  • -

#6 Goldfinger007  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 27
  • Joined: 17-September 12

Re: Farseer: How can I move the player over the tiles?

Posted 10 May 2013 - 07:37 AM

I did this tutorial and changed some things: http://digitalerr0r....indows-phone-1/
The tutorial doesn't explain how to do collision detection between rectangles. How can I do collision between two rectangles?
Was This Post Helpful? 0
  • +
  • -

#7 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 8948
  • View blog
  • Posts: 33,544
  • Joined: 12-June 08

Re: Farseer: How can I move the player over the tiles?

Posted 10 May 2013 - 07:41 AM

How would you go about doing collisions with your code? Be bold - throw out ideas! Go investigate! It is a common topic for games, XNA, and that Farseer physics engine.
Was This Post Helpful? 0
  • +
  • -

#8 LiberLogic969  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 34
  • View blog
  • Posts: 85
  • Joined: 03-September 12

Re: Farseer: How can I move the player over the tiles?

Posted 10 May 2013 - 07:47 PM

Instead of manually changing the position of the player you should be using the Body.ApplyForce or Body.ApplyLinearImpulse.


 if (kbState.IsKeyDown(Keys.Left))
            {
                playerrect.ApplyForce(new Vector2(-0.5f, 0));
            }
            if (kbState.IsKeyDown(Keys.Right))
            {
                playerrect.ApplyForce(new Vector2(0.5f, 0));
            }
            if (kbState.IsKeyDown(Keys.Up))
            {
                playerrect.ApplyForce(new Vector2(0, -0.5f));
            }
            if (kbState.IsKeyDown(Keys.Down))
            {
                playerrect.ApplyForce(new Vector2(0, 0.5f));
            }





Also don't forget to remove this line :


 playerrect.Position = new Vector2(PosX, PosY); 



This post has been edited by LiberLogic969: 10 May 2013 - 07:49 PM

Was This Post Helpful? 0
  • +
  • -

#9 Goldfinger007  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 27
  • Joined: 17-September 12

Re: Farseer: How can I move the player over the tiles?

Posted 11 May 2013 - 02:50 AM

thanks. It works, and it's easier than I thought. In addition, I set the FixedRotation on true so that the character can not rotate.
playerrect.FixedRotation = true;

But I still have difficulties with the rectangles(tiles). I want that the character jumps if the player presses "Space" and if the character is on the ground. Therefore, I use the variable isOnGround. For the moment, the character can not move because isOnGround is always false and I don't know when to set the variable on true or false :helpsmilie:
 if (isOnGround == true)
            {
            // Move the player
            if (kbState.IsKeyDown(Keys.Left))
           {
               playerrect.ApplyForce(new Vector2(-0.5f, 0));
           }
           if (kbState.IsKeyDown(Keys.Right))
           {
               playerrect.ApplyForce(new Vector2(0.5f, 0));
           }
           if (kbState.IsKeyDown(Keys.Space))
           {
               playerrect.ApplyForce(new Vector2(0, -1.5f));
           }
            }


For example, if the character touches the top of a tile, it can jump. If the character is in the air, it can not jump. I don't know how to detect if the character is on the ground or in the air :helpsmilie:
Can I solve the problem with OnCollision? Or how should I set the variable isOnGround?
I found the following code but I don't know how to use it in my case:
Body.OnCollision += Body_OnCollision; // or use a lambda

// ...

bool Body_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
{
    // fixtureA: The fixture of 'Body'
    // fixtureB: The fixture of the body that collided with 'Body'

    // return true : acknowledge the collision
    // return false : ignore the collision the collision
}

Was This Post Helpful? 0
  • +
  • -

#10 LiberLogic969  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 34
  • View blog
  • Posts: 85
  • Joined: 03-September 12

Re: Farseer: How can I move the player over the tiles?

Posted 11 May 2013 - 08:08 AM

You can use the OnCollision and OnSeperation events for that.


playerrect.OnCollision += Player_OnCollision; // or use a lambda
playerrect.OnSeperation += Player_Seperation; // or use a lambda

// ...

bool Player_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
{
    // fixtureA: FixtureA is always the body whose event was subscribed to... in this case its playerrect.
    // fixtureB: Any Fixture that can collide with the playerrect body... in this case its your tiles

    // return true : acknowledge the collision
    // return false : ignore the collision the collision
}

void Player_OnSeperation(Fixture fixtureA, Fixture fixtureB)
{
    // fixtureA: FixtureA is always the body whose event was subscribed to... in this case its playerrect.
    // fixtureB: Any Fixture that can collide with the playerrect body... in this case its your tiles
}





Now you need to be able to figure out if the body you collided with is considered 'ground'. You can do this using CollisionCategories property in the body class. Lets say that every tile in the game you consider the levels 'ground' will be in Category.Cat5...


            rectangle = BodyFactory.CreateRectangle(world, 0.64f, 0.64f, 1.0f);
            rectangle.BodyType = BodyType.Static;
            rectangle.Position = new Vector2(0.96f, 4.16f);
            rectangle.CollisionCategories = Category.Cat5;    <------

            rectangle2 = BodyFactory.CreateRectangle(world, 0.64f, 0.64f, 1.0f);
            rectangle2.BodyType = BodyType.Static;
            rectangle2.Position = new Vector2(0.32f, 4.80f);
            rectangle2.CollisionCategories = Category.Cat5;   <------
  

            rectangle3 = BodyFactory.CreateRectangle(world, 0.64f, 0.64f, 1.0f);
            rectangle3.BodyType = BodyType.Static;
            rectangle3.Position = new Vector2(0.96f, 4.80f);
            rectangle3.CollisionCategories = Category.Cat5;   <------

            rectangle4 = BodyFactory.CreateRectangle(world, 0.64f, 0.64f, 1.0f);
            rectangle4.BodyType = BodyType.Static;
            rectangle4.Position = new Vector2(1.60f, 4.80f);  
            rectangle4.CollisionCategories = Category.Cat5;   <------




You can use this in the OnCollision and OnSeperation methods to switch the isOnGround bool to true or false.


bool Player_OnCollision(Fixture fixtureA, Fixture fixtureB, FarseerPhysics.Dynamics.Contacts.Contact contact)
{
    if (fixtureB.Body.CollisionCategories == Category.Cat5)
    {
        isOnGround = true;
    }

    return true;
}

void Player_OnSeperation(Fixture fixtureA, Fixture fixtureB)
{
   if (fixtureB.Body.CollisionCategories == Category.Cat5)
   {
       isOnGround = false;
   }
}





That should do it! Hope it helped :)

This post has been edited by LiberLogic969: 11 May 2013 - 08:11 AM

Was This Post Helpful? 0
  • +
  • -

#11 Goldfinger007  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 27
  • Joined: 17-September 12

Re: Farseer: How can I move the player over the tiles?

Posted 11 May 2013 - 09:58 AM

thanks. It helped me, but I still have some difficulties :helpsmilie:
 if (fixtureB.Body.CollisionCategories == Category.Cat5)

I always get an error message in this line.
The property or indexer 'FarseerPhysics.Dynamics.Body.CollisionCategories' cannot be used in this context because it lacks the get accessor
What is wrong?

In addition, I don't know how to call Player_OnCollision. What is the third parameter contact?
Player_OnCollision(playerrect, Category.Cat5, contact);

Was This Post Helpful? 0
  • +
  • -

#12 LiberLogic969  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 34
  • View blog
  • Posts: 85
  • Joined: 03-September 12

Re: Farseer: How can I move the player over the tiles?

Posted 11 May 2013 - 04:58 PM

You don't need to call Player_OnCollision or Player_OnSeperation. It is an event which farseer will call for you. Make sure you have these lines in your LoadContent method :


playerrect.OnCollision += Player_OnCollision;
playerrect.OnSeperation += Player_Seperation;





For the error with the CollisionCategories Try this :


if (fixtureB.CollisionCategories == Category.Cat5)




I suggest you learn some more about C# and programming in general before you go any further.
Was This Post Helpful? 0
  • +
  • -

#13 Goldfinger007  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 27
  • Joined: 17-September 12

Re: Farseer: How can I move the player over the tiles?

Posted 12 May 2013 - 04:30 AM

It works, but I have a little problem with jumping. For example, the character jumps from the top of a tile. The character is now in the air and not touching a tile. After that, he touches the right or left side of a tile and is still in the air. In this case, the character can jump again because it touches the side of a tile. I don't want that it can jump again when it touches the side of a tile. I just want that the character can jump when it's feet are on the ground. How can I do that?
How can I determine which side of a tile is colliding with the character?
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1