SFML community forums

Help => General => Topic started by: Kubik on August 15, 2012, 01:09:37 pm

Title: box2d
Post by: Kubik on August 15, 2012, 01:09:37 pm
Please give me example how work with him in sfml with sprites
Title: Re: box2d
Post by: eXpl0it3r on August 15, 2012, 02:44:12 pm
Please use the search function and your brain to find such examples. ;)
Title: Re: box2d
Post by: TheVirtualDragon on August 15, 2012, 06:34:44 pm
I will give you a hint which will make life easier: Box2D has y increasing towards the top and calculates angles in radians while SFML has y increasing towards the bottom and calculates angles in degrees.

Also, GetPosition() in box2d returns the centre of a body while in SFML getPositon() (or GetPosition in SFML 1.6) returns the top left corner.

P.S. I don't blame Kubic for asking for an example, because I had loads of problems with Box2D and SFML and I searched for ages before I found anything decent.
Title: Re: box2d
Post by: FRex on August 15, 2012, 07:31:06 pm
1. Don't assume Box2d has y increasing towards the top, it's much easier this way.
2. #define or (preferably) make const floats to convert between pixels and meters, and radians and degrees to make your life easier.
3. Read sfml tutorials and documentation.
4. Read official user manual from box2d site.
5. Read this tutorials series, it's not for the latest version of box2d but changes are minor and it points out when something is done differently in latest version: http://www.iforce2d.net/b2dtut/
Title: Re: box2d
Post by: TheVirtualDragon on August 16, 2012, 05:11:39 pm
Quote
1. Don't assume Box2d has y increasing towards the top, it's much easier this way.

Actually, if you set gravity to be something like (0.0f, -10.0f) like it is in the real world, then you can't not assume that Box2D has y increasing to the top. If you make gravity to be (0.0f, 10.0f) then you don't need to flip the y axis.
Title: Re: box2d
Post by: Kubik on August 21, 2012, 09:18:53 am
Thanks for your answers... I use sfml 2.0 and box2d 2.1.2. I read documeantation of sfml 2.0 and not found function of set center of sprite.
how this function is named in sfml 2.0? How many pixels per meter? 64 or 32?
Title: Re: box2d
Post by: TheVirtualDragon on August 21, 2012, 11:42:26 am
You cannot set centre of a sprite, as there is no such function. You can implement your own function, or use the existing function - which is sf::Sprite::SetPosition - to align the centre of the sprite to the body's centre of mass. You can do it like this:

Code: [Select]
b2Vec2 bodyPos = body->GetPosition();
exampleSprite.setPosition(bodyPos.x - bodySize.x, bodyPos.y - bodySize.y);

Note that you might need to mess around with the second parameter of the setPosition function if gravity is negative in your world (i.e. b2Vec2 gravity(0.0f, -9.81f)). This works for me:

Code: [Select]
exampleSprite.setPosition(bodyPos.x - bodySize.x, - (bodyPos.y + bodySize.y) );

There are other ways of doing this, but I think that is the easiest.

Also note that you will have to declare bodySize yourself, either as a b2Vec2 or a sf::Vector2f. I don't recall there being anyway of getting the dimensions of a fixture or body, I think you will have to set it manually.
Title: Re: box2d
Post by: Kubik on August 21, 2012, 11:59:32 am
what is bodySize? Is b2PolygonShape size?
Title: Re: box2d
Post by: Kubik on August 21, 2012, 12:02:53 pm
#include <SFML/Graphics.hpp>
#include <Box2D/Box2D.h>
#include <iostream>

using namespace std;

const float M = 64.0;
const float P = 1.0/64.0;

int main()
{
    sf::RenderWindow Window(sf::VideoMode(800, 600, 32), "Test");
    // &#1089;&#1086;&#1079;&#1076;&#1072;&#1077;&#1084; &#1084;&#1080;&#1088;
    b2Vec2 gravity(0.0, 9.8);
    bool sleep = true;
    b2World world(gravity, sleep);

    // &#1089;&#1086;&#1079;&#1076;&#1072;&#1077;&#1084; &#1092;&#1080;&#1079;&#1080;&#1095;&#1077;&#1089;&#1082;&#1080;&#1081; &#1086;&#1073;&#1098;&#1077;&#1082;&#1090;
    b2BodyDef bodydef;
    bodydef.type = b2_dynamicBody;
    // &#1086;&#1087;&#1088;&#1077;&#1076;&#1077;&#1083;&#1103;&#1077;&#1084; &#1077;&#1075;&#1086; &#1082;&#1072;&#1082; &#1089;&#1090;&#1072;&#1090;&#1080;&#1095;&#1077;&#1089;&#1082;&#1080;&#1081;
    bodydef.position.Set(0,0);
    bodydef.angle = 0;
    // cjplftv &#1089;&#1072;&#1084; &#1086;&#1073;&#1098;&#1077;&#1082;&#1090;
    b2Body* body = world.CreateBody(&bodydef);
    // &#1089;&#1086;&#1079;&#1076;&#1072;&#1077;&#1084; &#1087;&#1086;&#1083;&#1080;&#1075;&#1086;&#1085; &#1080; &#1082;&#1088;&#1077;&#1087;&#1083;&#1077;&#1085;&#1080;&#1077;
    b2PolygonShape polygonShape;
    polygonShape.SetAsBox(64/2*P, 64/2*P);
    b2FixtureDef fixture;
    fixture.density = 0.5;
    fixture.friction = 0.7;
    fixture.shape = &polygonShape;
    body->CreateFixture(&fixture);
    //body->GetWorldPoint( b2Vec2(0,0) );
    // &#1089;&#1086;&#1079;&#1076;&#1072;&#1077;&#1084; &#1090;&#1077;&#1082;&#1089;&#1090;&#1091;&#1088;&#1091;
    sf::Texture texture;
    texture.loadFromFile("block.png");
    sf::Sprite sprite(texture);

    while (Window.isOpen())
    {
        Window.clear();
        world.Step(1/60, 6, 2);

        b2Vec2 bodyPos = body->GetPosition();
        b2Vec2 bodySize = b2Vec2(64*P, 64*P);
        sprite.setPosition(bodyPos.x - bodySize.x, bodyPos.y - bodySize.y);


        cout << "(" << body->GetPosition().x << ";" << body->GetPosition().y << ")" << endl;
        Window.draw(sprite);
        Window.display();
    }
    return 0;
}
 
