Qt项目-翻金币游戏
Qt基础课程完结项目,完成一款小游戏并封装:翻金币游戏,通过点击金币进行翻面,让所有金币为同一面就游戏通过进入下一关。
过程中会使用前面学到的 “信号和槽”,“Qt图片资源显示”,“Qt播放音频”,“Qt绘图函数”,“Qt消息控件”等等知识。是一次前面所学知识的汇总。
框架如下,(因为这个项目完成有些时间了,现在才记录下来,流程部分是看的当时的程序注释,有些不明白的地方可以私信我)
运行平台:
主界面代码:
1 #include "mainwindow.h" 2 #include "ui_mainwindow.h" 3 #include <QPainter> 4 #include <QMenuBar> 5 #include <QDebug> 6 #include <QSound> 7 #include <QTimer> 8 #include "mybutton.h" 9 10 11 MainWindow::MainWindow(QWidget *parent) : 12 QMainWindow(parent), 13 ui(new Ui::MainWindow) 14 { 15 ui->setupUi(this); 16 17 18 //-------------------------------------------------------------主窗口设置-------------------------------------------------------------------// 19 // 1.主窗口场景设置 20 this->setFixedSize(360, 360*1.7); 21 this->setWindowIcon(QPixmap(":/res/Coin0001.png")); 22 this->setWindowTitle("翻金币"); 23 24 // 2.主窗口控件设置 25 connect(ui->actionExit, &QAction::triggered, [=](){ 26 this->close(); 27 }); 28 29 // 3.创建关卡选择界面指针对象,同时监听关卡按钮前线发回的信号 30 this->CustomWidget = new ChooseCustoms; 31 32 connect(CustomWidget, &ChooseCustoms::ChooseCustomBacksig, [=](){ 33 this->setGeometry(CustomWidget->geometry()); 34 CustomWidget->hide(); 35 this->show(); 36 }); 37 38 // 4.创建并移动开始按钮对象 39 MyButton *startBtn = new MyButton(":/res/MenuSceneStartButton.png"); 40 startBtn->setParent(this); 41 startBtn->move((this->width() - startBtn->width())*0.5, this->height()*0.7); 42 43 // 5.播放开始按钮点击音效 44 QSound *startSound = new QSound(":/res/TapButtonSound.wav", this); 45 46 connect(startBtn, &MyButton::clicked, [=](){ 47 qDebug() << "点击了开始按钮"; 48 startBtn->jumpDown(); 49 startSound->play(); 50 startBtn->jumpUp(); 51 52 QTimer::singleShot(400, this, [=](){ this->hide(); CustomWidget->show(); }); 53 }); 54 } 55 56 57 58 59 //-------------------------------------------------------------主窗口绘图事件绘制界面-------------------------------------------------------------------// 60 void MainWindow::paintEvent(QPaintEvent *) 61 { 62 QPainter painter(this); 63 64 // 绘制主场景背景界面 65 QPixmap pix; 66 pix.load(":/res/海滩.jpg"); 67 painter.drawPixmap(QRect(0, 0, this->width(), this->height()), pix); 68 69 // 绘制主场景图标 70 pix.load(":/res/Title.png"); 71 pix = pix.scaled(pix.width()*0.7, pix.height()*0.7); 72 painter.drawPixmap(10, 30, pix.width(), pix.height() , pix); 73 } 74 75 76 MainWindow::~MainWindow() 77 { 78 delete ui; 79 }
关卡选择界面函数:
1 #include "choosecustoms.h" 2 #include <QMenuBar> 3 #include <QPainter> 4 #include <QSound> 5 #include <QLabel> 6 #include <QTimer> 7 #include <QDebug> 8 9 ChooseCustoms::ChooseCustoms(QWidget *parent) : QMainWindow(parent) 10 { 11 //-------------------------------------------------------------主窗口设置-------------------------------------------------------------------// 12 // 1.场景以及图标,标题设置 13 this->setFixedSize(360, 360*1.7); 14 this->setWindowIcon(QPixmap(":/res/Coin0001.png")); 15 this->setWindowTitle("翻金币"); 16 17 // 2.创建菜单栏,创建关闭按钮 18 QMenuBar *bar = this->menuBar(); 19 this->setMenuBar(bar); 20 QMenu *startMenu = bar->addMenu("开始"); 21 QAction *quitAction = startMenu->addAction("退出"); 22 23 connect(quitAction, &QAction::triggered, [=](){ 24 this->hide(); 25 }); 26 27 // 3.返回按钮,返回按钮点击后返回的信号 28 MyButton *retBtn = new MyButton(":/res/BackButton.png", ":/res/BackButtonSelected.png"); 29 retBtn->setParent(this); 30 retBtn->move(this->width()-retBtn->width(), this->height()-retBtn->height()); 31 32 33 connect(retBtn, &MyButton::clicked, [=](){ 34 qDebug() << "点击了返回按钮"; 35 QSound *retSound = new QSound(":/res/BackButtonSound.wav", this); 36 retSound->play(); 37 QTimer::singleShot(400, this, [=](){ emit this->ChooseCustomBacksig(); }); 38 }); 39 40 //-------------------------------------------------------------for循环创建关卡选择按钮----------------------------------------------------------// 41 // 4.创建关卡选择按钮 42 for(int i = 0; i < 20; i++) 43 { 44 // 绘制按钮图标 45 MyButton *customBtn = new MyButton(":/res/LevelIcon.png"); 46 customBtn->setParent(this); 47 customBtn->move(45 + (i%4)*70 , 150 + (i/4)*70); // 我们要一个4x5的矩阵 48 customBtnArray[i] = customBtn; 49 50 // 关联每一个按钮的启动函数 51 connect(customBtn, &MyButton::clicked, [=](){ 52 53 // 关卡选择按钮上锁,其余的按钮不能点击 54 for(int i = 0; i < 20; i++) 55 { 56 customBtnArray[i]->isclick = true; 57 } 58 qDebug() << "选择了" << i+1 << "关卡"; 59 if(this->coinfligwidget == NULL) 60 { 61 customBtn->jumpDown(); 62 customBtn->jumpUp(); 63 QSound *chooseSound = new QSound(":/res/TapButtonSound.wav", this); 64 chooseSound->play(); 65 66 QTimer::singleShot(400, this, [=](){ 67 this->hide(); 68 this->coinfligwidget = new CoinFligWidget(i+1); 69 coinfligwidget->setGeometry(this->geometry()); 70 coinfligwidget->show(); 71 72 // 关卡选择按钮解锁,其余的按钮可以点击 73 for(int i = 0; i < 20; i++) 74 { 75 customBtnArray[i]->isclick = false; 76 } 77 78 connect(coinfligwidget, &CoinFligWidget::CoinFligBacksig, [=](){ 79 this->setGeometry(coinfligwidget->geometry()); 80 this->show(); 81 delete coinfligwidget; 82 coinfligwidget = NULL; 83 }); 84 }); 85 } 86 }); 87 88 // 绘制按钮数字 89 QLabel *label = new QLabel; 90 label->setParent(this); 91 label->setFixedSize(customBtn->width(), customBtn->height()); 92 label->setText(QString::number(i+1)); 93 label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); 94 label->move(45 + (i%4)*70 , 150 + (i/4)*70); 95 label->setAttribute(Qt::WA_TransparentForMouseEvents,true); // 鼠标事件穿透 96 } 97 } 98 99 //-------------------------------------------------------------主窗口绘图事件绘制界面--------------------------------------------------------------// 100 101 void ChooseCustoms::paintEvent(QPaintEvent *event) 102 { 103 QPainter painter(this); 104 QPixmap pix; 105 pix.load(":/res/海滩1.jpg"); 106 painter.drawPixmap(0, 0, this->width(), this->height(), pix); 107 108 pix.load(":/res/Title.png"); 109 painter.drawPixmap((this->width() - pix.width())*0.5, 30, pix.width(), pix.height(), pix); 110 }
翻金币页面代码:
1 #include "coinfligwidget.h" 2 #include "dataconfig.h" 3 #include "mybutton.h" 4 #include <QPropertyAnimation> 5 #include <QMenuBar> 6 #include <iostream> 7 #include <QPainter> 8 #include <QDebug> 9 #include <QSound> 10 #include <QTimer> 11 12 13 14 CoinFligWidget::CoinFligWidget(int index) 15 { 16 //-------------------------------------------------------------初始化数据-------------------------------------------------------------------// 17 this->levalIndex = index; 18 dataConfig config; 19 for(int i = 0; i < 4; i++) 20 { 21 for(int j = 0; j < 4; j++) 22 { 23 gameArray[i][j] = config.mData[this->levalIndex][i][j]; 24 } 25 } 26 //-------------------------------------------------------------主窗口设置-------------------------------------------------------------------// 27 // 1.场景以及图标,标题设置 28 this->setFixedSize(360, 360*1.7); 29 30 this->setWindowIcon(QPixmap(":/res/Coin0001.png")); 31 this->setWindowTitle("翻金币"); 32 33 // 2.创建菜单栏,创建关闭按钮 34 QMenuBar *bar = this->menuBar(); 35 this->setMenuBar(bar); 36 QMenu *startMenu = bar->addMenu("开始"); 37 QAction *quickAction = startMenu->addAction("退出"); 38 39 connect(quickAction, &QAction::triggered, [=](){ 40 this->hide(); 41 }); 42 43 // 3.返回按钮,返回按钮发出的信号 44 MyButton *retBtn = new MyButton(":/res/BackButton.png", ":/res/BackButtonSelected.png"); 45 retBtn->setParent(this); 46 retBtn->move(this->width()-retBtn->width(), this->height()-retBtn->height()); 47 48 connect(retBtn, &MyButton::clicked, [=](){ 49 qDebug() << "点击了返回按钮"; 50 QSound *chooseSound = new QSound(":/res/TapButtonSound.wav", this); 51 chooseSound->play(); 52 QTimer::singleShot(400, this, [=](){ emit this->CoinFligBacksig(); }); 53 }); 54 55 // 4.显示当前关卡 56 QLabel *label = new QLabel(this); 57 QFont font; 58 font.setFamily("华文新魏"); 59 font.setPointSize(20); 60 label->setFont(font); 61 QString str = QString("Leavel: %1").arg(this->levalIndex); 62 label->setText(str); 63 label->setGeometry(QRect(20, this->height()-75, 120, 50)); 64 65 // 5.将胜利图片创建好,如果胜利触发了,将图片弹下去即可 66 QLabel *winLabel = new QLabel(this); 67 QPixmap temPix; 68 temPix.load(":/res/LevelCompletedDialogBg.png"); 69 winLabel->setGeometry(0, 0, temPix.width(), temPix.height()); 70 winLabel->setPixmap(temPix); 71 winLabel->move((this->width() - temPix.width())*0.5, -temPix.height()); 72 73 // 翻金币音效 74 QSound *flipSound = new QSound(":/res/ConFlipSound.wav",this); 75 76 77 //-------------------------------------------------------------金币初始化-------------------------------------------------------------------// 78 for(int i = 0; i < 4; i++) 79 { 80 for(int j = 0; j < 4; j++) 81 { 82 // 5.创建金币背景图片 83 QLabel *label = new QLabel(this); 84 label->setGeometry(0, 0, 50, 50); 85 label->setPixmap(QPixmap(":/res/BoardNode.png")); 86 label->move(80 + i*50, 200 + j*50); 87 88 // 6.初始化金币 89 QString img; 90 if(gameArray[i][j] == 1) 91 { 92 img = ":/res/Coin0001.png"; 93 } 94 else 95 { 96 img = ":/res/Coin0008.png"; 97 } 98 99 MyCoin *coin = new MyCoin(img); 100 coin->setParent(this); 101 coin->move(82 + i*50,203 + j*50); 102 103 // 为每个金币属性赋值,1.记录坐标 2.记录正反 104 coin->posX = i; 105 coin->posY = j; 106 coin->flag = gameArray[i][j]; 107 coinBtn[i][j] = coin; 108 109 // 7.监听每个按钮的点击 110 connect(coin, &MyCoin::clicked, [=](){ 111 flipSound->play(); 112 113 // 在此颗金币点击的瞬间,其余金币全部禁用,鼠标拦截事件弹出 114 for(int i = 0; i < 4; i++) 115 { 116 for(int j = 0; j < 4; j++) 117 { 118 this->coinBtn[i][j]->isWin = true; 119 } 120 } 121 122 // 翻转金币 123 coin->changflag(); 124 this->gameArray[i][j] = this->gameArray[i][j] == 0 ? 1 : 0; 125 126 //-------------------------------------------------------------周围金币翻转,并且判断输赢-------------------------------------------------------// 127 QTimer::singleShot(300, this, [=](){ 128 this->aroundChang(i, j, coin); 129 this->judgeWin(winLabel); 130 }); 131 }); 132 } 133 } 134 } 135 136 // ->将周围金币进行翻转 137 void CoinFligWidget::aroundChang(int i, int j, MyCoin *coin) 138 { 139 if(coin->posX+1 <= 3) 140 { 141 coinBtn[coin->posX+1][coin->posY]->changflag(); 142 gameArray[coin->posX+1][coin->posY] = gameArray[i][j] == 0 ? 1 : 0; 143 } 144 if(coin->posX-1 >= 0) 145 { 146 coinBtn[coin->posX-1][coin->posY]->changflag(); 147 gameArray[coin->posX-1][coin->posY] = gameArray[i][j] == 0 ? 1 : 0; 148 } 149 if(coin->posY+1 <= 3) 150 { 151 coinBtn[coin->posX][coin->posY+1]->changflag(); 152 gameArray[coin->posX][coin->posY+1] = gameArray[i][j] == 0 ? 1 : 0; 153 } 154 if(coin->posY-1 >= 0) 155 { 156 coinBtn[coin->posX][coin->posY-1]->changflag(); 157 gameArray[coin->posX][coin->posY-1] = gameArray[i][j] == 0 ? 1 : 0; 158 } 159 160 for(int i = 0; i < 4; i++) 161 { 162 for(int j = 0; j < 4; j++) 163 { 164 this->coinBtn[i][j]->isWin = false; 165 } 166 } 167 } 168 169 // ->判断是否胜利 170 void CoinFligWidget::judgeWin(QLabel *label) 171 { 172 this->isWin = true; 173 for(int i = 0; i < 4; i++) 174 { 175 for(int j = 0; j < 4; j++) 176 { 177 if(this->coinBtn[i][j]->flag == false) 178 { 179 this->isWin = false; 180 break; 181 } 182 } 183 } 184 185 if(this->isWin) 186 { 187 qDebug() << "亲爱的,你的的确确是赢了!"; 188 // 胜利按钮音效 189 QSound *winSound = new QSound(":/res/LevelWinSound.wav",this); 190 winSound->play(); 191 QPropertyAnimation *animation = new QPropertyAnimation(label, "geometry"); 192 animation->setDuration(1000); 193 animation->setStartValue(QRect(label->x(), label->y(), label->width(), label->height())); 194 animation->setEndValue(QRect(label->x(), label->y()+144, label->width(), label->height())); 195 animation->setEasingCurve(QEasingCurve::OutBounce); 196 animation->start(); 197 198 // 赢了之后禁止翻转按钮 199 for(int i = 0; i < 4; i++) 200 { 201 for(int j = 0; j < 4; j++) 202 { 203 this->coinBtn[i][j]->isWin = true; 204 } 205 } 206 } 207 } 208 209 //-------------------------------------------------------------主窗口绘图事件绘制界面--------------------------------------------------------------// 210 void CoinFligWidget::paintEvent(QPaintEvent *event) 211 { 212 QPainter painter(this); 213 QPixmap pix; 214 215 // 加载背景 216 pix.load(":/res/海滩.jpg"); 217 painter.drawPixmap(QRect(0, 0, this->width(), this->height()), pix); 218 219 // 加载标题 220 pix.load(":/res/Title.png"); 221 pix = pix.scaled(pix.width()*0.5, pix.height()*0.5); 222 painter.drawPixmap(10,30,pix.width(),pix.height(),pix); 223 }
- 这一次项目让我有了对C++的重新审视,刚学的时候:哟,这不就是C嘛,中途:WOC,这是什么??? 做完项目:原来这就是C++啊<仍然懵。。。>
- 要想开启一个项目,一定是先主体后局部,先框架后函数,以前我写代码总是热衷于函数某一个功能的优化,导致项目迟迟难以推进,这次真正见识到了,先搭框架后细化的感觉有多爽。
- Qt的环境变量花了我大量时间配置......