您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關利用Qt實現一個簡單的五子棋小游戲,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
下圖為游戲主窗口頁面:
第一步:窗口繪圖的實現(QPaintEvent繪圖事件 和 QMouseEvent鼠標事件)
①鼠標事件(這里我的是mouseDoubleClickEvent()雙擊事件)
void GamePage::mouseDoubleClickEvent(QMouseEvent *event)//鼠標雙擊事件 { m_dx = event->x(); m_dy = event->y(); //避免亂點時存入坐標 需添加:標志符--》game狀態 坐標的界限(點) if(m_dx < POINT_X_MAX && m_dy < POINT_Y_MAX && m_bRunState == true) { //如果點在交叉點周圍則設置點在交叉點上(判斷點位置) QPointF newPoint(gainPointPosition(QPointF(m_dx,m_dy))); if(!m_VectorRedPoint.contains(newPoint) && !m_VectorBlackPoint.contains(newPoint))//判斷點是否已經存在 { if(m_iFlagWho == 0)//紅棋 { m_VectorRedPoint.append(newPoint); m_iFlagWho = 1; } else//黑棋 { m_VectorBlackPoint.append(newPoint); m_iFlagWho = 0; } } } }
在這里窗口網格圖是通過直接繪畫以及鼠標雙擊選擇坐標來存儲棋子和繪畫棋子,因此對點進行了一個設置位置函數以便處于兩線之間的交接處,代碼如下:
QPointF GamePage::gainPointPosition(QPointF srcPoint)//返回一個處于格子兩線交接處的坐標點 { QPointF tmp; for(int i = 0;i < 12;i++) { if(srcPoint.x() >= 50*i && srcPoint.x() <= (50*i+25))//X判斷 { tmp.setX(50*i);//如果處于50*i ~ 50*i+25)之間則設置點坐標點為50*i } else if (srcPoint.x() >= (50*i + 25) && srcPoint.x() <= 50*(i+1)) { tmp.setX(50*(i+1));//如果處于50*i+25 ~ 50*(i+1)之間則設置點坐標點為50*(i+1) } if(srcPoint.y() >= 50*i && srcPoint.y() <= (50*i+25))//Y判斷 { tmp.setY(50*i);//同上 } else if (srcPoint.y() >= (50*i + 25) && srcPoint.y() <= 50*(i+1)) { tmp.setY(50*(i+1));//同上 } } return tmp; }
②繪圖事件( 主要是網格圖、黑棋、紅棋的繪畫 )
棋子坐標的存儲主要是通過QVector容器來實現,并對容器進行迭代循環繪圖,實現代碼如下:
void GamePage::paintEvent(QPaintEvent *event)//繪畫事件 { QPainter *pater = new QPainter(this); pater->begin(this); //網格圖 pater->setPen(Qt::black); for(int i = 0;i <= 12;i++) { pater->drawLine(0,50*i,600,50*i); pater->drawLine(50*i,0,50*i,600); } //紅色棋繪畫 QVector<QPointF>::iterator iter; for(iter = m_VectorRedPoint.begin();iter != m_VectorRedPoint.end();iter++) { pater->setBrush(QBrush(Qt::red, Qt::SolidPattern)); pater->setPen(Qt::red); pater->drawEllipse(*iter,15,15); } //黑色棋繪畫 QVector<QPointF>::iterator iter1; for(iter1 = m_VectorBlackPoint.begin();iter1 != m_VectorBlackPoint.end();iter1++) { pater->setBrush(QBrush(Qt::black, Qt::SolidPattern)); pater->setPen(Qt::black); pater->drawEllipse(*iter1,15,15); } pater->end(); update(); }
第二步:輸贏的計算
上圖列出了計算的關系規律,下面就用代碼分別實現三個不同方向的計算:
①橫向
bool GamePage::checkXPointF(QVector<QPointF> vector) //檢查X軸方向的 { int num_L= 1; int num_R = 1; QVector<QPointF>::iterator iter; QVector<QPointF>::iterator itertmp; for(iter = vector.begin();iter != vector.end();iter++) { QPointF tmp = *iter; for(int k = 1;k < 5;k++)//左方向的查找 { for(itertmp = vector.begin();itertmp != vector.end();itertmp++) { qDebug()<<*itertmp<<"X compare"<<tmp; if((*itertmp).x() - tmp.x() == k*50) { num_L ++; } } //qDebug()<<"count:"<<num; if(num_L == k+1)//尋找過程中找到幾個點相連 { if(num_L == 5) { return true; } } else { break; } } for(int k = 1;k < 5;k++)//右方向的查找 { for(itertmp = vector.begin();itertmp != vector.end();itertmp++) { qDebug()<<*itertmp<<"X compare"<<tmp; if((*itertmp).x() - tmp.x() == -k*50) { num_R ++; } } //qDebug()<<"count:"<<num; if(num_R == k+1)//尋找過程中找到幾個點相連 { if(num_R == 5) { return true; } } else { break; } } if(num_R + num_L == 5+1)//5+1 因為左右方向都是從1開始計算 重復了原點tmp坐標 { return true; } else { num_R = 1; num_L = 1; } } return false; }
②縱向(與橫向同理)
bool GamePage::checkYPointF(QVector<QPointF> vector) { qDebug()<<"enter Y***************"; int num_U = 1; int num_D = 1; QVector<QPointF>::iterator iter; QVector<QPointF>::iterator itertmp; for(iter = vector.begin();iter != vector.end();iter++) { QPointF tmp = *iter; for(int k = 1;k < 5;k++)//上 { for(itertmp = vector.begin();itertmp != vector.end();itertmp++) { qDebug()<<*itertmp<<"Y compare"<<tmp; if((*itertmp).y() - tmp.y() == k*50) { num_U ++; } } qDebug()<<"num_U:"<<num_U; if(num_U == k+1)//尋找過程中找到幾個點相連 { if(num_U == 5) { return true; } }else{break;} } for(int k = 1;k < 5;k++)//下 { for(itertmp = vector.begin();itertmp != vector.end();itertmp++) { qDebug()<<*itertmp<<"Y compare"<<tmp; if((*itertmp).y() - tmp.y() == -k*50) { num_D ++; } } qDebug()<<"num_D:"<<num_D; if(num_D == k+1)//尋找過程中找到幾個點相連 { if(num_D == 5) { return true; } }else{break;} } if(num_D + num_U == 5 + 1)//減去一個 { return true; } else { num_D = 1; num_U= 1; } } return false; }
③斜向(從上圖可知,以坐標系為例,分為四個象限的計算和計數來判斷是否達到要求)
int GamePage::findSeriesPointF(bool flag, QPointF tmp, QVector<QPointF> vector) { bool flag_iter = false; int forward_count = 1;//一象限的數量 int reverse_count = 1; int forward_count2 = 1; int reverse_count2 = 1; QVector<QPointF>::iterator iter= vector.begin(); while(iter != vector.end()) { qDebug()<<*iter<<"compare"<<tmp; switch(forward_count)//一象限 { case 1: if((*iter).x() - tmp.x() == 50 && (*iter).y() - tmp.y() == -50) { forward_count ++; flag_iter = true; } break; case 2: if((*iter).x() - tmp.x() == 50*forward_count && (*iter).y() - tmp.y() == -50*forward_count) { forward_count++; flag_iter = true; } break; case 3: if((*iter).x() - tmp.x() == 50*forward_count && (*iter).y() - tmp.y() == -50*forward_count) { forward_count++; flag_iter = true; } break; case 4: if((*iter).x() - tmp.x() == 50*forward_count && (*iter).y() - tmp.y() == -50*forward_count) { forward_count++; flag_iter = true; } break; } switch(reverse_count)//三象限 { case 1: if((*iter).x() - tmp.x() == -50 && (*iter).y() - tmp.y() == 50) { reverse_count=2; flag_iter = true; } break; case 2: if((*iter).x() - tmp.x() == -50*reverse_count && (*iter).y() - tmp.y() == 50*reverse_count) { reverse_count++; flag_iter = true; } break; case 3: if((*iter).x() - tmp.x() == -50*reverse_count && (*iter).y() - tmp.y() == 50*reverse_count) { reverse_count++; flag_iter = true; } break; case 4: if((*iter).x() - tmp.x() == -50*reverse_count && (*iter).y() - tmp.y() == 50*reverse_count) { reverse_count++; flag_iter = true; } break; } qDebug()<<forward_count<<"+"<<reverse_count; if(forward_count + reverse_count == 6)//未加上點本身 { return 5; } switch(forward_count2)//2象限 { case 1: if((*iter).x() - tmp.x() == -50 && (*iter).y() - tmp.y() == -50) { forward_count2++; flag_iter = true; } break; case 2: if((*iter).x() - tmp.x() == -50*forward_count2 && (*iter).y() - tmp.y() == -50*forward_count2) { forward_count2++; flag_iter = true; } break; case 3: if((*iter).x() - tmp.x() == -50*forward_count2 && (*iter).y() - tmp.y() == -50*forward_count2) { forward_count2++; flag_iter = true; } break; case 4: if((*iter).x() - tmp.x() == -50*forward_count2 && (*iter).y() - tmp.y() == -50*forward_count2) { forward_count2++; flag_iter = true; } break; } switch(reverse_count2)//4象限 { case 1: if((*iter).x() - tmp.x() == 50 && (*iter).y() - tmp.y() == 50) { reverse_count2++; flag_iter = true; } break; case 2: if((*iter).x() - tmp.x() == 50*reverse_count2 && (*iter).y() - tmp.y() == 50*reverse_count2) { reverse_count2++; flag_iter = true; } break; case 3: if((*iter).x() - tmp.x() == 50*reverse_count2 && (*iter).y() - tmp.y() == 50*reverse_count2) { reverse_count2++; flag_iter = true; } break; case 4: if((*iter).x() - tmp.x() == 50*reverse_count2 && (*iter).y() - tmp.y() == 50*reverse_count2) { reverse_count2++; flag_iter = true; } break; } qDebug()<<forward_count2<<"+"<<reverse_count2; if(forward_count2 + reverse_count2 == 6)//未加上點本身 { return 5; } if(flag_iter) { iter = vector.begin();//目的是返回首個點,重頭存貨在后 不錯過 flag_iter = false; } else { iter++; } } return 0; }
以上橫、縱、斜三個方向的運算都是通過最簡單的算法是實現,易于理解。
④定時器實現紅黑旗的定時檢查功能
void GamePage::slotCheckWhetherWin()//定時器檢查是否輸贏功能 { m_pVerVector.clear(); m_pVerVectorB.clear(); m_pHerVector.clear(); m_pHerVectorB.clear(); QVector<QPointF>::iterator iterRed; for(iterRed = m_VectorRedPoint.begin();iterRed != m_VectorRedPoint.end();iterRed++) { qDebug()<<*iterRed; } QVector<QPointF> tmpRed = m_VectorRedPoint; //紅棋判斷 if(m_VectorRedPoint.size() >= 5) { for(iterRed = m_VectorRedPoint.begin();iterRed != m_VectorRedPoint.end();iterRed++) { QPointF tmp = *iterRed;//獲取第一個點 qDebug()<<"tmp:"<<tmp; QVector<QPointF>::iterator itertmp; for(itertmp = tmpRed.begin();itertmp != tmpRed.end();itertmp++) { qDebug()<<"tmpRed:"<<*itertmp; //橫向連續5個點 if((*itertmp).y() - tmp.y() >= -0.000001 && (*itertmp).y() - tmp.y() <= 0.000001)//先判斷y是同一坐標 { m_pHerVector.append(*itertmp); } //縱向連續5個點 if((*itertmp).x() - tmp.x() >= -0.000001 && (*itertmp).x() - tmp.x() <= 0.000001)//先判斷y是同一坐標 { m_pVerVector.append(*itertmp); } } //對容器進行操作 if(checkXPointF(m_pHerVector) || checkYPointF(m_pVerVector)) { QMessageBox::warning(nullptr,"warning","紅方XY贏了!"); m_ptimer->stop(); return; } else { m_pHerVector.clear();//清空 m_pVerVector.clear();//清空 count = 0; } //其他都是斜向 if(findSeriesPointF(true,tmp,m_VectorRedPoint) == 5) { QMessageBox::warning(nullptr,"warning","紅方斜線贏了!"); m_ptimer->stop(); return; } } } //黑棋判斷 QVector<QPointF>::iterator iterBlack; QVector<QPointF> tmpBlack = m_VectorBlackPoint; if(m_VectorBlackPoint.size() >= 5) { for(iterBlack = m_VectorBlackPoint.begin();iterBlack != m_VectorBlackPoint.end();iterBlack++) { QPointF tmp = *iterBlack;//獲取第一個點 qDebug()<<"tmp:"<<tmp; QVector<QPointF>::iterator itertmp; for(itertmp = tmpBlack.begin();itertmp != tmpBlack.end();itertmp++)//正向 { qDebug()<<"tmpRed:"<<*itertmp; //橫向連續5個點 if((*itertmp).y() - tmp.y() >= -0.000001 && (*itertmp).y() - tmp.y() <= 0.000001)//先判斷y是同一坐標 { m_pHerVectorB.append(*itertmp); } //縱向連續5個點 if((*itertmp).x() - tmp.x() >= -0.000001 && (*itertmp).x() - tmp.x() <= 0.000001)//先判斷y是同一坐標 { m_pVerVectorB.append(*itertmp); } } //對容器進行操作 if(checkXPointF(m_pHerVectorB) || checkYPointF(m_pVerVectorB)) { QMessageBox::warning(nullptr,"warning","黑方XY贏了!"); m_ptimer->stop(); return; } else { m_pHerVectorB.clear();//清空 m_pVerVectorB.clear();//清空 count = 0; } //其他都是斜向 if(findSeriesPointF(true,tmp,m_VectorBlackPoint) == 5) { QMessageBox::warning(nullptr,"warning","黑方斜線贏了!"); m_ptimer->stop(); return; } } } }
上述就是小編為大家分享的利用Qt實現一個簡單的五子棋小游戲了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。