关闭

贪吃蛇

197人阅读 评论(0) 收藏 举报
分类:
这里主要是食物的防止和蛇的游走,蛇我用QGraphicsPathItem,
然后用QList<QPointF> snake来确定蛇身体坐标
场景坐标为400X400,左上角定点坐标为(0,0),右下角点坐标为(400,400)


每个格子都占据20X20的QRectF,蛇身的坐标为格子的中心
距离场景最左上角的格子坐标(0,0,20,20),如果蛇头位于这个格子
则有*(snake.begin()) == QPointF(10,10)
即蛇身体所处格子的坐标为 (格子场景坐标.x()+10,格子场景坐标.y()+10)


另外在写代码的时候需要很多变量,一般来说使用枚举会直观性,但由于很多变量需要计算,而且我在写代码是经常遇到需要额外加一些,所以我这里使用了int +注释的形式
比如代表蛇运动方向,一般可能会
emun {left,up,down,right};类似这样

我在代码里是
int turns; //这里turns代表蛇的方向,取值-1=左,1=右,-2=上,2=下
这种形式

食物的坐标同


开始的时候蛇和食物位置固定,在游戏菜单中,
新游戏:建立一个新游戏
开始:游戏开始(蛇开始运动)
暂停:游戏暂停(蛇停止运动);
开始和暂停选项互斥;


在选项一栏里可以调整游戏选项(蛇的运动间隔,有0.9秒,0.6秒,0.3秒)蛇身体有3个颜色可选
这里当点击 新游戏 后可以通过点击 难度 来调整游戏,当点击开始后,该 难度选项为不可用状态(无论暂停还是开始),只有再次 新游戏 后才能再次可用,这里避免了扫雷游戏中途调整游戏难度导致游戏问题
 
撞墙或吃到自己游戏判负

游戏胜利的条件是吃满10个食物

其实这蛇在装到强或吃到自己是都会发生一些形状上的变化贪吃蛇 - 板烧鱿鱼 - 我只是个路人甲,别在意我,但由于此时游戏判断结束,所以我用图片掩盖这些贪吃蛇 - 板烧鱿鱼 - 我只是个路人甲,别在意我

其实2个图片游戏启动时就已经位于场景中,但位于QgraphicsView之外,这里通过信号与槽把图片移动坐标(到view)内,新建游戏时在把他们移到view之外贪吃蛇 - 板烧鱿鱼 - 我只是个路人甲,别在意我

这里是蛇围绕这食物

 这2个图说明碰撞判断符合要求(其实这里蛇环绕食物的碰撞有些问题,所以我使用了坐标碰撞而不是QGraphicsItem的碰撞函数贪吃蛇 - 板烧鱿鱼 - 我只是个路人甲,别在意我)
~~~~
http://pan.baidu.com/s/1o6upbHg
注意这里文件是我在linux(ubuntu14.04)下写的文件,在win系统下编译没问题,但打开可能会出现乱码.如果有这里问题,下面有源代码(PS:源代码里没有.pro文件的源代码)
这里pro文件写好了,编译的时候记得打开编译器的c++11选择(如果你没开的话)
~~~~~以下是源代码~~~~~~

GameMap.h

