鸿 网 互 联 www.68idc.cn

当前位置 : 服务器租用 > 编程语言开发 > c++ > >

图形绘制

来源:互联网 作者:佚名 时间:2016-07-01 16:52
耍过贪吃蛇的朋友应该都知道运行起来,看着很简单,但是,实际在用代码写的时候,有一个逻辑判断会思考很久~就是贪吃蛇在拐弯的时候,怎么计算在连续多次拐弯的情况下,你绘制出来的贪吃蛇是不会断成几节,而且能够按照正确的路线进行行驶! 1.我这里采用的是
耍过贪吃蛇的朋友应该都知道运行起来,看着很简单,但是,实际在用代码写的时候,有一个逻辑判断会思考很久~就是贪吃蛇在拐弯的时候,怎么计算在连续多次拐弯的情况下,你绘制出来的贪吃蛇是不会断成几节,而且能够按照正确的路线进行行驶!
1.我这里采用的是一个map进行管理,将贪吃蛇所有的点存入到map中,然后进行实时的对数据进行更新
2.其他的话,就没有什么技术难点了,就是如何设计绘制贪吃蛇的位置刷新以及方框、随机原点的绘制;
我采取的是一个定时器的方式,每500ms进行一次刷新;对于绘制的话,需要将代码放置在:paintEvent()这个函数中,你将函数放置在其他位置,绘制都是无效的
源码链接:http://pan.baidu.com/s/1pL3Xq6v 密码:osq8 <无>
#ifndef SNAKE_H
#define SNAKE_H

#include <QMainWindow>
#include <QGraphicsView>
#include <QTimer>
#include <QKeyEvent>
#include <map>
using namespace std;

namespace Ui {
class CSnake;
}

enum dirType
{
    leftPos = 1,
    topPos = 2,
    rightPos = -1,
    bottomPos = -2,
    invaild = 0
};

typedef struct Point
{
    int     iX;
    int     iY;
    dirType    type;

    Point()
    {
        iX = 0;
        iY = 0;
        type = invaild;
    }
}stPoint;

class CSnake : public QMainWindow
{
    Q_OBJECT

public:
    explicit CSnake(QWidget *parent = 0);
    ~CSnake();

    /***********************************
     *  功  能:界面初始化函数
     *  参  数:无
     *  返回值:无
     ***********************************/
    void init();

    /***********************************
     *  功  能:绘制线条
     *  参  数:无
     *  返回值:无
     ***********************************/
    virtual void paintEvent(QPaintEvent *event);

    /***********************************
     *  功  能:随机的产生一个白点
     *  参  数:无
     *  返回值:无
     ***********************************/
    void showPoint();

    /***********************************
     *  功  能:显示蛇
     *  参  数:无
     *  返回值:无
     ***********************************/
    void showSnake();

    /***********************************
     *  功  能:键盘按下事件
     *  参  数:无
     *  返回值:无
     ***********************************/
    void keyPressEvent(QKeyEvent  *event) ;

    /***********************************
     *  功  能:判断蛇是否吃到了蛇
     *  参  数:无
     *  返回值:无
     ***********************************/
    void checkFood();

private:
    Ui::CSnake *ui;

    //标志位
    //是否需要刷新贪吃蛇
    bool            bInit;

    //是否需要刷新随机白点
    bool            bFlag;

    //设置背景颜色
    QPalette*       palette;

    //产生点的位置
    int             iX;
    int             iY;

    //定义蛇的运行方向
    dirType         curType;
    //存储之前的运行方向
    dirType         preType;

    //记录蛇的长度
    int             iLen;

    //用该map进行蛇的绘制
    map<int,stPoint> mapSnake;

    //用一个定时器让蛇进行轨迹的运行
    QTimer*         timer;


private slots:
    /***********************************
     *  功  能:让蛇进行运动
     *  参  数:无
     *  返回值:无
     ***********************************/
    void snakeRun();
};

#endif // SNAKE_H
#include "snake.h"
#include "ui_snake.h"
#include <QMessageBox>
#include <QtAlgorithms>
#include <QTime>

#define ILARGE  20

