C++ 加QT 框架 使用 QWidget 完成简易版贪吃蛇

首先说一下实现思路:

四个类

蛇 、食物、块 、Widget(主类)
可以将蛇看成一个一个的块的组成 。

块类 功能

记录当前坐标 、上一个块、下一个块的

蛇类 功能

记录蛇的位置(蛇头和蛇身)、 移动、吃、 换方向

食物类 功能

记录食物出现位置。以及要出现的位置

Widget主类

Widget主类相当于上帝,在这个类里面需要实现 创建一条蛇,创建一个食物,在蛇移动的时候观察是否碰到墙上、是否吃到了食物、还有是否玩家对蛇进行了操作(换方向)

block.h

#ifndef BLOCK_H
#define BLOCK_H


class block
{
public:
    block(int x,int y);
    int x ;   // x y 记录这个块的坐标 
    int y ;
    block *next;  // 记录下一个块 
    block * prev; // 记录上一个块
};

#endif // BLOCK_H

block.cpp

#include "block.h"

block::block(int x,int y )
{
    this->x=x;
    this->y=y;
}

snake.h

#ifndef SNAKE_H
#define SNAKE_H
#include "block.h"
#include <QPen>
#include <QPainter>

typedef struct   {
    int x ;
    int y ;
}dir;

class snake 
{
public:
    snake();
    block * snakeHead; // 记录蛇头位置
    block * snakeBody; // 记录蛇身位置  也可以看成是蛇的尾(yi)巴
    bool isMove; // 是否已经移动过
    void init();
    void move();
    void eat();
    void setDir(char s);
    char getS();
    int getNextX();
    int getNextY();
private:
    char s;
    dir direction;
};

#endif // SNAKE_H

snake.cpp

#include "snake.h"
#include <QDebug>
using namespace std;

snake::snake()
{

}
void snake::init()
{
    //初始化蛇头
    snakeHead = new block(1,0);
    //初始化蛇尾
    snakeBody = new block(0,0);
    // 初始化方向
    isMove=true; // 先设置可以移动用来进行初始化 第一步永远向右走一步
    this->setDir('r');
    snakeHead->next=this->snakeBody;
    snakeHead->prev=nullptr;
    snakeBody->prev=this->snakeHead;
    snakeBody->next=nullptr;

}
int snake::getNextX(){
    return snakeHead->x+this->direction.x*1;
};
int snake::getNextY(){
   return snakeHead->y+(this->direction.y*1);
};
void snake::setDir(char s )
{
    // 动一次之后才可以继续设置下一次的方向,不可以在动一次的过程中多次设置
    if( isMove==false){ return ;} // 没有移动 不可以设置
    isMove=false;
    this->s=s;
    switch (s) {
    case 'u':
        this->direction.x=0;
        this->direction.y=-1;
        break;
    case 'd':
        this->direction.x=0;
        this->direction.y=1;
        break;
    case 'l':
        this->direction.x=-1;
        this->direction.y=0;
        break;
    case 'r':
        this->direction.x=1;
        this->direction.y=0;
        break;
    }
}
char snake::getS(){

    return  this->s;
}
void snake::move()
{
    //擦去蛇尾
    // 移动
    int x =  getNextX(); // 下一个节点的位置 x
    int y =  getNextY();// ;下一个节点的位置y
    block *temp=  snakeBody->prev; // 保存最后一个节点
    temp->next=nullptr; // 设置最后一个节点的下一个为空
    snakeBody->x=x;
    snakeBody->y=y;
    snakeBody->next= snakeHead;
    snakeHead->prev=snakeBody;
    snakeBody->prev=nullptr;//
    snakeHead= snakeBody; //头节点替换
    snakeBody = temp;
    isMove=true;// 移动之后才可以设置方向
};
void snake::eat(){
    int x =  getNextX(); // 下一个节点的位置 x
    int y =  getNextY();// ;下一个节点的位置y
    block *temp = new block(x,y);
    temp->next=snakeHead;
    temp->prev= nullptr;
    snakeHead->prev=temp;
    snakeHead=temp;
}

food.h

#ifndef FOOD_H
#define FOOD_H
#include<iostream>

class food
{
public:
    food();
    int x ;
    int y ;
    void init (int x, int y);
};

#endif // FOOD_H

food.cpp

#include "food.h"
#include <time.h>

using namespace std;
food::food( )
{

}
void food::init(int x, int y)
{

    this->x=x;
    this->y=y;
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QLabel>
#include <QTimer>
#include <QPainter>
#include "snake.h"
#include "food.h"
#include <QPen>
#include <block.h>
#include <QKeyEvent>
#include <QDebug>
#include <QColor>
#include <QRectF>
#include <QTime>
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();
    void init();// 初始化函数
    void draw(QPainter &p  );// 画函数
    void initFood();// 初始化食物函数

private:
    Ui::Widget *ui;
    QTimer* mytimer; // 定时器
    snake * mySnake;
    food * f;
protected:
    //  QPainter* mPainter=nullptr; //画家对象
     QPen * mPen=nullptr;// 画笔对象
    void paintEvent(QPaintEvent *event);//画图事件更新函数
    void keyPressEvent(QKeyEvent *);//键盘判定

public slots:
    void doProcessTimeOut();//计时结束后触发的槽


};