#ifndef GAMEMAP_H_
#define GAMEMAP_H_
#include<QDialog>
#include<QPointF>
#include<QGraphicsView>
#include<QGraphicsScene>
#include<QGraphicsRectItem>
#include<QGraphicsPathItem>   //用于蛇以及周围的墙
#include<QGraphicsEllipseItem>  //用于食物
#include<QGraphicsPixmapItem>
#include<QTimer>
#include<QKeyEvent>
class GameMap:public QDialog
{
  Q_OBJECT
 private:
  QGraphicsScene* scene;
  QGraphicsView* view;
  QGraphicsPixmapItem* winPix;
  QGraphicsPixmapItem* lostPix;
  QGraphicsRectItem* upWalls;  //用于四周的墙
  QGraphicsRectItem* downWalls; 
  QGraphicsRectItem* leftWalls;
  QGraphicsRectItem* rightWalls; 
  QGraphicsRectItem* food;  //食物
  qreal food_x;
  qreal food_y;  //这2个坐标存放食物在地图上的坐标,用于蛇吃食物的碰撞判断
  bool hasFood;  //表示地图上是否有食物
  QGraphicsPathItem* snake;  //蛇
  QList<QPointF> RunPath;  //蛇运动时的坐标
  QPointF snakeTail;  //储存上次运动的尾部,用于吃到食物后蛇身体(在尾部)加一格
  QPainterPath snakePath;  //蛇自身的坐标
  QTimer* times;  //时间控制器
  int keepGo;  //游戏状态,0=可以继续,1=撞墙/吃到自己失败,2=吃满食物胜利
  int getFood;  //食物数量,吃到10个为胜利
  int levels;  //通过控制时间长短来控制游戏难度
  int color;  //定义蛇的颜色,1=白,2=蓝,3=红
  int turns;  //输入指令的方向 1=上,-1= 下 -2=左 2=右
  int running;  //蛇正在运动的方向,数值同turns,确保蛇不会反方向运动
  void forPath();  //将运动坐标转化为蛇身坐标
 protected:
  void keyPressEvent(QKeyEvent* event);  //点击事件,响应键盘的A W S D
 public:
  GameMap(QWidget* parent = 0);  //构造函数
 public slots:
  void newGame();  //新建游戏(重置蛇,食物等);
  void startGame();
  void stopGame();  //停止游戏,用于蛇吃到自己或撞墙
  void newOption(int,int);
 private slots:
  void keepRun();  //蛇运动
  void giveFood();  //放置一个新的食物
  void eating();  //这个函数包括蛇吃到自己,食物,墙,3种情况
 signals:
  void lost();
  void finishChange();
};
#endif


GameMap.cxx

