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事件中修改的棋子位置瞬间被覆盖,所以看起来棋子完全不动。
修复步骤
将棋子初始位置的设置移到主循环之外,只在程序启动时执行一次,而不是每次渲染都重置:
把上述位置设置代码从主循环内的绘制部分,移到初始化sprites数组之后、主循环之前。保留拖拽过程中棋子的位置修改,不需要在渲染时重置任何棋子的位置(除非是放下棋子时的逻辑)。
修改后的完整代码示例
#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
相关产品推荐
相关产品推荐

