Qt小遊戲開發:連連看
阿新 • • 發佈:2019-02-18
繼續更新~ 原來csdn部落格用底部的批量匯入圖片就不會失真
預覽
步驟
專案結構
包括:遊戲邏輯類,介面類,資源
1 定義遊戲資料結構
一些狀態,和結構體// ------------ 全域性變數 ------------ // // 最大行和列數 const int MAX_ROW = 15; const int MAX_COL = 20; // 遊戲可玩圖片數量 const int MAX_ICON = 25; // 遊戲狀態 enum GameStatus { PLAYING, PAUSE, WIN, OVER }; // 遊戲難度,不同的方塊數 const int kBasicNum = MAX_ROW * MAX_COL * 0.3; const int kMediumNum = MAX_ROW * MAX_COL * 0.7; const int kHardNum = MAX_ROW * MAX_COL; enum GameLevel { BASIC, MEDIUM, HARD }; // 用於繪製線段的連線點(其實應該統一用這個結構體的,程式碼有待優化) struct PaintPoint { PaintPoint(int _x, int _y) : x(_x), y (_y) {} int x; int y; }; // -------------------------------- //
2 建立遊戲邏輯類
3 遊戲邏輯class GameModel { public: GameModel(); virtual ~GameModel(); public: void startGame(); // 開始遊戲 void startGame(GameLevel level); int *getGameMap(); // 獲得地圖 GameStatus checkGameStatus(); // 判斷獲得遊戲狀態,是否輸贏 bool linkTwoTiles(int srcX, int srcY, int dstX,int dstY); // 連線起點和終點方塊,連線是否成功 bool isFrozen(); // 判斷是否已經成為了僵局 bool isWin(); // 檢查遊戲是否結束 int *getHint(); // 獲得提示 std::vector<PaintPoint> paintPoints; // 用於繪製的點 // 遊戲狀態和難度 GameStatus gameStatus; GameLevel gameLevel; private: // 遊戲地圖,儲存方塊,0表示消失,1-其他數字表示圖片標號 int *gameMap; // 遊戲提示,儲存2個點 int *hintArray; // 判斷起點到終點的方塊是否可以連線消除 bool isCanLink(int srcX, int srcY, int dstX, int dstY); bool canLinkDirectly(int srcX, int srcY, int dstX, int dstY); bool canLinkWithOneCorner(int srcX, int srcY, int dstX, int dstY); bool canLinkWithTwoCorner(int srcX, int srcY, int dstX, int dstY); // 提示模式還是連線模式判斷 bool isFrozenMode; };
(1)開始遊戲初始化
void GameModel::startGame(GameLevel level) { // 用C的方式初始化陣列,懷舊一下~ gameMap = (int *)malloc(sizeof(int) * MAX_ROW * MAX_COL); memset(gameMap, 0, MAX_ROW * MAX_COL); for (int i = 0; i < MAX_ROW * MAX_COL; i++) // 必須這樣賦初值,memset容易出問題 gameMap[i] = 0; hintArray = (int *)malloc(sizeof(int) * 4); memset(hintArray, 0, 4); for (int i = 0; i < 4; i++) hintArray[i] = -1; gameStatus = PLAYING; gameLevel = level; int gameLevelNum; switch (gameLevel) { case BASIC: gameLevelNum = kBasicNum; break; case MEDIUM: gameLevelNum = kMediumNum; break; case HARD: gameLevelNum = kHardNum; } // 填充方塊標號 int iconID = 0; for(int i = 0; i < gameLevelNum; i += 2) { // 每次填充連著的兩個,圖片用盡了就迴圈 gameMap[i] = iconID % MAX_ICON + 1; gameMap[i + 1] = iconID % MAX_ICON + 1; iconID++; } // 打亂方塊 srand((unsigned)time(0)); for(int i = 0; i < MAX_ROW * MAX_COL; i++) { int randomID = rand() % (MAX_ROW * MAX_COL); std::swap(gameMap[i], gameMap[randomID]); } // 初始化判斷模式 isFrozenMode = false; // 初始化繪製點 paintPoints.clear(); }
- 隨機佈置方塊
- 打亂方塊
(3)連線方塊判定
// 最重要的判斷連線演算法
bool GameModel::canLinkDirectly(int srcX, int srcY, int dstX, int dstY)
{
// 豎線
if (srcX == dstX)
{
if (srcY > dstY)
std::swap(srcY, dstY);
for (int y = srcY + 1; y < dstY; y++)
if (gameMap[MAX_COL * y + srcX])
return false;
if (!isFrozenMode) // 這裡有坑,注意了
{
// 記錄點和路線
PaintPoint p1(srcX, srcY), p2(dstX, dstY);
paintPoints.clear();
paintPoints.push_back(p1);
paintPoints.push_back(p2);
}
return true;
}
// 橫線
if (srcY == dstY)
{
if (srcX > dstX)
std::swap(srcX, dstX);
for (int x = srcX + 1; x < dstX; x++)
if (gameMap[MAX_COL * srcY + x])
return false;
if (!isFrozenMode)
{
PaintPoint p1(srcX, srcY), p2(dstX, dstY);
paintPoints.clear();
paintPoints.push_back(p1);
paintPoints.push_back(p2);
}
return true;
}
return false;
}
bool GameModel::canLinkWithOneCorner(int srcX, int srcY, int dstX, int dstY)
{
if (srcX > dstX)
{
// 統一化,方便後續處理
std::swap(srcX, dstX);
std::swap(srcY, dstY);
}
// 先確定拐點,再確定直連線路,2種情況,4個點,每種情況逐個試,所以多個if順序執行
if (dstY > srcY)
{
if (gameMap[srcY * MAX_COL + dstX] == 0)
{
// 右上角
if (canLinkDirectly(srcX, srcY, dstX, srcY) && canLinkDirectly(dstX, srcY, dstX, dstY))
{
// 只有連線模式才記錄點
if (!isFrozenMode)
{
PaintPoint p1(srcX, srcY), p2(dstX, srcY), p3(dstX, dstY);
paintPoints.clear();
paintPoints.push_back(p1);
paintPoints.push_back(p2);
paintPoints.push_back(p3);
}
return true;
}
}
if (gameMap[dstY * MAX_COL + srcX] == 0)
{
// 左下角
if (canLinkDirectly(srcX, srcY, srcX, dstY) && canLinkDirectly(srcX, dstY, dstX, dstY))
{
if (!isFrozenMode)
{
PaintPoint p1(srcX, srcY), p2(srcX, dstY), p3(dstX, dstY);
paintPoints.clear();
paintPoints.push_back(p1);
paintPoints.push_back(p2);
paintPoints.push_back(p3);
}
return true;
}
}
}
else
{
if (gameMap[dstY * MAX_COL + srcX] == 0)
{
// 左上角
if (canLinkDirectly(srcX, srcY, srcX, dstY) && canLinkDirectly(srcX, dstY, dstX, dstY))
{
if (!isFrozenMode)
{
PaintPoint p1(srcX, srcY), p2(srcX, dstY), p3(dstX, dstY);
paintPoints.clear();
paintPoints.push_back(p1);
paintPoints.push_back(p2);
paintPoints.push_back(p3);
}
return true;
}
}
if (gameMap[srcY * MAX_COL + dstX] == 0)
{
// 右下角
if (canLinkDirectly(srcX, srcY, dstX, srcY) && canLinkDirectly(dstX, srcY, dstX, dstY))
{
if (!isFrozenMode)
{
PaintPoint p1(srcX, srcY), p2(dstX, srcY), p3(dstX, dstY);
paintPoints.clear();
paintPoints.push_back(p1);
paintPoints.push_back(p2);
paintPoints.push_back(p3);
}
return true;
}
}
}
return false;
}
bool GameModel::canLinkWithTwoCorner(int srcX, int srcY, int dstX, int dstY)
{
if (srcX > dstX)
{
// 統一化,方便後續處理
std::swap(srcX, dstX);
std::swap(srcY, dstY);
}
// 兩種情況,橫向垂線和豎向垂線,以src點作為基準遍歷,雙摺線由直線和一個拐點的折線構成
// 常規情況
for (int y = 0; y < MAX_ROW; y++)
{
if (y != srcY && y != dstY)
{
if (gameMap[y * MAX_COL + srcX] == 0
&& canLinkDirectly(srcX, srcY, srcX, y)
&& canLinkWithOneCorner(srcX, y, dstX, dstY))
{
if (!isFrozenMode)
{
PaintPoint p1(srcX, srcY), p2(srcX, y), p3(dstX, y), p4(dstX, dstY);
paintPoints.clear();
paintPoints.push_back(p1);
paintPoints.push_back(p2);
paintPoints.push_back(p3);
paintPoints.push_back(p4);
}
return true;
}
}
}
for (int x = 0; x < MAX_COL; x++)
{
if (x != srcX && x != dstX)
{
if (gameMap[srcY * MAX_COL + x] == 0
&& canLinkDirectly(srcX, srcY, x, srcY)
&& canLinkWithOneCorner(x, srcY, dstX, dstY))
{
if (!isFrozenMode)
{
PaintPoint p1(srcX, srcY), p2(x, srcY), p3(x, dstY), p4(dstX, dstY);
paintPoints.clear();
paintPoints.push_back(p1);
paintPoints.push_back(p2);
paintPoints.push_back(p3);
paintPoints.push_back(p4);
}
return true;
}
}
}
// 邊緣情況,從外邊緣連線,注意方塊不一定在邊緣,(分開寫便於記錄路徑)
if ((srcX == 0 || gameMap[srcY * MAX_COL + 0] == 0 && canLinkDirectly(srcX, srcY, 0, srcY))
&& (dstX == 0 || gameMap[dstY * MAX_COL + 0] == 0 && canLinkDirectly(0, dstY, dstX, dstY)))
{
// 左
if (!isFrozenMode)
{
PaintPoint p1(srcX, srcY), p2(-1, srcY), p3(-1, dstY), p4(dstX, dstY);
paintPoints.clear();
paintPoints.push_back(p1);
paintPoints.push_back(p2);
paintPoints.push_back(p3);
paintPoints.push_back(p4);
}
return true;
}
if ((srcX == MAX_COL - 1 || gameMap[srcY * MAX_COL + MAX_COL - 1] == 0 && canLinkDirectly(srcX, srcY, MAX_COL - 1, srcY))
&& (dstX == MAX_COL - 1 || gameMap[dstY * MAX_COL + MAX_COL - 1] == 0 && canLinkDirectly(MAX_COL - 1, dstY, dstX, dstY)))
{
// 右
if (!isFrozenMode)
{
PaintPoint p1(srcX, srcY), p2(MAX_COL, srcY), p3(MAX_COL, dstY), p4(dstX, dstY);
paintPoints.clear();
paintPoints.push_back(p1);
paintPoints.push_back(p2);
paintPoints.push_back(p3);
paintPoints.push_back(p4);
}
return true;
}
if ((srcY == 0 || gameMap[srcX] == 0 && canLinkDirectly(srcX, srcY, srcX, 0))
&& (dstY == 0 || gameMap[dstX] == 0 && canLinkDirectly(dstX, 0, dstX, dstY)))
{
// 上
if (!isFrozenMode)
{
PaintPoint p1(srcX, srcY), p2(srcX, -1), p3(dstX, -1), p4(dstX, dstY);
paintPoints.clear();
paintPoints.push_back(p1);
paintPoints.push_back(p2);
paintPoints.push_back(p3);
paintPoints.push_back(p4);
}
return true;
}
if ((srcY == MAX_ROW - 1 || gameMap[(MAX_ROW - 1) * MAX_COL + srcX] == 0 && canLinkDirectly(srcX, srcY, srcX, MAX_ROW - 1))
&& (dstY == MAX_ROW - 1 || gameMap[(MAX_ROW - 1) * MAX_COL + dstX] == 0 && canLinkDirectly(dstX, MAX_ROW - 1, dstX, dstY)))
{
// 下
if (!isFrozenMode)
{
PaintPoint p1(srcX, srcY), p2(srcX, MAX_ROW), p3(dstX, MAX_ROW), p4(dstX, dstY);
paintPoints.clear();
paintPoints.push_back(p1);
paintPoints.push_back(p2);
paintPoints.push_back(p3);
paintPoints.push_back(p4);
}
return true;
}
return false;
}
bool GameModel::isCanLink(int srcX, int srcY, int dstX, int dstY)
{
// 首先判斷點選的兩個方塊不是同一個不是空,且方塊相同
// 判斷方塊是否可以連,可用於實際的連線消除和提示消除
// x表示橫向索引,y表示縱向索引,從0開始
// 分3種情況往下找,每一種都可以用前面簡單情況組合找到一種情況可以連通就返回true,並選用這種連線情況
if (gameMap[srcY * MAX_COL + srcX] == 0 || gameMap[dstY * MAX_COL + dstX] == 0)
return false;
if (srcX == dstX && srcY == dstY)
return false;
if(gameMap[MAX_COL * srcY + srcX] != gameMap[MAX_COL * dstY + dstX])
return false;
// 情況1:橫向或者豎向可以直線連通
if (canLinkDirectly(srcX, srcY, dstX, dstY))
return true;
// 情況2:一次拐彎可以連通
if (canLinkWithOneCorner(srcX, srcY, dstX, dstY))
return true;
// 情況3:兩次拐彎可以連通
if (canLinkWithTwoCorner(srcX, srcY, dstX, dstY))
return true;
return false;
}
// 點選方塊進行連線操作
bool GameModel::linkTwoTiles(int srcX, int srcY, int dstX, int dstY)
{
// 成功連線就返回true否則false用於GUI裡面判斷
if(isCanLink(srcX, srcY, dstX, dstY))
{
// 值重置
gameMap[MAX_COL * srcY + srcX] = 0;
gameMap[MAX_COL * dstY + dstX] = 0;
return true;
}
return false;
}
示意圖:
方塊連線判定是最重要的演算法,主要分成直線連線、一個拐點折線、兩個拐點折線,三種連線情況進行討論,還要注意一些邊緣情況。
(4)判斷是否形成僵局
bool GameModel::isFrozen()
{
// 暴力法,所有方塊兩兩判斷是否可以連線
// 每次消除後做一次判斷
// 其實在這個過程中記錄提示
for (int i = 0; i < MAX_ROW * MAX_COL - 1; i++)
for( int j = i + 1; j < MAX_ROW * MAX_COL; j++)
{
int srcX = i % MAX_COL;
int srcY = i / MAX_COL;
int dstX = j % MAX_COL;
int dstY = j / MAX_COL;
// 只要能找到可以連線的就不為僵局
isFrozenMode = true;
if (isCanLink(srcX, srcY, dstX, dstY))
{
// 記錄第一個可以連線的hint
hintArray[0] = srcX;
hintArray[1] = srcY;
hintArray[2] = dstX;
hintArray[3] = dstY;
isFrozenMode = false;
return false;
}
}
isFrozenMode = false;
return true;
}
- 該方法略暴力,可以採用dfs進行剪枝
- 在搜尋過程中儲存用於連線的提示
(5)判斷輸贏
bool GameModel::isWin()
{
for (int i = 0; i < MAX_ROW * MAX_COL; i++)
{
if (gameMap[i])
return false;
}
gameStatus = WIN;
return true;
}
4 遊戲介面類
// 繼承自button,儲存座標值
struct IconButton : QPushButton
{
public:
IconButton(QWidget *parent = Q_NULLPTR) :
QPushButton(parent),
xID(-1),
yID(-1)
{
}
int xID; // x 座標
int yID; // y 座標
};
class MainGameWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainGameWindow(QWidget *parent = 0);
virtual ~MainGameWindow();
virtual bool eventFilter(QObject *watched, QEvent *event); // 事件過濾
private:
Ui::MainGameWindow *ui;
GameModel *game; // 遊戲模型
IconButton *imageButton[MAX_ROW * MAX_COL]; // 圖片button陣列
QTimer *gameTimer; // 遊戲計時器
IconButton *preIcon, *curIcon; // 記錄點選的icon
bool isLinking; // 維持一個連線狀態的標誌
QMediaPlayer *audioPlayer; // 音樂播放器
void initGame(GameLevel level); // 初始化遊戲
private slots:
void onIconButtonPressed(); // icon點選到響應
void gameTimerEvent(); // 遊戲計時回撥
void handleLinkEffect(); // 實現連線效果
void on_hintBtn_clicked(); // 提示按鈕
void on_robot_btn_clicked(); // 機器人自動刷
void createGameWithLevel(); // 選中難度開始
};
5 遊戲互動邏輯
(1)開始遊戲
void MainGameWindow::initGame(GameLevel level)
{
// 啟動遊戲
game = new GameModel;
game->startGame(level);
// 新增button
for(int i = 0; i < MAX_ROW * MAX_COL; i++)
{
imageButton[i] = new IconButton(this);
imageButton[i]->setGeometry(kLeftMargin + (i % MAX_COL) * kIconSize, kTopMargin + (i / MAX_COL) * kIconSize, kIconSize, kIconSize);
// 設定索引
imageButton[i]->xID = i % MAX_COL;
imageButton[i]->yID = i / MAX_COL;
imageButton[i]->show();
if (game->getGameMap()[i])
{
// 有方塊就設定圖片
QPixmap iconPix;
QString fileString;
fileString.sprintf(":/res/image/%d.png", game->getGameMap()[i]);
iconPix.load(fileString);
QIcon icon(iconPix);
imageButton[i]->setIcon(icon);
imageButton[i]->setIconSize(QSize(kIconSize, kIconSize));
// 新增按下的訊號槽
connect(imageButton[i], SIGNAL(pressed()), this, SLOT(onIconButtonPressed()));
}
else
imageButton[i]->hide();
}
// 進度條
ui->timeBar->setMaximum(kGameTimeTotal);
ui->timeBar->setMinimum(0);
ui->timeBar->setValue(kGameTimeTotal);
// 遊戲計時器
gameTimer = new QTimer(this);
connect(gameTimer, SIGNAL(timeout()), this, SLOT(gameTimerEvent()));
gameTimer->start(kGameTimerInterval);
// 連線狀態值
isLinking = false;
// 播放背景音樂(QMediaPlayer只能播放絕對路徑檔案),確保res檔案在程式執行檔案目錄裡而不是開發目錄
audioPlayer = new QMediaPlayer(this);
QString curDir = QCoreApplication::applicationDirPath(); // 這個api獲取路徑在不同系統下不一樣,mac 下需要擷取路徑
QStringList sections = curDir.split(QRegExp("[/]"));
QString musicPath;
for (int i = 0; i < sections.size() - 3; i++)
musicPath += sections[i] + "/";
audioPlayer->setMedia(QUrl::fromLocalFile(musicPath + "res/sound/backgrand.mp3"));
audioPlayer->play();
}
- 根據遊戲模型資料建立方塊地圖
- 初始化一些音訊和定時器
void MainGameWindow::onIconButtonPressed()
{
// 如果當前有方塊在連線,不能點選方塊
// 因為涉及到多線,可能還要維護佇列,有點複雜,就先這麼簡單處理一下
if (isLinking)
{
// 播放音效
QSound::play(":/res/sound/release.wav");
return;
}
// 記錄當前點選的icon
curIcon = dynamic_cast<IconButton *>(sender());
if(!preIcon)
{
// 播放音效
QSound::play(":/res/sound/select.wav");
// 如果單擊一個icon
curIcon->setStyleSheet(kIconClickedStyle);
preIcon = curIcon;
}
else
{
if(curIcon != preIcon)
{
// 如果不是同一個button就都標記,嘗試連線
curIcon->setStyleSheet(kIconClickedStyle);
if(game->linkTwoTiles(preIcon->xID, preIcon->yID, curIcon->xID, curIcon->yID))
{
// 鎖住當前狀態
isLinking = true;
// 播放音效
QSound::play(":/res/sound/pair.wav");
// 重繪
update();
// 延遲後實現連線效果
QTimer::singleShot(kLinkTimerDelay, this, SLOT(handleLinkEffect()));
// 每次檢查一下是否僵局
if (game->isFrozen())
QMessageBox::information(this, "oops", "dead game");
// 檢查是否勝利
if (game->isWin())
QMessageBox::information(this, "great", "you win");
int *hints = game->getHint();
}
else
{
// 播放音效
QSound::play(":/res/sound/release.wav");
// 消除失敗,恢復
preIcon->setStyleSheet(kIconReleasedStyle);
curIcon->setStyleSheet(kIconReleasedStyle);
// 指標置空,用於下次點選判斷
preIcon = NULL;
curIcon = NULL;
}
}
else if(curIcon == preIcon)
{
// 播放音效
QSound::play(":/res/sound/release.wav");
preIcon->setStyleSheet(kIconReleasedStyle);
curIcon->setStyleSheet(kIconReleasedStyle);
preIcon = NULL;
curIcon = NULL;
}
}
}
點選方塊,根據方塊索引進行遊戲邏輯的更新
(3)繪製連線線
bool MainGameWindow::eventFilter(QObject *watched, QEvent *event)
{
// 重繪時會呼叫,可以手動呼叫
if (event->type() == QEvent::Paint)
{
QPainter painter(ui->centralWidget);
QPen pen;
QColor color(rand() % 256, rand() % 256, rand() % 256);
pen.setColor(color);
pen.setWidth(5);
painter.setPen(pen);
QString str;
for (int i = 0; i < game->paintPoints.size(); i++)
{
PaintPoint p = game->paintPoints[i];
str += "x:" + QString::number(p.x) + "y:" + QString::number(p.y) + "->";
}
// qDebug() << str;
// 連線各點畫線(注,qt中用標磚vector的size好像有點問題,需要型別轉換,否則溢位)
for (int i = 0; i < int(game->paintPoints.size()) - 1; i++)
{
PaintPoint p1 = game->paintPoints[i];
PaintPoint p2 = game->paintPoints[i + 1];
// 拿到各button的座標,注意邊緣點座標
QPoint btn_pos1;
QPoint btn_pos2;
// p1
if (p1.x == -1)
{
btn_pos1 = imageButton[p1.y * MAX_COL + 0]->pos();
btn_pos1 = QPoint(btn_pos1.x() - kIconSize, btn_pos1.y());
}
else if (p1.x == MAX_COL)
{
btn_pos1 = imageButton[p1.y * MAX_COL + MAX_COL - 1]->pos();
btn_pos1 = QPoint(btn_pos1.x() + kIconSize, btn_pos1.y());
}
else if (p1.y == -1)
{
btn_pos1 = imageButton[0 + p1.x]->pos();
btn_pos1 = QPoint(btn_pos1.x(), btn_pos1.y() - kIconSize);
}
else if (p1.y == MAX_ROW)
{
btn_pos1 = imageButton[(MAX_ROW - 1) * MAX_COL + p1.x]->pos();
btn_pos1 = QPoint(btn_pos1.x(), btn_pos1.y() + kIconSize);
}
else
btn_pos1 = imageButton[p1.y * MAX_COL + p1.x]->pos();
// p2
if (p2.x == -1)
{
btn_pos2 = imageButton[p2.y * MAX_COL + 0]->pos();
btn_pos2 = QPoint(btn_pos2.x() - kIconSize, btn_pos2.y());
}
else if (p2.x == MAX_COL)
{
btn_pos2 = imageButton[p2.y * MAX_COL + MAX_COL - 1]->pos();
btn_pos2 = QPoint(btn_pos2.x() + kIconSize, btn_pos2.y());
}
else if (p2.y == -1)
{
btn_pos2 = imageButton[0 + p2.x]->pos();
btn_pos2 = QPoint(btn_pos2.x(), btn_pos2.y() - kIconSize);
}
else if (p2.y == MAX_ROW)
{
btn_pos2 = imageButton[(MAX_ROW - 1) * MAX_COL + p2.x]->pos();
btn_pos2 = QPoint(btn_pos2.x(), btn_pos2.y() + kIconSize);
}
else
btn_pos2 = imageButton[p2.y * MAX_COL + p2.x]->pos();
// 中心點
QPoint pos1(btn_pos1.x() + kIconSize / 2, btn_pos1.y() + kIconSize / 2);
QPoint pos2(btn_pos2.x() + kIconSize / 2, btn_pos2.y() + kIconSize / 2);
painter.drawLine(pos1, pos2);
}
return true;
}
else
return QMainWindow::eventFilter(watched, event);
}
- 注意視窗的事件過濾和分發
- 繪製的時候要注意邊界情況
void MainGameWindow::on_robot_btn_clicked()
{
// 初始時不能自動玩
for (int i = 0; i < 4;i++)
if (game->getHint()[i] == -1)
return;
while (game->gameStatus == PLAYING)
{
// 連線生成提示
int srcX = game->getHint()[0];
int srcY = game->getHint()[1];
int dstX = game->getHint()[2];
int dstY = game->getHint()[3];
if(game->linkTwoTiles(srcX, srcY, dstX, dstY))
{
// 播放音效
// QSound::play(":/res/sound/pair.wav");
// 消除成功,隱藏掉
IconButton *icon1 = imageButton[srcY * MAX_COL + srcX];
IconButton *icon2 = imageButton[dstY * MAX_COL + dstX];
icon1->hide();
icon2->hide();
game->paintPoints.clear();
// 重繪
update();
// 檢查是否勝利
if (game->isWin())
QMessageBox::information(this, "great", "you win");
// 每次檢查一下是否僵局
if (game->isFrozen() && game->gameStatus == PLAYING)
QMessageBox::information(this, "oops", "dead game");
int *hints = game->getHint();
}
}
}
遊戲內建上帝模式,可以根據提示顯示連線的方塊或者自動連線
截圖
原始碼
csdn:連連看 github:連連看