#include"GameMap.h"
#include<QPixmap>
#include<QPainter>
#include<QBrush>
#include<QPainterPath>
#include<QHBoxLayout>
#include<ctime>
#include<QDebug>
GameMap::GameMap(QWidget* parent):QDialog(parent)
{
  running = -2;//蛇默认向左移动
  turns = -2;  
  levels = 900;  //默认为最简单,蛇0.9秒移动一格
  color = 1;  //默认蛇为白色
  keepGo = 0;  //默认可以继续游戏
  getFood = 0;  //默认吃到0个食物
  //时间控制
  times = new QTimer(this);
  times->setInterval(levels);
  connect(times,SIGNAL(timeout()),this,SLOT(eating()));
  connect(this,SIGNAL(lost()),this,SLOT(stopGame()));
  scene = new QGraphicsScene;
  scene->setSceneRect(-3,-3,406,406);  //设计地图大小为400X400周围3格的空隙作为墙
  //设置图层背景
  QPixmap pix(20,20);
  QPainter pt(&pix);
  pt.setBrush(QBrush(Qt::gray));
  pt.drawRect(0,0,20,20);
  scene->setBackgroundBrush(QBrush(pix));
  view = new QGraphicsView(scene);
  //放置第一块食物
  food = new QGraphicsRectItem(0,0,18,18);
  food->setBrush(QBrush(Qt::yellow));
  scene->addItem(food);
  food_x = 100;
  food_y = 100;  //食物最初坐标
  food->setPos(food_x+1,food_y+1);
  hasFood = true;  //确认有食物
 //放置周围的墙
  upWalls = new QGraphicsRectItem(0,0,406,2);
  upWalls->setBrush(QBrush(Qt::black));
  scene->addItem(upWalls);
  upWalls->setPos(-3,-3);
  leftWalls = new QGraphicsRectItem(0,2,2,404);
  leftWalls ->setBrush(QBrush(Qt::black));
  scene->addItem(leftWalls);
  leftWalls->setPos(-3,-3);
  downWalls = new QGraphicsRectItem(2,404,404,2);
  downWalls->setBrush(QBrush(Qt::black));
  scene->addItem(downWalls);
  downWalls->setPos(-3,-3);
  rightWalls = new QGraphicsRectItem(404,2,2,402);  //墙的路径,为401X401外围2格子
  rightWalls->setBrush(QBrush(Qt::black));
  scene->addItem(rightWalls);
  rightWalls->setPos(-3,-3);
  //放置最初的蛇 
  snake = new QGraphicsPathItem;
  scene->addItem(snake);
  for(int i = 0 ; i < 5 ; ++i)
  {
   QPointF A((10+i)*20+10,10*20+10);
    RunPath.append(A);
  }
  forPath();
  snakeTail = RunPath.last();  //先储存蛇.
  snake->setPos((*RunPath.begin()).x(),(*RunPath.begin()).y());
  snake->setPath(snakePath);
  snake->setBrush(QBrush(Qt::white));
  //设置游戏结束(胜利or失败)后的图片
  QPixmap winner(tr(":/images/win.jpg"));
  winPix = new QGraphicsPixmapItem(winner.scaled(406,406));
  scene->addItem(winPix);
  winPix->setPos(0,500);  //确保游戏过程中图片在view的外面
  QPixmap los(tr(":/images/fail.jpg"));
  lostPix = new QGraphicsPixmapItem(los.scaled(406,406));
  scene->addItem(lostPix);
  lostPix->setPos(500,0);  //确保游戏过程中图片在view的外面
  //安装
  QHBoxLayout* main_layout = new QHBoxLayout;
  main_layout->addWidget(view);
  setLayout(main_layout);
}
void GameMap::forPath()
{
  QPainterPath A;
  snakePath = A;  //QPainterPath找不到清空的函数,只能用这个本办法。。
  //这个函数作用是将scene上的坐标,转化为蛇的坐标
  int disX = (*(RunPath.begin())).x();
  int disY = (*(RunPath.begin())).y();
  for(auto A : RunPath)
  {
    QPointF mid(A.x()-disX , A.y()-disY);
    snakePath.addRect(mid.x()-10,mid.y()-10,20,20);
  }
}
void GameMap::newGame()
{
  times->stop();
  winPix->setPos(0,500);
  lostPix->setPos(500,0);  //先一开图片
  keepGo = 0;
  getFood = 0;  //设置正常游戏状态,获得食物数量为0
  turns = -2;
  running = -2;  //每次新游戏开始蛇的运动方向固定向左
  times->setInterval(levels); //设置新的时间间隔
  //设置颜色
  if(color == 1)
   snake->setBrush(QBrush(Qt::white));
  else if(color == 2)
    snake->setBrush(QBrush(Qt::blue));
   else if(color == 3)
    snake->setBrush(QBrush(Qt::red)); 
  if(!(RunPath.isEmpty()))
   RunPath.clear();  //如果坐标不为空,先清空坐标
  for(int i = 0 ; i < 5 ; ++i)
  {
   QPointF A((10+i)*20+10,10*20+10);
    RunPath.append(A);
  }
  forPath();
  snake->setPos((*RunPath.begin()).x(),(*RunPath.begin()).y());//先放置一条初始状态的蛇
  snake->setPath(snakePath);
  //放置一块食物
  hasFood = true;
  food_x = 100;  //新游戏第一个食物出现位置固定
  food_y = 100;
  food->setPos(food_x+1,food_y+1);
}
void GameMap::keepRun()
{
  snakeTail = RunPath.last();  //先储存蛇.
  qreal x = (*(RunPath.begin())).x();
  qreal y = (*(RunPath.begin())).y();  //获取头部坐标
  if(running+turns != 0)
   running = turns;      //通过数字大小判断方向,如果操作的方向和原来的运动放不完全相反,则响应操作
  if(running == 1)         //如操作与蛇运动方向完全相反,如蛇运动为1(即朝左边),而操作为-1(即朝右边)
   y = y - 20;             //此时蛇的运动方向不变
  if(running == -1)
   y = y + 20;
  if (running == -2)
   x = x - 20;
  if(running == 2)
   x = x + 20;
  QPointF head(x,y);
  RunPath.push_front(head);
  RunPath.pop_back();
  forPath();
  snake->setPos((*RunPath.begin()).x(),(*RunPath.begin()).y());
  snake->setPath(snakePath);
}
void GameMap::keyPressEvent(QKeyEvent* event)
{
  if(event->key() == Qt::Key_W)
   turns = 1;   
  if(event->key() == Qt::Key_S)
   turns = -1;   
  if(event->key() == Qt::Key_A)
   turns = -2;  
  if(event->key() == Qt::Key_D)
   turns = 2;  
  QDialog::keyPressEvent(event);
}
void GameMap::giveFood()
{
  srand(unsigned(time(0)));  //生成随机数种子
  QPainterPath mid;
  qreal x = 0;
  qreal y = 0;
  for(int i ;  ; ++i)
  {
   int agains = 0;
   x = rand()%19;
   y = rand()%19;
   for(auto A : RunPath)  //确保食物出现在蛇身体周围外至少一格
   {
    if(x*20+10 == A.x() and y*20+10 == A.y())
      ++agains;
   }
    if(agains == 0)  //表示没有相同坐标
     break;
    else continue;
  }
  food_x = x*20;
  food_y = y*20;
  food->setPos(food_x+1,food_y+1);
}
void GameMap::eating()
{
  keepRun();  //先让蛇走一步
  //首先判断有没有撞墙
  if(snake->collidesWithItem(upWalls) or snake->collidesWithItem(downWalls) or snake->collidesWithItem(leftWalls) or snake->collidesWithItem(rightWalls))
      {
       keepGo = 1;
       emit lost();
       return;
      }
  //然后判断有木有吃到自己
  QPointF head = *(RunPath.begin());
  int i = 0;
  for(auto A : RunPath)
   {
    if(head == A)
     ++i;
   }
  if(i == 2) 
   {
     keepGo = 1;
     emit lost();
     return;
   }
   
  //判断有没有吃到食物,吃到了尾部+1
  int m = 0;
  for(auto A : RunPath)
  {
   if(A.x() == food_x+10 and A.y() == food_y+10)  //坐标相同就说明吃到食物了
    {
     ++m;
     break;
    }
  }  
  if(m == 1)
   {
    ++getFood;
    hasFood = false;
    RunPath.append(snakeTail);
    forPath();
    snake->setPos((*RunPath.begin()).x(),(*RunPath.begin()).y());
    snake->setPath(snakePath);  //在刷新一次蛇,是身体(在尾部)多一格
   }
  if(hasFood == false)
   {
    hasFood = true;
    giveFood();  //重新放置一块食物
   }
  if(getFood == 10)  //胜利条件,获得10个食物
   {
    keepGo = 2;
    emit lost();
   }
}
void GameMap::stopGame()
{
  times->stop();
  if(keepGo == 1)
   lostPix->setPos(-3,-3);  //显示失败图片
  if(keepGo == 2)
   winPix->setPos(-3,-3);  //显示胜利图片
}
void GameMap::startGame()
{
  if(keepGo == 0)  //判断是否可以继续游戏
  times->start();
}
void GameMap::newOption(int le , int co)
{
  levels = le;
  color = co;
  emit finishChange();  //完成设置更改
}