CSnake::CSnake(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::CSnake)
{
    ui->setupUi(this);

    bFlag = true;
    bInit = false;

    //设置整个背景为黑色
    palette = new QPalette;
    palette->setColor(QPalette::Background, QColor(100,100,100));
    this->setPalette(*palette);
    iLen = 0;

    //定时器的初始化
    timer = new QTimer;
    connect(timer,SIGNAL(timeout()),this,SLOT(snakeRun()));
    timer->start(500);

    //初始化
    init();
}

CSnake::~CSnake()
{
    delete ui;
    if(timer)
    {
        delete timer;
        timer = NULL;
    }
}

void CSnake::init()
{
    //判断蛇的运行轨迹
    //判断X轴运行轨迹
    if(iX <= 4)
    {
        curType = bottomPos;
    }
    else if(iX >= rect().height() / ILARGE - 4)
    {
        curType = topPos;
    }
    //判断Y轴运行轨迹
    if(iY <=4)
    {
        curType = rightPos;
    }
    else if(iY >= rect().width() / ILARGE - 4)
    {
        curType = leftPos;
    }
    curType = topPos;
}

void CSnake::paintEvent(QPaintEvent *event)
{
    //用线条绘制表格
    QPainter painter(this);
    QPen pen;
    pen.setColor(Qt::black);
    painter.setPen(pen);
    int sum = rect().height() / ILARGE ;
    //绘制横向的线条
    for(int i = 0 ; i < sum ; i++)
    {
        painter.drawLine(0,i*ILARGE,rect().width(),i*ILARGE);
    }

    //绘制纵向的线条
    sum = rect().width() / ILARGE ;
    for(int i = 0 ;i < sum ; i++)
    {
        painter.drawLine(i*ILARGE,0,i*ILARGE,rect().height());
    }

    //获得点的位置
    showPoint();

    //绘制点,并让尽量显示在方框中间
    painter.setBrush(Qt::white);
    painter.drawEllipse(iX * ILARGE + 5,iY * ILARGE + 5,10,10);

    //显示蛇
    showSnake();

    //遍历转弯点
    map<int,stPoint>::iterator iter;
    for(iter = mapSnake.begin() ; iter != mapSnake.end() ; iter++)
    {
        //如果是头的话,将蛇的头用红色的方框表示
        if(iter == mapSnake.begin())
        {
            painter.setBrush(Qt::red);
        }
        else
        {
            painter.setBrush(Qt::white);
        }
        painter.drawRect(iter->second.iX * ILARGE,iter->second.iY * ILARGE , ILARGE , ILARGE);
    }

}

void CSnake::showPoint()
{
    //随机产生一个白点
    if(bFlag)
    {
        int iWidth = rect().width() / ILARGE ;
        int iHeight = rect().height() / ILARGE;

        //让时间作为随机的种子,这样才能相对更随机
        QTime time;
        time= QTime::currentTime();
        qsrand(time.msec()+time.second()*1000);
        iX = qrand()% iWidth;
        iY = qrand() % iHeight;

        bFlag = false;
    }
}

void CSnake::showSnake()
{
    //判断蛇是否吃到了东西
    checkFood();

    if(!bInit)
    {
        //随机产生一个白色方点
        int iWidth = rect().width() / ILARGE ;
        int iSnakeX = rand() % iWidth;
        int iHeight = rect().height() / ILARGE;
        int iSnakeY = rand() % iHeight;
        bInit = true;
        stPoint pos;

        //记录蛇的位置信息
        pos.iX = iSnakeX;
        pos.iY = iSnakeY;
        pos.type = curType;
        mapSnake.insert(make_pair(iLen, pos));
        iLen++;
    }
    else
    {

        map<int,stPoint>::iterator iter ;

        //下一个需要紧随上一个步伐走
        for(int i = iLen - 1 ; i >= 0 ; i--)
        {
            int iTmp = i;
            iTmp--;
            if(iTmp >= 0)
            {
                mapSnake[i].iX =  mapSnake[iTmp].iX;
                mapSnake[i].iY =  mapSnake[iTmp].iY;
                mapSnake[i].type =  mapSnake[iTmp].type;
            }
        }


        iter = mapSnake.begin();
        //判断下一帧的运行方向
        switch (curType)
        {
        //x轴减少,Y轴不变
        case leftPos:
        {
            iter->second.iX--;
            break;
        }
        //x不变,Y轴减少
        case topPos:
        {
            iter->second.iY--;
            break;
        }
        //x增加,Y轴不变
        case rightPos:
        {
            iter->second.iX++;
            break;
        }
        //x增加,Y轴不变
        case bottomPos:
        {
            iter->second.iY++;
            break;
        }
        default:
            break;
        }
    }
}

