0
\$\begingroup\$

I trying to make a card game using SFML. I want to move the card relative to the position the player selects on the card. I managed to check if the card is pressed. However, when I click and drag, the top-left (the origin) of the card is immediately moved to where the mouse is. I tried to set the origin, in the process_events function, to 'event.mouseButton' (both x and y) each time the card is pressed but it moves to the top-left corner of the screen. I spent a lot of time on this. I hope you guys will help me out.

const int card_width = 79;
const int card_height = 123;

Game::Game()
: window(sf::VideoMode(1024, 800), "SFML")
, frame_rate(sf::seconds(1.f / 60.f))
, card(card_sheet, sf::IntRect(0, 0, card_width, card_height))
// 'card' is an sf::Sprite object pointing to an sf::Texture object that holds the sprite sheet. 
, selected(false)
{
    card.setPosition(500.f, 400.f);
    card.setOrigin(card_width / 2, card_height / 2);
    // I tried to set the origin to the center of the card.
    // Still doesn't look nice.
}

void Game::process_events()
{
    sf::Event event;
    while (window.pollEvent(event))
    {
        switch (event.type)
        {
            case sf::Event::Closed:
                window.close();
            break;
            case sf::Event::MouseButtonPressed:
                if (event.mouseButton.button == sf::Mouse::Left)
                    if (card.getGlobalBounds().
                                   contains(sf::Mouse::getPosition(window).x,
                                            sf::Mouse::getPosition(window).y))
                    {
                        // the problem is here
                        card.setOrigin(event.mouseButton.x, event.mouseButton.y);
                        selected = true;
                    }

            break;
            case sf::Event::MouseMoved:

                if (selected)
                {
                    // stuff might need to be added here too
                    card.setPosition(sf::Mouse::getPosition(window).x, sf::Mouse::getPosition(window).y);
                }
            break;
            case sf::Event::MouseButtonReleased:
                selected = false;
            break;
            default: break;
        }
    }
}

void Game::update(sf::Time dt)
{
}

void Game::render()
{
    window.clear();
    window.draw(card);
    window.display();
}

void Game::run()
{
    sf::Clock clock;
    while(window.isOpen())
    {
        sf::Time dt = clock.restart();
        process_events();
        update(dt);
        render();
    }
}
\$\endgroup\$
1
\$\begingroup\$

When you set the origin you have to take into account the position of the card and its previous origin.

card.setOrigin(event.mouseButton.x - (card.getPosition().x - card.getOrigin().x),
               event.mouseButton.y - (card.getPosition().y - card.getOrigin().y));

I don't really know how to explain, I will try with a drawing.

Your card is the red rectangle: its position is the dark green arrow and its origin is the light green arrow. The position of the click is the blue arrow.

So, when you subtract the light green arrow to the dark green arrow you get the purple arrow. So the purple arrow is card.position - card.origin.

Then you subtract that purple arrow to the blue arrow, and you get the pink arrow mouse.position - (card.position - card.origin). And the pink arrow in the new origin of the card, it is at the position where the player clicked with coordinates that are local to the card. i.e. on a card that is at position (0,0) and origin (0,0).

enter image description here

I hope that makes sense.

\$\endgroup\$
  • \$\begingroup\$ I tried to do that but it doesn't work, the card jumps around. Let me rephrase what I want: I want the origin of the card to be wherever the user clicks on the card (not necessarily on center ). When he moves the card, it moves according to that. Just like a normal card game. \$\endgroup\$ – Aaron Mar 21 '15 at 21:09
  • \$\begingroup\$ I misunderstood your question, now I get it! I edited my answer. \$\endgroup\$ – Heckel Mar 21 '15 at 22:06
  • \$\begingroup\$ I read your edit. Nice, you kind of solved it. Still jumps to position and comes back to relative to the mouse. Maybe the other problem is in the setPosition. I'll try myself. \$\endgroup\$ – Aaron Mar 21 '15 at 22:07
  • \$\begingroup\$ It's probably because you don't get a "MouseButtonPressed" and a "MouseMoved" at the same time. You should try to add card.setPosition after card.SetOrigin. \$\endgroup\$ – Heckel Mar 21 '15 at 22:10
  • \$\begingroup\$ Awesome explanation! Worked perfectly! Thanks man. \$\endgroup\$ – Aaron Mar 21 '15 at 22:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.