效果如下:
由于是个人为了学习而实现的,隐藏图片比较粗糙,有兴趣的可以自己优化,仅作学习参考。
游戏比较简单主要包括绘制墙壁、食物、蛇、网格, 以及一些逻辑运算组成。
源码地址:https://gitee.com/lingluonianhua/Snake.git
核心代码如下:
#include "snakelogic.h"
#include <QPixmap>
SnakeLogic::SnakeLogic(QPoint left,QPoint right,int unit,QObject *parent) :
QObject(parent),m_pLeftTop(left),m_pRight(right),m_iUnitage(unit),
m_icoortable(NULL),m_lSnakeList(NULL)
{
InitParam();
memset(m_pFoodArr,0,sizeof(m_pFoodArr));
QPoint rect = m_pRight - m_pLeftTop;
m_iNumX = rect.x()/m_iUnitage;
m_iNumY = rect.y()/m_iUnitage;
m_icoortable = new int*[m_iNumY ];
for(int i = 0; i < m_iNumY ; i++)
{
m_icoortable[i] = new int[m_iNumX ];
}
InitMap();
}
void SnakeLogic::start()
{
try
{
if(m_lSnakeList != NULL)
{
this->CleanSnake();
delete m_lSnakeList;
}
m_lSnakeList = new QList<QPoint>;
this->InitParam();
this->InitSnake();
this->CreateFood();
this->m_bIsStart = true;
}
catch(...)
{
}
}
void SnakeLogic::CleanSnake()
{
QList<QPoint>::const_iterator item = m_lSnakeList->begin();
while(item != m_lSnakeList->end())
{
m_lSnakeList->pop_front();
item++;
}
}
void SnakeLogic::InitParam()
{
m_pCurDir = QPoint(1,0);
m_bListRev = false;
m_iFoodNum = 0;
m_iScore = 0;
m_iLevel = 0;
m_bIsPause = false;
m_bIsStart = false;
m_bIsGameOver = false;
}
void SnakeLogic::InitSnake()
{
if(!m_lSnakeList)
return ;
while(!m_lSnakeList->isEmpty())
{
m_lSnakeList->pop_back();
}
QPoint one(4,2);
QPoint two(3,2);
QPoint three(2,2);
m_lSnakeList->push_back(one);
m_lSnakeList->push_back(two);
m_lSnakeList->push_back(three);
}
void SnakeLogic::InitMap()
{
for(int i = 0;i < m_iNumY ; i++)
{
for(int j = 0; j < m_iNumX ; j++)
{
if(i == 0 || j == 0 || i == m_iNumY - 1 || j == m_iNumX - 1 )
{
m_icoortable[i][j] = 1;
}
else
{
m_icoortable[i][j] = 0;
}
}
}
}
void SnakeLogic::Paint(QPainter *p)
{
try
{
this->PaintGridding(p);
this->PaintWall(p);
this->PaintSnake(p);
this->PaintFood(p);
}
catch(...)
{
}
}
void SnakeLogic::PaintWall(QPainter *p) //ǽ
{
QPixmap img("://res/855.bmp");
QImage bk("://res/wall.bmp");
QBrush brsh;
brsh.setTextureImage(bk);
p->setOpacity(0.5);
p->fillRect(m_pLeftTop.x(),m_pLeftTop.y(),m_pRight.x(),m_pRight.y(),brsh);
p->setOpacity(1.0);
for(int i = 0;i < m_iNumY ; i++)
{
for(int j = 0; j < m_iNumX ; j++)
{
if(m_icoortable[i][j] == 1)
{
QPoint beg = GetConvPoint(QPoint(j,i));
QRect rect(beg,beg + QPoint(m_iUnitage,m_iUnitage));
p->drawPixmap(rect,img);
}
}
}
}
void SnakeLogic::PaintGridding(QPainter *p)
{
QColor clr(0,255,100);
p->setPen(clr);
for(int i = m_pLeftTop.x(); i <= m_pRight.x() ; i += m_iUnitage)
{
p->drawLine(i,m_pLeftTop.y(),i,m_pRight.y());
}
for(int i = m_pLeftTop.y(); i <= m_pRight.y() ; i += m_iUnitage)
{
p->drawLine(m_pLeftTop.x() ,i,m_pRight.x(),i);
}
}
void SnakeLogic::PaintSnake(QPainter *p)
{
if(!m_lSnakeList)
return;
QPixmap img("://res/849.bmp");
QList<QPoint>::const_iterator item = m_lSnakeList->begin();
QPoint unit(1,1);
while(item != m_lSnakeList->end())
{
QPoint beg = GetConvPoint(*item ) + unit ;
QRect rect(beg,beg + QPoint(m_iUnitage - 2,m_iUnitage - 2));
p->drawPixmap(rect,img);
item++;
}
}
void SnakeLogic::PaintFood(QPainter *p)
{
QPixmap img("://res/small.bmp");
QPoint unit(1,1);
for(int i = 0; i < m_iFoodNum; i++)
{
QPoint beg = GetConvPoint(m_pFoodArr[i]) + unit ;
QRect rect(beg,beg + QPoint(m_iUnitage - 2,m_iUnitage - 2));
p->drawPixmap(rect,img);
}
}
void SnakeLogic::CreateFood() //ʳ
{
int i,j;
while(1)
{
while(1)
{
i = qrand()%m_iNumX;
if(i > 0 && i < m_iNumX )
break;
}
while(1)
{
j = qrand()%m_iNumY;
if(j > 0 && j < m_iNumY)
break;
}
if(m_icoortable[j][i] == 0)
{
m_icoortable[j][i] = 2;
break;
}
}
QPoint food(i,j);
m_pFoodArr[m_iFoodNum++] = food;
}
QPoint SnakeLogic::GetConvPoint(QPoint sourcePos)
{
return sourcePos * m_iUnitage + m_pLeftTop;
}
void SnakeLogic::Move(QPoint& dir)
{
if(m_bIsPause || m_bIsGameOver)
return;
QPoint tmp(0,0);
if(dir + m_pCurDir == tmp)
{
QPoint newDir;
if(CheckDirection(newDir))
{
m_pCurDir = dir;
}
else
{
m_pCurDir = newDir;
}
m_bListRev = !m_bListRev;
}
else
{
m_pCurDir = dir;
}
Move();
}
void SnakeLogic::Move()
{
if(m_bIsPause || m_bIsGameOver)
return;
if(!m_lSnakeList || m_lSnakeList->isEmpty())
return;
int ch = CheckMove();
if(ch == -1)
{
this->m_bIsGameOver = true;
emit gameOver();
return ;
}
if(ch == 0)
{
return;
}
if(m_bListRev)
{
m_lSnakeList->pop_front();
QList<QPoint>::const_iterator item = m_lSnakeList->end();
QPoint newPos = *(item - 1) + m_pCurDir;
m_lSnakeList->push_back(newPos);
}
else
{
m_lSnakeList->pop_back();
QList<QPoint>::const_iterator item = m_lSnakeList->begin();
QPoint newPos = *item + m_pCurDir;
m_lSnakeList->push_front(newPos);
}
}
int SnakeLogic::CheckMove()
{
QPoint nextPos;
if(m_bListRev)
{
QList<QPoint>::const_iterator item = m_lSnakeList->end();
nextPos = *(item - 1) + m_pCurDir;
}
else
{
nextPos = *m_lSnakeList->begin() + m_pCurDir;
}
if(m_lSnakeList->contains(nextPos))
return -1;
if(CheckFood(nextPos))
{
return 0;
}
return CheckRect(nextPos)?1:-1;
}
bool SnakeLogic::CheckRect(QPoint& pos)
{
if(pos.x() < 1 || pos.y() < 1 || pos.x() >= m_iNumX -1 || pos.y() >= m_iNumY - 1)
return false;
if(1 == m_icoortable[pos.y()][pos.x()])
return false;
return true;
}
bool SnakeLogic::CheckFood(QPoint& pos)
{
if(m_icoortable[pos.y()][pos.x()] == 2)
{
if(m_bListRev)
{
m_lSnakeList->push_back(pos);
}
else
{
m_lSnakeList->push_front(pos);
}
m_iFoodNum--;
m_icoortable[pos.y()][pos.x()] = 0;
CreateFood();
m_iScore += 10;
emit chageScore(m_iScore);
emit chageLevel(m_iScore/100);
return true;
}
return false;
}
bool SnakeLogic::CheckDirection(QPoint& redir)
{
QPoint tmpDir;
if(m_bListRev)
{
//ͷ
QList<QPoint>::const_iterator item = m_lSnakeList->begin();
tmpDir = *(item + 1) - *item;
}
else
{
//β
QList<QPoint>::const_iterator item = m_lSnakeList->end();
tmpDir = *(item - 2) - *(item - 1);
}
if(tmpDir != m_pCurDir)
{
tmpDir.setX(-tmpDir.x());
tmpDir.setY(-tmpDir.y());
redir = tmpDir;
return false;
}
return true;
}
// slots:
//void SnakeLogic::start()
void SnakeLogic::pause()
{
this->m_bIsPause = !m_bIsPause;
}