why my body don't fly down? please help
Title: Re: box2d
Post by: TheVirtualDragon on August 21, 2012, 03:20:49 pm
Your body won't fly down because gravity is:

b2Vec2 gravity(0.0, 9.8);
 

It should be:

b2Vec2 gravity(0.0f, -9.80f); //The minus is important. In physics, a negative force means down.
 

And bodySize is the size of the body. If the shape of the body is not a rectangle (i.e. the shape is a custom polygon), then body size should be the size of the sprite. So, for clarity, it really should be this:

exampleSprite.setPosition(bodyPos.x - spriteSize.x, - (bodyPos.y + spriteSize.y) );
 
Title: Re: box2d
Post by: G. on August 21, 2012, 08:48:06 pm
You cannot set centre of a sprite, as there is no such function. You can implement your own function, or use the existing function - which is sf::Sprite::SetPosition - to align the centre of the sprite to the body's centre of mass.
Isn't it what setOrigin (http://www.sfml-dev.org/documentation/2.0/classsf_1_1Transformable.php#a56c67bd80aae8418d13fb96c034d25ec) is doing?
Using setPosition here is totally incorrect.
Title: Re: box2d
Post by: TheVirtualDragon on August 21, 2012, 09:28:48 pm
Good point, setOrigin is the SFML1.6 equivalent of SetCenter...

Note to self: Must read documentation before posting answers  :-\

Edit: No wait, there is a reason it was renamed. SetOrigin does not set the centre of the sprite - it is just the point around which all transformations will happen. So after calling setOrigin and passing the position of the body to it, you will still need to call setPosition - or otherwise the sprite's top left corner will be located at the centre of the body.
Title: Re: box2d
Post by: FRex on August 22, 2012, 02:58:41 am
1. It's good thing you made gravity positive, one less minus sign to write/forget/cause problems. Try not to listen too much to virtualdragon about that...  :)
2. 1/60 in your step call is integer division, it rounds to 0 so box2d thinks you want to do a time step equal to 0 seconds, that can't be good. ::) Change it to 1.f/60.f or 0.0166666667 and it'll work. Write .f after integer if you mean that it's a float that just happen to also be integer or things like that happen.
3. You should convert body position back into pixels in sprite.setPosition
4. You shouldn't tie your steps to framerate but I understand that's just a test here.
5. If you set origin of sprite to it's center then you CAN just do:
sprite.setPosition(bodyPos.x*M, bodyPos.y*M);
Title: Re: box2d
Post by: G. on August 22, 2012, 04:51:29 am
AFAIR you HAVE to set the origin of the sprite to its center, or else rotations will be wrong.
Title: Re: box2d
Post by: FRex on August 22, 2012, 05:12:14 am
It depends on what you're doing with that sprite, in a side view metroidvania style game most of the sprites never rotate.
Title: Re: box2d
Post by: TheVirtualDragon on August 22, 2012, 09:25:57 am
Sorry about that. I automatically presumed you flipped the y axis in sfml so dont listen to me about that. (That was probably because I am addicted to realistic physics... :-X)
Title: Re: box2d
Post by: Kubik on August 22, 2012, 11:00:22 am
So how much pixels in meter?
Title: Re: box2d
Post by: FRex on August 22, 2012, 11:12:37 am
That's your choice to make. Depends on the game/billion other things. Just try to follow everything recommended in box2d user manual.
Title: Re: box2d
Post by: Kubik on August 22, 2012, 11:17:04 am
Thanks :)
Title: Re: box2d
Post by: TheVirtualDragon on August 22, 2012, 11:18:29 am
You have to define the metre your self : there is no definition which I am aware of...

For example, if you have a sprite of a ten year old which is 64x64 pixels, then you can say that 1 metre is 50 pixels. This will mean that your sprite is 1.28m tall.
To implement this, you have to scale your box2d measurements up by 50 and your sfml measurements down by 50. Alternatively, you could set up a view, like this:

sf::View gameView ( sf::FloatRect (0, 0, 800 / 50, 600 / 50) );
 

Hope that helped.