Skip to content

lorem-ipsum/game

Repository files navigation

Qt贪吃蛇项目设计文档

大致框架

本程序在Ubuntu 20.04系统上编写,未使用Qt Designer,所有ui设计均通过代码实现。

游戏窗口由类MainWindow实现,它继承自类QMainWindow,因此可以引入菜单栏(Menubar)和工具栏(Toolbar)。MainWindow类有以下若干子元素:

  • bg为类Background的实例,负责绘出40*40的地图。
  • snake为类Snake的实例,负责存放地图上动态生成的一切元素,包括贪吃蛇的身体、随机出现的果实和用户自定义的障碍物。
  • label为类QLabel的实例,负责显示游戏分数和游戏结束的信息。
  • cp为类QLabel的实例,负责显示版权信息。
  • menubar为类QMenuBar的实例,负责生成菜单栏。
  • toolbar为类QToolBar的实例,负责生成工具栏。
  • btns为类QButtonGroup的实例,负责展示和维护开始游戏、暂停等操作按钮。

细节介绍

Background

class Background : public QWidget {
  Q_OBJECT
 public:
  Background(QWidget* parent = nullptr);
  ~Background();

 protected:
  void paintEvent(QPaintEvent* event); // 绘制静态的地图

 private:
};

Bug

Bug类为Snake类的组成部分,提供了随机生成果实与展示果实位置的功能。

#define POS std::pair<int, int>

class Bug : public QWidget {
 public:
  // 构造函数接受动态组件信息,生成果实时检查是否与其他动态组件重叠
  explicit Bug(QList<POS> body, QList<POS> obstacles,
               QWidget* parent = nullptr);
  ~Bug();

  void generateRandomPs();

  POS getPs() const;

  POS ps;
};

Snake

#define POS std::pair<int, int> // 用POS表示单个格点的位置

enum DIR { UP, DOWN, RIGHT, LEFT }; // 用枚举类型DIR表示蛇的前进方向

class Snake : public QWidget {
  Q_OBJECT

 public:
  explicit Snake(QWidget* parent);
  ~Snake();

  QList<POS> getBody() const;
  QList<POS> getObstacles() const;
  DIR getDir() const;
  int getTime() const;
  POS getBug() const;

  void restart(); // 重新开始游戏,将所有动态组件置零即可

  bool validMove(const POS& next); // 判断前进的下一步是否会与障碍或自身相撞

  void load(QJsonArray body, QJsonArray obstacles, QJsonArray bug, DIR dir, int time); // 从文件读入当前状态,调用方负责异常处理和语法分析

  QTimer* timer; // 用来计时

  bool timeToToggleObstacles; // 判断当前时刻用户是否可以自主添加障碍

 protected:
  void paintEvent(QPaintEvent* event); // 绘制一切动态元素,包括蛇身、果实和障碍

  void mousePressEvent(QMouseEvent* event); // 在添加障碍时使用

  void toggleObstacle(int i, int j); // 在添加障碍时使用

 private:
  QList<POS> body_;      // 蛇身
  QList<POS> obstacles_; // 障碍
  DIR dir_;              // 当前蛇的前进方向
  int time_;             // 当前时刻
  Bug* bug;              // 当前时刻果实的位置
  int afterEating_;      // 用于判断蛇是否在进食后的三步以内

 public slots:
  void oneMove();        // 蛇前进一步

  // 以下四个函数当键盘事件请求蛇转向时调用,会检查转向是否合法,若不合法则忽略请求
  void dirUP();
  void dirDOWN();
  void dirRIGHT();
  void dirLEFT();

 signals:
  void gameOver();     // 发出游戏结束的信号
  void timeFlies(int); // 发出时间前进的信号,参数即为当前时刻
};

MainWindow

class MainWindow : public QMainWindow {
  Q_OBJECT

 public:
  MainWindow(QWidget *parent = nullptr);
  ~MainWindow();

  void keyPressEvent(QKeyEvent *event); // 被调用时发送方向键按下的信号

 private:
  Background *bg; // 绘制静态地图
  Snake *snake;   // 绘制动态元素

  // 以下两个函数负责确认是否将按下方向键的事件通知给snake,比如实现暂停时方向键不起作用
  void connectArrowKeysToSnake();
  void disConnectArrowKeysToSnake();

 signals:
  // 当按下方向键时触发以下4个信号
  void UP_pressed();
  void DOWN_pressed();
  void RIGHT_pressed();
  void LEFT_pressed();
};

所有除转向之外的逻辑信息均在MainWindow的构造函数中完成。

其他

  • Save时将局面保存为一个json文件,Load时打开已保存的文件,读取内容并转化为局面。具体来说,json文件中包括蛇身、当前前进方向、障碍位置、果实位置和当前时间。
  • 在鼠标点击按钮时,focus会改变,导致方向键重定向到btns处,无法正常改变蛇的前进方向。因此每次触发按钮之后,要调用snake->setFocus()
  • PushButtonMenubarToolbar处共用一个QAction,可以减少代码冗余,并共享状态。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published