通过函数移动QGraphicsPixmapItem



我正在用Qt创建一个国际象棋游戏,现在我要添加AI来与计算机对抗,但我有一个大问题。。。我使用mouseReleaseEvent()函数通过拖放来移动工件,所以现在我不知道没有它如何移动它们。当然,我必须创建一个函数来获取移动工件的坐标,但如何使其移动?我想我需要向你解释更多关于游戏的信息,所以这里有一些重要的代码可以让你了解它是如何工作的:

件.h

class Piece : public QGraphicsPixmapItem
{
public:
Piece(QGraphicsItem *parent = nullptr);
void setPieceScene(QGraphicsScene *graphicsScene) { pieceScene = graphicsScene; }
QGraphicsScene *getPieceScene() { return pieceScene; }
void setPieceName(QString pieceName) { name = pieceName; }
QString getPieceName() { return name; }
void setPrevPos(QPointF pos) { prevPos = pos; }
QPointF getPrevPos() { return prevPos; }
bool leftStart = false;      
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
private:
QString name;
QGraphicsScene *pieceScene;
QPointF prevPos;
};

在MainWindow.cpp中,当我开始游戏时,我会设置碎片

void MainWindow::start()
{
scene.setSceneRect(-400, -250, 1024, 768);
Piece* pieces = new Piece[32];
ChessBoard::setBoard(scene, pieces);
}

在ChessBoard.cpp中,我在场景中绘制棋盘,并在上面添加棋子

void ChessBoard::setBoard(QGraphicsScene &scene, Piece piece[])
{
setSquares(scene); //just drawing the squares by adding QGraphicsRectItem

//...
piece[8].setPixmap(QPixmap(":/images/rook_w.svg").scaled(80, 80));
piece[8].setPos(-200, 360);
piece[8].setPieceName("W_Rook");
scene.addItem(&piece[8]);
// and so on for the other pieces
}

最后在Piece.cpp中,我通过拖放来移动它们

void Piece::mousePressEvent(QGraphicsSceneMouseEvent *event)
{

Piece::setPrevPos(Piece::pos()); 
}
void Piece::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QPointF lastPoint = mapToScene(event->lastPos());
Piece::setPos(lastPoint.x() - 40, lastPoint.y() - 40);
}
void Piece::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Game* game = Game::getInstance();
game->setTurn();
QList<QGraphicsItem*> colliders = Piece::collidingItems();
int prevRow, prevCol, nextRow, nextCol;
//...other checks for the capture before this, but it's not important
if (colliders.length() == 1) //1 collider means it's a square
{
if ((this->name == "W_Pawn" && game->turn=="white") || (this->name == "B_Pawn" && game->turn=="black"))
{

if (Pawn::pawnMove(this, colliders[0], defaultBoardState))
//here I check if the move is valide, then the drop is accepted
//...same thing for the other pieces
}
}
else 
{
this->setPos(this->prevPos);
}
}

defaultBoardState是一个简单的全局int矩阵[8][8],包含片段的值,我会在移动完成后更新它。因此,我们现在面临的问题是:在Game.cpp中,我运行AI,假设它决定执行

void Game::run()
{
defaultBoardState[3][4] = -1;
defaultBoardState[1][4] = 0;

emit aiMoved();

}

信号连接到应该移动该片段的MainWindow函数(我在这里写了函数,因为场景是MainWindow类中的QGraphicsScene变量,我可以在这里轻松访问它(

connect(game, SIGNAL(aiMoved()), this, SLOT(aiMove()));
void MainWindow::aiMove()
{

//here I don't know how to make it move
}

我想让这些片段成为全局的,这样我就可以在这个函数中访问它们,并在那个位置上做一些类似piece[1].setPos()的事情,但我不能让QGraphicsPixmapItem成为全局的。我如何创建一个只知道要移动的工件和目的地位置就移动工件的函数?

您需要保留指向MainWindow中各部分的指针。类似于:

class MainWindow : public (whatever, most likely should be QWidget not QMainWindow) {
Piece *pieces[8*4] = {}; // so they are null be default
...
};
void MainWindow::start()
{
scene.setSceneRect(-400, -250, 1024, 768);
for (auto *& piece: m_pieces)
piece = new Piece;
ChessBoard::setBoard(scene, m_pieces);
}

此外:不要使用全局变量。它们是不必要的,它们是有问题的,并且它们隐藏了程序中模块之间的耦合。你需要明确地传递东西,因为这会让你真正思考什么去了哪里,你必须做一些设计工作,而不是让所有东西都在任何地方可用。

很难对这样的代码进行推理这就好像你会把车停在加油站,把房子的钥匙交给他们,以防他们想问你问题不,如果他们想问,他们必须通过一个定义良好的界面:他们给你打电话、发短信、发电子邮件,或者发送信鸽。无论是什么,都需要有意识地选择。你必须考虑并做出决定。

最新更新