GameOption.h
#ifndef GAMEOPTION_H_
#define GAMEOPTION_H_
#include<QDialog>
#include<QRadioButton>
#include<QGroupBox>
#include<QPushButton>
#include<QCloseEvent>
class GameOption:public QDialog
{
  Q_OBJECT
 private:
  int levels;
  int color;  // 保存选项数值
  QGroupBox* level_box;
  QRadioButton* easy_button;
  QRadioButton* mid_button;
  QRadioButton* hard_button;
  QGroupBox* color_box;
  QRadioButton* white_button;
  QRadioButton* blue_button;
  QRadioButton* red_button;  //用于颜色和游戏难度
  QPushButton* ok_button;
 public:
  GameOption(QWidget* parent = 0);
 public slots:
  void changeOption();
 signals:
  void newOption(int,int);
 protected:
  void closeEvent(QCloseEvent*);  //重写关闭事件,配合主窗体中的模态调用
}; 
#endif

GameOption.cxx
#include"GameOption.h"
#include<QHBoxLayout>
#include<QVBoxLayout>
GameOption::GameOption(QWidget* parent):QDialog(parent)
{
  levels = 1;
  color = 1;  //默认为简单难度,白色蛇体,和游戏窗体对应
  //安装布局难度框
  easy_button = new QRadioButton(tr("简单"));
  easy_button->setChecked(true);  //默选为简单
  mid_button = new QRadioButton(tr("一般"));
  hard_button = new QRadioButton(tr("困难"));
  level_box = new QGroupBox(tr("游戏难度"));
  QVBoxLayout* level_layout = new QVBoxLayout;
  level_layout->addWidget(easy_button);
  level_layout->addWidget(mid_button);
  level_layout->addWidget(hard_button);
  level_box->setLayout(level_layout);
  //安装颜色选择框
  white_button = new QRadioButton(tr("白色"));
  white_button->setChecked(true);  //默选白色
  blue_button = new QRadioButton(tr("蓝色"));
  red_button = new QRadioButton(tr("红色"));
  color_box = new QGroupBox(tr("颜色选择"));
  QVBoxLayout* color_layout = new QVBoxLayout;
  color_layout->addWidget(white_button);
  color_layout->addWidget(blue_button);
  color_layout->addWidget(red_button);
  color_box->setLayout(color_layout);
  //下方确定按钮布局
  ok_button = new QPushButton(tr("确定"));
  connect(ok_button,SIGNAL(clicked()),this,SLOT(hide()));  //点击确定,影藏窗体
  connect(ok_button,SIGNAL(clicked()),this,SLOT(changeOption()));
  QHBoxLayout* button_layout = new QHBoxLayout;
  button_layout->addStretch();
  button_layout->addWidget(ok_button);
  //整体布局
  QHBoxLayout* option_layout = new QHBoxLayout;
  option_layout->addWidget(level_box);
  option_layout->addWidget(color_box);
  QVBoxLayout* main_layout = new QVBoxLayout;
  main_layout->addLayout(option_layout);
  main_layout->addLayout(button_layout);
  setLayout(main_layout);
  setWindowTitle(tr("游戏选项"));
  main_layout->setSizeConstraint(QLayout::SetFixedSize);  //固定大小
}
void GameOption::changeOption()
{
  //难度
  if(easy_button->isChecked())
   levels = 900;
  if(mid_button->isChecked())
   levels = 600;
  if(hard_button->isChecked())
   levels = 300;    //蛇每次移动的事件间隔(毫秒)
  //颜色
  if(white_button->isChecked())
   color = 1;
  if(blue_button->isChecked())
   color = 2;
  if(red_button->isChecked())
   color = 3;
  emit newOption(levels,color);
}
void GameOption::closeEvent(QCloseEvent* event)
{
  changeOption();
  hide();//关闭该窗口只是影藏
  QDialog::closeEvent(event);
}


