学习QT的过程中,为了加深自己的一些基础操作,也为了想装x,就自己写了一个五子棋小游戏,目前界面没写完整,游戏主题部分可以玩。
五子棋游戏主要的操作有三个。
第一:
void MainWindow::paintEvent(QPaintEvent *) //使用绘图事件时需要添加时间函数在h文件下面
{
QPainter p(this);//创建Qpainter类型并指定绘图背景
QPen pen; //创建画笔,用于设置绘图的线的粗细颜色和一些风格
QBrush brush;
pen.setWidth(4); //制定宽度
p.setPen(pen); //告诉p用画笔来画图
p.drawPixmap(0,0,this->width(),this->height(),QPixmap(":/new/prefix1/5c8a2a67967b8.jpg")); //设置窗口背景]
grand_x=width()/25; //记录横向每一格子的宽度,,分25格子
grand_y=height()/15; //记录纵向每一格子宽度
start_x=grand_x; //记录期盼绘制横向起始坐标
start_y=grand_y; //记录期盼纵向起始坐标
for(int i=0;i<= 23;i++) //循环绘制竖线
{
p.drawLine(start_x+i*grand_x,start_y,start_x+i*grand_x,13*start_y+grand_y); //起始坐标加上每一次循环后格子de宽度
}
for(int i=0;i<=13;i++) //横线
{
p.drawLine(start_x,start_y+i*grand_y,23*grand_x+start_x,start_y+i*grand_y);
}
brush.setStyle(Qt::SolidPattern);
if(chess_x>=0&&click_x<24&&chess_y>=0&&chess_y<14) //绘制下子标记点
{
brush.setColor(Qt::white);
p.setBrush(brush);
p.drawEllipse((start_x+grand_x*chess_x)-7,(start_y+grand_y*chess_y)-7, 14, 14);
}
/*绘制棋子 */
for(int i=0;i<=23;i++)
for(int j=0;j<=13;j++)
{
if((game->gameMapVec[i][j]==1)) //绘制棋子
{
p.setPen(QColor(Qt::black)); //画黑点
p.setBrush(QBrush(Qt::black));
point_x=(start_x+grand_x*i)-15;
point_y=(start_y+grand_y*j)-15;
p.drawEllipse(point_x,point_y,33,33);
// p.end();
/*
第一个参数是x坐标,
第二个是圆的y坐标
注意:这里的xy不是指圆心坐标,而是指圆点起点坐标,从屏幕左上角(0.0)算起
第三个参数是圆点宽度
第四个是高度
可以根据三四各参数来绘制椭圆或者圆
*/
}
if((game->gameMapVec[i][j]==-1)) //绘制棋子
{
p.setPen(QColor(Qt::white)); //画白点
p.setBrush(QBrush(Qt::white));
point_x=(start_x+grand_x*i)-15;
point_y=(start_y+grand_y*j)-15;
p.drawEllipse(point_x,point_y,33,33);
}
}
}
上述函数实现的功能就是绘制棋盘,棋子,和下棋标记。
当鼠标移动时,坐标会跟着移动,判断鼠标当前坐标,动态绘制除下棋标记,当鼠标出发按压事件后,在此处绘制一个棋子。
第二:
void MainWindow::mouseMoveEvent(QMouseEvent *event) //鼠标按压事件
{
int x=event->x(); //定义变量来获取鼠标每次按下后的坐标值
int y=event->y();
if(x>=start_x/2&&x<=start_x+23.5*grand_x&&y>=start_y/2&&y<=start_y*13.5+grand_y) //保证棋子落在棋盘内部,在外部的无效
{
chess_x=(x-start_x/2)/(grand_x); //保证鼠标点击区域的坐标是十字线,(未优化)
chess_y=(y-start_y/2)/(grand_y);
//qDebug() << chess_x<< chess_y;
update();//更新整个界面,(为显示新的棋子的图像)
}
else
{
chess_x=-1; //棋盘的坐标,为了防止出错,初始化-1
chess_y=-1;
}
}
上述代码实现了如下功能:
1,捕获鼠标移动时的坐标,并判断是否在棋盘内。
2,若果在棋盘内,就同过处理,让鼠标在某一个棋盘十字附近的时候,让坐标直接等于棋盘的格子相应的坐标。比如左上角第一个就是(0,0),这样,棋盘在我们眼里相当于一个二维数组。具体处理过程,程序里面有注释。
第三:
int gamemode::Jude_win()
{
int situ_1[5][5]= {{1,1,1,1,1},
{0,0,0,0,0},
{0,0,0,0,0},
{0,0,0,0,0},
{0,0,0,0,0}};
int situ_2[5][5]= {{1,0,0,0,0},
{1,0,0,0,0},
{1,0,0,0,0},
{1,0,0,0,0},
{1,0,0,0,0}};
int situ_3[5][5]= {{1,0,0,0,0},
{0,1,0,0,0},
{0,0,1,0,0},
{0,0,0,1,0},
{0,0,0,0,1}};
int situ_4[5][5]= {{0,0,0,0,1},
{0,0,0,1,0},
{0,0,1,0,0},
{0,1,0,0,0},
{1,0,0,0,0}};
int situ_5[5][5]= {{0,0,0,0,1},
{0,0,0,0,1},
{0,0,0,0,1},
{0,0,0,0,1},
{0,0,0,0,1}};
int situ_6[5][5]= {{0,0,0,0,0},
{0,0,0,0,0},
{0,0,0,0,0},
{0,0,0,0,0},
{1,1,1,1,1}};
for(int i=0;i<=19;i++)
for(int j=0;j<=9;j++)
{
int cnt=0;
for(int x=0;x<=4;x++)
for(int y=0;y<=4;y++)
{
cnt=cnt+situ_1[x][y]*gameMapVec[i+x][j+y]; //
if(cnt==5)
{
return 1;
}
if(cnt==-5)
{
return -1;
}
}
cnt=0;
for(int x=0;x<=4;x++)
for(int y=0;y<=4;y++)
{
cnt=cnt+situ_2[x][y]*gameMapVec[i+x][j+y];
if(cnt==5)
{
return 1;
}
if(cnt==-5)
{
return -1;
}
}
cnt=0;
for(int x=0;x<=4;x++)
for(int y=0;y<=4;y++)
{
cnt=cnt+situ_3[x][y]*gameMapVec[i+x][j+y];
if(cnt==5)
{
return 1;
}
if(cnt==-5)
{
return -1;
}
}
cnt=0;
for(int x=0;x<=4;x++)
for(int y=0;y<=4;y++)
{
cnt=cnt+situ_4[x][y]*gameMapVec[i+x][j+y];
if(cnt==5)
{
return 1;
}
if(cnt==-5)
{
return -1;
}
}
cnt=0;
for(int x=0;x<=4;x++)
for(int y=0;y<=4;y++)
{
cnt=cnt+situ_5[x][y]*gameMapVec[i+x][j+y];
if(cnt==5)
{
return 1;
}
if(cnt==-5)
{
return -1;
}
}
cnt=0;
for(int x=0;x<=4;x++)
for(int y=0;y<=4;y++)
{
cnt=cnt+situ_6[x][y]*gameMapVec[i+x][j+y];
if(cnt==5)
{
return 1;
}
if(cnt==-5)
{
return -1;
}
}
cnt=0;
}
return 0;
}
上述代码是用来判断输赢的。学过图像处理的都知道卷积操作。五子连珠就是相当于用一个5x5的模板去扫描整个棋盘。
在这之前,我用和一个二维数组保存下棋的情况。初始化数组为0.(没有棋子),当触发鼠标按压事件的的时候,如果黑色,标记为1,白色为-1.那么用上述六中情况可以包括所有五子连一起的情况。
ps:刚开始用了四中情况。米子一样的四个模板。但是这样,边界就扫描不到。
人机对战还没有加进去。
如果有大佬愿意一起开发,可以给它加一个开始页面,加人机挑战,甚至可以写如tcp协议,局域网玩。
源码上传至csnd,注释很详细,欢迎下载相互学习。