void CSnake::keyPressEvent(QKeyEvent *event)
{
    map<int,stPoint>::iterator iter;
    iter = mapSnake.begin();

    if(event->key() == Qt::Key_Left)
    {
        curType = leftPos;
    }
    else if(event->key() == Qt::Key_Up)
    {
        curType = topPos;
    }
    else if(event->key() == Qt::Key_Right)
    {
        curType = rightPos;
    }
    else if(event->key() == Qt::Key_Down)
    {
        curType = bottomPos;
    }
    //改变头的方向
    iter->second.type = curType;

}

void CSnake::checkFood()
{
    map<int,stPoint>::iterator iBegin;
    iBegin = mapSnake.begin();
    if(iX == iBegin->second.iX && iY == iBegin->second.iY)
    {
        bFlag = true;
        //找到最后一个点,根据最后点的运行方向,在后面添加方框
        map<int,stPoint>::iterator iter;
        iter = mapSnake.end();
        iter--;
        stPoint pos;
        switch (iter->second.type)
        {
        //往左走,则在右边的方框添加
        case leftPos:
        {
            //y不变,x增加
            pos.iX = iter->second.iX + 1;
            pos.iY = iter->second.iY;
            pos.type = iter->second.type;
            break;
        }
        case topPos:
        {
            //x不变,y增加
            pos.iX = iter->second.iX ;
            pos.iY = iter->second.iY + 1;
            pos.type = iter->second.type;
            break;
        }
        case rightPos:
        {
            //y不变,x增加
            pos.iX = iter->second.iX - 1;
            pos.iY = iter->second.iY;
            pos.type = iter->second.type;
            break;
        }
        case bottomPos:
        {
            //y不变,x增加
            pos.iX = iter->second.iX ;
            pos.iY = iter->second.iY - 1;
            pos.type = iter->second.type;
            break;
        }
        default:
            break;
        }
        mapSnake.insert(make_pair(iLen , pos));
        iLen++;
    }
}

void CSnake::snakeRun()
{
    //判断,如果相加为0,代表死掉
    int sum = curType + preType;
    if( sum == 0)
    {
        timer->stop();
        QMessageBox::warning(0 , "提示" , "Game over!");
        //程序结束
        qApp->quit();
    }
    else
    {
        //先改变之前存储的方向
        preType = curType;

        int iWidth = rect().width() / ILARGE ;
        int iHeight = rect().height() / ILARGE;

        //判断是否撞墙死亡
        if(mapSnake[0].iX < 0 || mapSnake[0].iY < 0 ||
                mapSnake[0].iX > iWidth || mapSnake[0].iY > iHeight)
        {
            timer->stop();
            QMessageBox::warning(0 , "提示" , "Game over!");
            //程序结束
            qApp->quit();
        }
        //判断是否自己把自己咬住了
        map<int,stPoint>::iterator iter;
        bool bDead = false;
        iter = mapSnake.begin();
        for( iter++ ; iter != mapSnake.end() ; iter++)
        {
            if(mapSnake[0].iX == iter->second.iX && mapSnake[0].iY == iter->second.iY)
            {
                bDead = true;
                break;
            }
        }
        if(bDead)
        {
            timer->stop();
            QMessageBox::warning(0 , "提示" , "Game over!");
            //程序结束
            qApp->quit();
        }

        //让蛇按照之前的当前的运行方向进行运动
        update();
    }
}
#include "snake.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    CSnake w;
    w.show();
    w.setWindowTitle("贪吃蛇——made by HNN");
    return a.exec();
}
上一篇:1
下一篇:C++PrimerPlus第七章课后练习
网友评论
<