GameWindow.h

#ifndef GAMEWINDOW_H_
#define GAMEWINDOW_H_
#include<QMainWindow>
#include<QMenu>
#include<QMenuBar>
#include<QAction>
#include"GameMap.h"
#include"GameOption.h"
#include"GameWord.h"
class GameWindow:public QMainWindow
{
  Q_OBJECT
 private:
  GameMap* game_map;
  GameOption* options;
  GameWord* words;
  QMenuBar* menuBars;  //菜单栏
  QMenu* game_menu;
  QMenu* option_menu;
  QAction* newgame_action;
  QAction* start_action;
  QAction* stop_action;
  QAction* close_action;
  QAction* option_action;
  QAction* word_action;
  void create_action();
  void create_menu();  //创建菜单
 public:
  GameWindow(QWidget* parent = 0);
 private slots:
  void coustom();
  void goStop();
  void goStart();
 public slots:
  void goOption();
};
#endif


GameWindow.cxx
#include<QLayout>
#include"GameWindow.h"
GameWindow::GameWindow(QWidget* parent):QMainWindow(parent)
{
  game_map = new GameMap;
  setCentralWidget(game_map);  //设置中心窗体
  connect(game_map,SIGNAL(finishChange()),this,SLOT(goOption()));
  options = new GameOption(this);  //设置选项对话框
  connect(options,SIGNAL(newOption(int,int)),game_map,SLOT(newOption(int,int)));
  words = new GameWord(this);
  create_action();
  create_menu();
  setWindowTitle(tr("贪吃蛇"));
  setWindowIcon(QIcon(tr(":/images/read.png")));
  layout()->setSizeConstraint(QLayout::SetFixedSize);  //固定大小
}
void GameWindow::create_action()
{
  newgame_action = new QAction(tr("新建游戏"),this);
  newgame_action->setStatusTip(tr("建立新游戏"));
  newgame_action->setIcon(QIcon(tr(":/images/begin.png")));
  connect(newgame_action,SIGNAL(triggered()),options,SLOT(changeOption()));
 
  start_action = new QAction(tr("开始"),this);
  start_action->setIcon(QIcon(tr(":/images/snake.png")));
  connect(start_action,SIGNAL(triggered()),game_map,SLOT(startGame()));
  connect(start_action,SIGNAL(triggered()),this,SLOT(goStart()));

  stop_action = new QAction(tr("暂停"),this);
  stop_action->setStatusTip(tr("你可以点击此选项来暂停游戏"));
  stop_action->setEnabled(false);  //游戏未开始时无法使用暂停按钮
  connect(stop_action,SIGNAL(triggered()),game_map,SLOT(stopGame()));
  connect(stop_action,SIGNAL(triggered()),this,SLOT(goStop()));

  close_action = new QAction(tr("关闭"),this);
  close_action->setStatusTip(tr("关闭游戏"));
  connect(close_action,SIGNAL(triggered()),this,SLOT(close()));
  
  option_action = new QAction(tr("自定义"),this);
  option_action->setStatusTip(tr("设置游戏难度以及外观"));
  connect(option_action,SIGNAL(triggered()),this,SLOT(coustom()));

  word_action = new QAction(tr("说明"),this);
  connect(word_action,SIGNAL(triggered()),words,SLOT(exec()));
}
void GameWindow::create_menu()
{
  game_menu = new QMenu(tr("游戏"),this);
  game_menu->addAction(newgame_action);
  game_menu->addAction(start_action);
  game_menu->addAction(stop_action);
  game_menu->addSeparator();
  game_menu->addAction(close_action);
  option_menu = new QMenu(tr("选项"),this);
  option_menu->addAction(option_action);
  option_menu->addAction(word_action);
  menuBars = menuBar();
  menuBars->addMenu(game_menu);
  menuBars->addMenu(option_menu);
  statusBar();  //建立状态栏
}
void GameWindow::coustom()
{
  options->exec();
}
void GameWindow::goStart()  //这2个槽确保 开始 暂停 这2个菜单在同一时间只有1个可用
{
  start_action->setEnabled(false);
  stop_action->setEnabled(true);
  option_action->setEnabled(false);  //一旦游戏开始后就无法更改设置
}
void GameWindow::goStop()
{
  start_action->setEnabled(true);
  stop_action->setEnabled(false);
}
void GameWindow::goOption()
{
  start_action->setEnabled(true);
  stop_action->setEnabled(false);
  option_action->setEnabled(true);  //只有新建游戏有才能进行游戏难度选择
  game_map->newGame();  //建立新游戏
}