#endif // WIDGET_H

widget.cpp


#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    this->setMinimumSize(600,600);
    this->setMaximumSize(600,600);
    this->init();


}
void  Widget::initFood(){
    QTime randtime;
    randtime = QTime::currentTime();
    qsrand(randtime.msec()+randtime.second()*1000); //以当前时间ms为随机种子
    int x = qrand() % 60;
    int y = qrand() % 60;
    f->init(x,y);
    block *temp =  mySnake->snakeHead;
    while (temp!=nullptr) {
        if(temp->x==x&&temp->y==f->y)
        {
            x = qrand() % 60;
            y = qrand() % 60;
            temp= mySnake->snakeHead; // 从头开始
        }else {
            temp= temp->next;

        }
    }
}
void Widget::init(   ){
    mySnake = new snake();
    mySnake->init();
    mytimer = new QTimer(this);
    //
    this->f = new food();
    this->initFood();// 创建食物
    connect(mytimer,&QTimer::timeout, this, [&]() mutable{
        // 获取下一步 的 x y
        int x=  this->mySnake->getNextX(); // 获取下一步的x y
        int y=  this->mySnake->getNextY();

        if(x<0||x>59||y<0||y>59)
        {
            //碰到墙了 游戏结束
             this->mytimer->stop();
        }
        else
        {
            if(x==f->x&&y==f->y)
            {
                // 吃
                 this->mySnake->eat();
                //重新初始化食物
                this->initFood();//
            }
            else
            {
              this->mySnake->move(); // x y  bool
            }

            this->update();
        }

    });
    mytimer->start(100);


}
void Widget::draw(QPainter &p  ){
    // 开始画
    block *temp =  mySnake->snakeHead;
    p.brush();
    this->mPen->setColor(QColor(255, 2,2) ); // 头的颜色 255, 2,2     身体的颜色 35, 146, 1
    p.setPen( *( this->mPen));

    while (temp!=nullptr) {
        double x = static_cast<double>(temp->x) ;
        double y = static_cast<double>(temp->y) ;
        temp= temp->next;
        p.drawRect(QRectF(x*10,y*10,10,10));
        this->mPen->setColor(QColor(35, 146,1) );
        p.setPen( *( this->mPen));

    }
    // 画食物
    this->mPen->setColor(QColor(0, 115,225) );
    p.setPen( *( this->mPen));
    p.drawRect(QRectF(this->f->x*10,this->f->y*10,10,10));


}
void Widget::doProcessTimeOut(){

}

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter p (this);
    this->mPen=new QPen();
    this->draw(p);

}


void Widget::keyPressEvent(QKeyEvent *event)
{
    switch(event->key()){
    case Qt::Key_W  :
        //上

        if( mySnake->getS()=='u' ||mySnake->getS()=='d'){
             return ;
        }
        this->mySnake->setDir('u');

        break;
    case Qt::Key_Up  :
        //上
        if( mySnake->getS()=='u' ||mySnake->getS()=='d'){
             return ;
        }
        this->mySnake->setDir('u');

        break;
    case Qt::Key_S :
        //下
        if( mySnake->getS()=='u' ||mySnake->getS()=='d'){
             return ;
        }
        this->mySnake->setDir('d');

        break;
    case Qt::Key_Down :
        //下
        if( mySnake->getS()=='u' ||mySnake->getS()=='d'){
             return ;
        }
        this->mySnake->setDir('d');

        break;
    case Qt::Key_A:
        //左
        if( mySnake->getS()=='l' ||mySnake->getS()=='r'){
             return ;
        }
        this->mySnake->setDir('l');

        break;
    case Qt::Key_Left:
        //左
        if( mySnake->getS()=='l' ||mySnake->getS()=='r'){
             return ;
        }
        this->mySnake->setDir('l');

        break;
    case Qt::Key_D:
        //右
        if( mySnake->getS()=='l' ||mySnake->getS()=='r'){
             return ;
        }
        this->mySnake->setDir('r');

        break;
    case Qt::Key_Right:
        //右
        if( mySnake->getS()=='l' ||mySnake->getS()=='r'){
             return ;
        }
        this->mySnake->setDir('r');

        break;
    }
}
Widget::~Widget()
{
    delete ui;
}

main.cpp

#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
	//初始化窗口   
    QApplication a(argc, argv);
    Widget w;
    w.show();

    return a.exec();
}

完成效果:
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值