I’m working on a chess game using SFML in C++, and I’ve encountered an issue with dragging and dropping sprites. I’ve implemented a feature to allow players to move chess pieces by clicking and dragging them across the board. However, the sprites don’t move with the mouse drag as expected.
The sprites are correctly detected when clicked, and the isPieceSelected flag is set to true. The clickOffset is calculated to maintain the correct position relative to the mouse cursor. However, when I try to drag a sprite, it doesn’t follow the mouse. The window is focused, and there are no framerate limits set that could affect the responsiveness.
I’ve tried using both setPosition and move methods for updating the sprite’s position, but neither has resolved the issue. The sprites are not moving at all, even though there are no errors, and the program compiles successfully.
#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
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;
}
//king
// 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);
}
}
// 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.x,newPosition.y);
}
else if (event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left) {
isPieceSelected = false;
}
}
// Clear window
window.clear();
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
window.draw(board[i][j]);
}
}
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));
}
}
}
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 8; j++)
{
window.draw(sprites[i][j]);
}
}
// Draw the sprite
// Display window contents
window.display();
}
return 0;
}
Your issue is that you are setting the positions of the chess pieces in their starting spots each iteration of the window loop. This happens in the loop here:
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));
}
}
}
This can be easily solved by introducing an initializer function that takes your sprites matrix and sets their original positions only once.
Create a function like this:
void setPiecesInStartingPosition(sf::Sprite(&sprites)[4][8])
and move your initializing code in the function, namely:
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));
}
}
}
Finally, make sure to call it only once, somewhere before you start your while loops. Perhaps right after you create your sprite matrix is a good idea.
Also, I would suggest removing the break statements and move the boolean check above the for loops
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;
So something like this:
if (!isPieceSelected) {
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;
}
}
}
}