GameWord.h

#ifndef GAMEWORD_H_
#define GAMEWORD_H_
#include<QDialog>
#include<QTextEdit>
#include<QCloseEvent>
class GameWord:public QDialog
{
 private:
  QTextEdit* texts;
 public:
  GameWord(QWidget* parent = 0);
 protected:
  void closeEvent(QCloseEvent*);
};
#endif


GameWord.cxx

#include"GameWord.h"
#include<QHBoxLayout>
GameWord::GameWord(QWidget* parent):QDialog(parent)
{
  texts = new QTextEdit;
  texts->setFixedSize(250,250);
  QString A(tr("1 在自定义选项中可以调节难度"));
  QString B(tr("2 新建游戏后,必须点击“开始”后才能开始游戏."));
  QString C(tr("3 吃满10个食物即可获得胜利."));
  QString D(tr("4 使用| W.上 S.下 A.左 D.右 |键来操作方向"));
  texts->append(A);
  texts->append(B);
  texts->append(C);
  texts->append(D);
  texts->setReadOnly(true);  //设置为不可用,放置修改内容
  QHBoxLayout* main_layout = new QHBoxLayout;
  main_layout->addWidget(texts);
  setLayout(main_layout);
  main_layout->setSizeConstraint(QLayout::SetFixedSize);  //固定大小
  setWindowTitle(tr("游戏说明"));
}
void GameWord::closeEvent(QCloseEvent* event)
{
  hide();
  QDialog::closeEvent(event);
}


main.cxx

#include<QApplication>
#include"GameWindow.h"
int main(int argc , char** argv)
{
  QApplication app(argc,argv);
  GameWindow A;
  A.show();
  return app.exec();
}


pix.qrc

<RCC>
<qresource>
<file>images/fail.jpg</file>
<file>images/win.jpg</file>
<file>images/title.png</file>
<file>images/begin.png</file>
<file>images/read.png</file>
<file>images/snake.png</file>
</qresource>
</RCC>


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:8046次
    • 积分:51
    • 等级:
    • 排名:千里之外
    • 原创:78篇
    • 转载:0篇
    • 译文:0篇
    • 评论:1条
    文章分类
    最新评论
  • 学生管理系统

    qq_20553613: 不错,用txt方式模拟数据库。可以改用MySQL实现,加入搜索等功能;代码量和逻辑容易实现多了。另外...