You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SFML国际象棋游戏中MouseMoved事件后sf::Sprite无法拖拽移动

问题分析与解决方案

你的棋子拖拽功能失效的核心原因是:每次主循环渲染时,你都会重新强制设置所有棋子的初始位置,覆盖了拖拽过程中修改的位置。

看你代码中的这段逻辑,它在每次窗口绘制前都会执行:

for (int i = 0; i < 8; i++)
{
    for (int j = 0; j < 4; j++)
    {
      if (j<2)
      {
        sprites[j][i].setPosition(sf::Vector2f(100*(i+1)-50,100*(j+1)-50));
      }else{
        sprites[j][i].setPosition(sf::Vector2f(100*(i+1)-50,100*(j+5)-50));
      }
    }
}

这段代码会把所有棋子硬放回初始的棋盘格子位置,导致你在MouseMoved事件中修改的棋子位置瞬间被覆盖,所以看起来棋子完全不动。


修复步骤

  1. 将棋子初始位置的设置移到主循环之外,只在程序启动时执行一次,而不是每次渲染都重置:
    把上述位置设置代码从主循环内的绘制部分,移到初始化sprites数组之后、主循环之前。

  2. 保留拖拽过程中棋子的位置修改,不需要在渲染时重置任何棋子的位置(除非是放下棋子时的逻辑)。


修改后的完整代码示例

#include <SFML/Graphics.hpp>
#include <vector>
#include <string>
#include<iostream>
#include <unistd.h>

int main() {
// Create a window
sf::RenderWindow window(sf::VideoMode(800, 800), "Chess by devtony");
sf::RectangleShape board[8][8];
sf::Color blck(128,128,128);
sf::Color wth(255,204,204);

    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            board[i][j].setPosition(i*100,j*100);
            board[i][j].setSize(sf::Vector2f(100, 100));
            board[i][j].setFillColor((i + j) % 2 == 0 ? wth : blck);
        }
    }

sf::Texture pieces[4][8];
for (int i = 0; i < 8; i++)
{
    if (!pieces[1][i].loadFromFile("assets/w_pawn.png")) {
        std::cout << "Error loading image!" << std::endl;
        return EXIT_FAILURE;
    }
}

//rooks
for (int i = 0; i < 8; i++)
{
    if (!pieces[2][i].loadFromFile("assets/b_pawn.png")) {
        std::cout << "Error loading image!" << std::endl;
        return EXIT_FAILURE;
    }
}
if (!pieces[0][0].loadFromFile("assets/w_rook.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}
if (!pieces[0][7].loadFromFile("assets/w_rook.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}
if (!pieces[3][0].loadFromFile("assets/b_rook.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}
if (!pieces[3][7].loadFromFile("assets/b_rook.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}

//bishop
if (!pieces[0][2].loadFromFile("assets/w_bishop.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}
if (!pieces[0][5].loadFromFile("assets/w_bishop.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}
if (!pieces[3][2].loadFromFile("assets/b_bishop.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}
if (!pieces[3][5].loadFromFile("assets/b_bishop.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}

//horse
if (!pieces[0][1].loadFromFile("assets/w_knight.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}
if (!pieces[0][6].loadFromFile("assets/w_knight.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}
if (!pieces[3][1].loadFromFile("assets/b_knight.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}
if (!pieces[3][6].loadFromFile("assets/b_knight.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}

//queen & king
if (!pieces[0][4].loadFromFile("assets/w_queen.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}
if (!pieces[0][3].loadFromFile("assets/w_king.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}
if (!pieces[3][3].loadFromFile("assets/b_queen.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}
if (!pieces[3][4].loadFromFile("assets/b_king.png")) {
    std::cout << "Error loading image!" << std::endl;
    return EXIT_FAILURE;
}

// Create a sprite
sf::Sprite sprites[4][8];
for (int i = 0; i < 4; i++)
{
    for (int j = 0; j < 8; j++)
    {
        sprites[i][j].setTexture(pieces[i][j]);
        sprites[i][j].setScale(0.5,0.5);
        sprites[i][j].setOrigin(50,50);
    }
}

// --- 初始化棋子初始位置,只执行一次 ---
for (int i = 0; i < 8; i++)
{
    for (int j = 0; j < 4; j++)
    {
        if (j<2)
        {
            sprites[j][i].setPosition(sf::Vector2f(100*(i+1)-50,100*(j+1)-50));
        }else{
            sprites[j][i].setPosition(sf::Vector2f(100*(i+1)-50,100*(j+5)-50));
        }
    }
}

// Flag to check if a piece is selected
bool isPieceSelected = false;
sf::Sprite* selectedPiece = nullptr;
sf::Vector2f clickOffset;

// Main loop
while (window.isOpen()) {
    sf::Event event;
    while (window.pollEvent(event)) {
        if (event.type == sf::Event::Closed) {
            window.close();
        }
        if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) {
            for (int i = 0; i < 4; i++) {
                for (int j = 0; j < 8; j++) {
                    if (sprites[i][j].getGlobalBounds().contains(window.mapPixelToCoords(sf::Mouse::getPosition(window)))) {
                        isPieceSelected = true;
                        selectedPiece = &sprites[i][j];
                        clickOffset = window.mapPixelToCoords(sf::Mouse::getPosition(window)) - selectedPiece->getPosition();
                        break;
                    }
                }
                if (isPieceSelected) break;
            }
        }
        else if (event.type == sf::Event::MouseMoved && isPieceSelected) {
            sf::Vector2f newPosition = window.mapPixelToCoords(sf::Mouse::getPosition(window)) - clickOffset;
            std::cout << "New Position: " << newPosition.x << ", " << newPosition.y << std::endl;
            selectedPiece->setPosition(newPosition);
        }
        else if (event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left) {
            isPieceSelected = false;
        }
    }

    // Clear window
    window.clear();
    
    // Draw board
    for (int i = 0; i < 8; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            window.draw(board[i][j]);
        }
    }
    
    // Draw pieces (不再重置位置,直接绘制当前状态)
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            window.draw(sprites[i][j]);
        }
    }
    
    // Display window contents
    window.display();
}

return 0;
}

额外优化建议:

  • 可以给选中的棋子设置一个层级(比如绘制时最后绘制选中的棋子),让它显示在其他棋子上方,提升交互体验。
  • 鼠标释放时可以添加逻辑,判断棋子是否落在合法的棋盘格子上,再决定是否保留位置或放回原位。

内容的提问来源于stack exchange,提问作者Tony Prajapati

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 09:35:53