大家好,欢迎来到IT知识分享网。
这期内容当中小编将会给大家带来有关利用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;
}
}
}
}
在这里窗口网格图是通过直接绘画以及鼠标双击选择坐标来存储棋子和绘画棋子,因此对点进行了一个设置位置函数以便处于两线之间的交接处,代码如下:.
领Qt学习资料→「链接」
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;
}
}
}
}
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/62112.html