一.图形的绘制
1.蛇的绘制
蛇采用RectF方式绘制,每个Rect放入链表中组成
QRect rect(x, y, width, height) 参数为,矩形顶点坐标,宽,高
QList append() ——尾部添加节点
//.h中声明
QList<QRect> snake;
//.cpp构造中初始化
QRectF rect(300,180,nodeWidth,nodeHeight);
snake.append(rect);
绘图事件中绘制蛇
for(int i=0;i<snake.length();i++)
{
painter.drawRect(snake[i]);
}
2.奖励的绘制
奖励的绘制同样使用rect
//.h中
QRectF rewordNode;
//.cpp的绘图事件中
painter.drawEllipse(rewordNode);
奖品的随机出现单独封装函数,rect的顶点随机,长宽在.h中初始设置。
在构造函数中调用,初始化奖品
QRandomGenerator::global()->bounded(10) 生成0-10随机数
void Widget::addNewReword()
{
rewordNode=QRectF(QRandomGenerator::global()->bounded(this->width()/20)*20,
QRandomGenerator::global()->bounded(this->height()/20)*20,
nodeWidth,nodeHeight);
}
二.蛇的移动
1.按键与方向关联(重写键盘事件)
自定义枚举变量表示是否改变方向,声明方向改变标志判断,声明游戏是否开始标志。方向初始默认为向上
(枚举变量需类外声明)
//枚举变量表示方向
typedef enum Dridct{
Dir_left, Dir_right, Dir_up, Dir_down
}dir_t;
int moveFlag=Dir_up; //改变方向标志
bool gameStart=false; //游戏开始标志
重写键盘事件,将方向与摁键关联,空格键需判断游戏是否处于开始状态,若为开始状态则暂停,若为暂停状态则开始。若为正在向上时则不允许向下,其他方向同理。
void Widget::keyPressEvent(QKeyEvent *e)
{
switch(e->key()) //确定是哪个按键
{
case Qt::Key_Up:
if(moveFlag != Dir_down)
moveFlag=Dir_up;
break;
case Qt::Key_Down:
if(moveFlag != Dir_up)
moveFlag=Dir_down;
break;
case Qt::Key_Right:
if(moveFlag != Dir_left)
moveFlag=Dir_right;
break;
case Qt::Key_Left:
if(moveFlag != Dir_right)
moveFlag=Dir_left;
break;
case Qt::Key_Space:
if(gameStart==false) //此时游戏开始
{
gameStart=true;
//启动定时器
timer->start(time);
}
else
{
gameStart=false;
//关闭定时器
timer->stop();
}
break;
default:
break;
}
}
2.移动过程蛇身变化
以向上为例,当向上移动时,蛇链表头部向上增加一个矩形。
要判断是否超出了边框
//向上添加
void Widget::addTop()
{
QPointF leftTop;
QPointF rightBottom;
if(snake[0].y()-nodeHeight<0)
{
leftTop=QPoint(snake[0].x(),this->height()-nodeHeight);
rightBottom=QPointF(snake[0].x()+nodeWidth,this->height());
}
else
{
leftTop=QPointF(snake[0].x(),snake[0].y()-nodeHeight);
rightBottom=snake[0].topRight();
}
snake.insert(0,QRectF(leftTop,rightBottom)); //在下标0处添加节点
}
QList 中
insetr() ——插入节点到 removeLast()——尾部删除
三.定时器事件控制
1.定时器
当游戏开始时,定时器开始,并且每隔180毫秒刷新界面。
//.h中声明出定时器
QTimer *timer;
int time=100; //超时时间间隔
//.cpp的构造函数中初始化定时器
timer=new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(timeout()));
2.自定义定时器槽函数
当游戏开始时,定时器开始,绘图事件重写,界面将不断刷新。槽函数中需要完成:蛇移动过程中图像的变化,以及吃掉奖励时的画面变化
void Widget::timeout()
{
int count=1;
//判断吃掉奖励 蛇头部是否与奖励重合
if(snake[0].intersects(rewordNode))
{
count++;
addNewReword();
scoer++; //记录分数
}
while(count--)
{
switch(moveFlag)
{
case Dir_up:
//向上增加
addTop();
break;
case Dir_down:
addDown();
break;
case Dir_left:
addLeft();
break;
case Dir_right:
addRight();
break;
}
}
deletelast(); //封装的尾删函数 当未吃掉奖励时,删掉最后一个保持长度不变
update();
}
四.判断游戏结束
检查蛇头是否碰到蛇身
自定义bool类函数
//检查是否碰到蛇身
bool Widget::checkContact()
{
for(int i=0;i<snake.length();i++)
{
for(int j=i+1;j<snake.length();j++)
{
if(snake[j] == snake[i])
{
return true;
}
}
}
return false;
}
在绘图事件中绘制游戏结束 并且关闭定时器
if(checkContact())
{
QFont font("方正舒体",30,QFont::ExtraLight,false);
pen.setColor(Qt::red);
painter.setPen(pen);
painter.setFont(font);
painter.drawText((this->width()-300)/2,
(this->height()-30)/2,
QString("GAME OVER!"));
time->stop();
}
效果如图所示