Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
175 views
in Technique[技术] by (71.8m points)

c++ - Dragging a sprite in sfml

I'm doing an assignment at the moment and for it, I need to drag chess pieces on a board, the problem is that I have no idea how to make this work for more than one piece. I can compute the mouse position and I've been able to move just one piece but the code only works for that single piece. My question is how do I click on a piece, have it become the active piece until I release the mouse button. This won't work if I only check if it intersects with one piece because it isn't dynamic then. My code is a mess from me trying different things but here are some of the relevant parts.

Here is the setup for the sprites:

// load the texture and setup the sprite for the logo
void Game::setupSprite()
{
    sf::IntRect pieceRect(m_wking.getPosition().x, m_wking.getPosition().y, 128, 128);

    if (!m_boardTexture.loadFromFile("ASSETS\IMAGES\board.png"))
    {
        // simple error message if previous call fails
        std::cout << "problem loading board" << std::endl;
    }
    m_boardSprite.setTexture(m_boardTexture);
    m_boardSprite.setPosition(0.0f, 0.0f);


    //pieces
    if (!m_wkingTex.loadFromFile("ASSETS\IMAGES\PIECES\wking.png"))
    {
        // simple error message if previous call fails
        std::cout << "problem loading piece" << std::endl;
    }
    m_wking.setTexture(m_wkingTex);
    m_wking.setPosition(0.0f, 0.0f);
    sf::IntRect wkingRect(pieceRect);
}

If the mouse button is down

void Game::processMouseButtonDown(sf::Event t_event)
{
    if (sf::Mouse::isButtonPressed(sf::Mouse::Button::Left)) {
        std::cout << "Mouse button pressed
";
        sf::Vector2f mouse = m_window.mapPixelToCoords(sf::Mouse::getPosition(m_window));
        if (isSpriteClicked() && !m_holdingPiece) {

            m_holdingPiece = true;
        }
    }
}

Mouse button is up:

void Game::processMouseButtonUp(sf::Event t_event)
{
    m_holdingPiece = false;
    sf::IntRect pieceRect(m_wking.getPosition().x, m_wking.getPosition().y, 128, 128);
    m_wking.setTextureRect(pieceRect);
}

If the sprite is clicked

bool Game::isSpriteClicked()
{
    sf::Vector2f mouse = m_window.mapPixelToCoords(sf::Mouse::getPosition(m_window));
    sf::FloatRect bounds(mouse.x, mouse.y, 1.0f, 1.0f);
    if (bounds.intersects(wkingRect.I dont know what Im doing)) {

        std::cout << "King has Been clicked!
";
        return true;
    }
    else {
        return false;
    }
}

And finally to move the sprite:

void Game::move()
{
    if (m_holdingPiece) {
        sf::Vector2f mouse = m_window.mapPixelToCoords(sf::Mouse::getPosition(m_window));
        m_wking.setPosition(mouse);
    }
}

Sorry if that seems like a lot of code, but I feel like it was all relevant to the problem.

question from:https://stackoverflow.com/questions/65644289/dragging-a-sprite-in-sfml

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Problem:

You have hardcoded all your variables so even if you create a list and iterate over it to run Game::move() it will move all the pieces instead of only one because the variable m_holdingPiece is the same for all pieces.

Solution:

You should use a more OOP aproach creating a class for the chess pieces while the Game class should probably just control when the game starts, when it ends and check whether moves are legal or not. Explaning all that would be too broad Stack Overflow and it's part of the work you must do, so I will just let an example of how a basic chessPiece class would be to make pieces dragabble.

Example:

Here is an example of how you can make a group of pieces draggable.

#include <SFML/Graphics.hpp>
#include <string>

class chessPiece: public sf::Drawable, public sf::Transformable
{
private:
    sf::RenderWindow& window;
    sf::Texture texture;
    sf::Sprite sprite;
    bool moving;
public:
    chessPiece(sf::RenderWindow& windowRef, const std::string& fileName): window(windowRef)
    {
        if(!texture.loadFromFile(fileName))
            exit(0);
        this->sprite.setTexture(this->texture);
        this->moving = false;
        this->sprite.setScale(128/this->sprite.getGlobalBounds().width,128/this->sprite.getGlobalBounds().height);
    }
    chessPiece(chessPiece&& rval): window(rval.window)
    {
        this->texture = std::move(rval.texture);
        this->sprite.setTexture(this->texture);
        this->sprite.setScale(rval.sprite.getScale());
        this->moving = std::move(rval.moving);
    }
    chessPiece(const chessPiece& lval): window(lval.window)
    {
        this->texture = lval.texture;
        this->sprite.setTexture(this->texture);
        this->sprite.setScale(lval.sprite.getScale());
        this->moving = lval.moving;
    }
    void draw(sf::RenderTarget& target, sf::RenderStates states) const
    {
        states.transform *= this->getTransform();
        target.draw(this->sprite,states);
    }
    void move(bool& movingAPiece)
    {
        sf::Vector2f mousePosition = window.mapPixelToCoords(sf::Mouse::getPosition(window));
        if(this->moving)
        {
            this->setPosition(mousePosition.x - this->sprite.getGlobalBounds().width/2,mousePosition.y - this->sprite.getGlobalBounds().height/2);
            if(!sf::Mouse::isButtonPressed(sf::Mouse::Button::Left))
            {
                this->moving = false;
                movingAPiece = false;
            }
        }
        else
        {
            if(sf::Mouse::isButtonPressed(sf::Mouse::Button::Left) && mousePosition.x > this->getPosition().x &&
               mousePosition.y > this->getPosition().y && mousePosition.x < this->getPosition().x + this->sprite.getGlobalBounds().width &&
               mousePosition.y < this->getPosition().y + this->sprite.getGlobalBounds().height && !movingAPiece)
            {
                this->moving = true;
                movingAPiece = true;
            }
        }
    }
};

int main()
{
    sf::RenderWindow window(sf::VideoMode(1000,500),"Window");
    std::vector<chessPiece> pieces = {chessPiece(window,"white-king.png"),chessPiece(window,"white-pawn.png")};
    pieces[0].setPosition(400,400);
    bool movingAPiece = false;
    while(true)
    {
        sf::Event event;
        if(window.pollEvent(event))
            if(event.type == sf::Event::Closed)
                window.close();
        for(unsigned int i = 0; i < pieces.size(); i++)
            pieces[i].move(movingAPiece);
        window.clear();
        for(unsigned int i = 0; i < pieces.size(); i++)
            window.draw(pieces[i]);
        window.display();
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...