【Qt】贪吃蛇

2024-08-25 19:20
文章标签 qt 贪吃蛇

本文主要是介绍【Qt】贪吃蛇,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

贪吃蛇小游戏

一.项目介绍及演示

1. 项目介绍

2. 项目演示

3. 窗口介绍

3.1 游戏大厅窗口

3.2 游戏关卡选择窗口

3.3 游戏房间窗口

二、创建项目及资源配置

1. 创建项目(QWidget)

​编辑

2. 资源配置(图片声音素材)

三、项目实现

1. 游戏大厅

1.1 重写绘图事件

1.2 设置窗口大小、图标、标题

1.3 设置开始按钮样式

2. 游戏关卡选择

2.1 创建GameSelect类

2.2 连接按钮和窗口跳转

3. 游戏房间

3.1 创建GameRoom类

3.2 对游戏房间数据结构进行封装

3.3 初始化游戏房间界面

3.4 绘制界面窗口

3.5 蛇的移动

3.6 绘制蛇头身体尾巴

3.6 绘制食物与分数

3.7 判定游戏结束

3.8 随机生成食物节点

3.9 创建游戏开始和暂停按钮

3.10 实现定时器的超时槽函数

3.11 设置游戏退出按钮

3.12 获取历史战绩

四.贪吃蛇移动的逻辑讲解

 1.贪吃蛇的一次普通移动:

2.贪吃蛇吃到食物的一次移动:

3.贪吃蛇的持续移动:


贪吃蛇小游戏

一.项目介绍及演示


1. 项目介绍

贪吃蛇游戏规则:简单来说,贪吃蛇游戏规则是玩家通过四个方向键来控制蛇的移动控制其在地图上吃豆子。蛇运动过程中撞到蛇身,则立即结束游戏


2. 项目演示


3. 窗口介绍

3.1 游戏大厅窗口


3.2 游戏关卡选择窗口


3.3 游戏房间窗口

二、创建项目及资源配置


1. 创建项目(QWidget)

在桌面上创建一个名为Snake的文件夹,用于存放项目代码

新建一个项目

2. 资源配置(图片声音素材)

在上述创建完成后,新建一个qrc文件,步骤如下:

此时资源文件,如图示:


三、项目实现


1. 游戏大厅
1.1 重写绘图事件

在gamehall.h文件中,进行重写绘图事件函数的声明

鼠标当到painEvent函数上点击Alt+Enter(回车),为painEvent函数添加定义

在这里插入图片描述

在上述过程后,开始编辑painEvent函数。
第一步:

先实例化画家,使用QPainter painter(this)实例化一个画家,this是让画家在当前窗口(gamehall)进行绘制。注意在使用QPainter需要包含头文件#include<QPainter>
第二步:

再实例化绘图设备,将图片加载到绘图设备中。注意在使用QPixmap需要包含头文件#include<QPixmap>
第三步:

再进行绘画,使用drawPixmap()方法,参数1和参数2,表示绘制开始的坐标;参数3,表示绘制的宽度;参数4,表示绘制的高度;参数5,表示绘制的图片。

void GameHall::paintEvent(QPaintEvent *event)
{//实例化画家,this:让画家在当前窗口进行绘制QPainter painter(this);//实例化绘图设备QPixmap pix(":/res/game_hall.png");//绘画 0,0从界面左上角开始绘画根据窗口的宽和高进行绘制painter.drawPixmap(0,0,this->width(),this->height(),pix);
}

1.2 设置窗口大小、图标、标题

第一步,先修改窗口的大小通过setFixedSize()方法将窗口的宽度设置为1000,高度设置为800。
第二步,设置窗口的图标先通过QIcon()将图片加载到项目中,再通过setWindowIcon()方法设置到窗口中。
第三步,设置窗口的标题通过setWindowTitle()方法将文字设置到窗口标题中。

GameHall::GameHall(QWidget *parent): QWidget(parent), ui(new Ui::GameHall)
{ui->setupUi(this);//设置窗口大小this->setFixedSize(1000,800);//设置窗口的图标this->setWindowIcon(QIcon(":/res/ico.png"));//设置窗口标题this->setWindowTitle("游戏大厅");
}

1.3 设置开始按钮样式

第一步,通过QPushButton创建一个游戏开始按钮,按钮文本设置为"开始游戏",this在父窗口中显示。
第二步,通过move移动按钮再窗口中的位置,消除按钮的边框。
第三步,修改按钮中的文本样式,需要先创建一个字体样式(字体为黑体,大小为20像素),最后通过setFont方法将字体样式加载到按钮中

GameHall::GameHall(QWidget *parent): QWidget(parent), ui(new Ui::GameHall)
{ui->setupUi(this);//设置窗口大小this->setFixedSize(1000,800);//设置窗口的图标this->setWindowIcon(QIcon(":/res/ico.png"));//设置窗口标题this->setWindowTitle("游戏大厅");//添加开始游戏按钮QPushButton * startButton = new QPushButton("开始游戏",this);//设置按钮的位置startButton->move(450,600);//消除按钮边框startButton->setStyleSheet("QPushButton{border:0px}");//创建字体样式QFont font("黑体", 20);//将字体样式加入到按钮文本中startButton->setFont(font);}

点击运行,此时游戏大厅绘制成功


2. 游戏关卡选择

2.1 创建GameSelect类

先创建一个新的类,名为为GameSelect,基类选择QWidget
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


2.2 连接按钮和窗口跳转

在gamehall.cpp中进行编辑按钮的信号和槽,实现点击按钮跳转至关卡选择窗口
第一步,先创建出一个GameSelect窗口,在创建时要包含头文件#include "gameselect.h"
第二步,进行连接使用connnect()方法进行信号和槽函数之间的连接,使用Lambda表达式进行槽函数的编写。
第三步,编辑Lambda表达式,使用close()方法关闭当前窗口。
第四步,将关卡选择窗口设置为同游戏大厅窗口大小相同。
第五步,打开游戏关卡选择窗口。
第六步,给按钮添加点击音效,首先在.pro文件中添加multimedia,然后使用play()进行添加音效。

#include "gamehall.h"
#include "ui_gamehall.h"
#include "gameselect.h"
#include <QPainter>
#include <QPixmap>
#include <QIcon>
#include <QPushButton>
#include <QFont>
#include <QSound>
GameHall::GameHall(QWidget *parent): QWidget(parent), ui(new Ui::GameHall)
{ui->setupUi(this);//设置窗口大小this->setFixedSize(1000,800);//设置窗口的图标this->setWindowIcon(QIcon(":/res/ico.png"));//设置窗口标题this->setWindowTitle("游戏大厅");//添加开始游戏按钮QPushButton * startButton = new QPushButton("开始游戏",this);//设置按钮的位置startButton->move(450,600);//消除按钮边框startButton->setStyleSheet("QPushButton{border:0px}");//创建字体样式QFont font("黑体", 20);//将字体样式加入到按钮文本中startButton->setFont(font);//新建GameSelect窗口GameSelect * gameSelect = new GameSelect;//Lambda表达式connect(startButton,&QPushButton::clicked,[=](){//先关闭当前窗口this->close();//设置gameSelect窗口大小跟gamehall窗口大小一样gameSelect->setGeometry(this->geometry());//打开gameselect窗口gameSelect->show();//添加按钮点击的音效QSound::play(":/res/clicked.wav");});}

编写gameselect.h文件,同游戏大厅步骤,这里不重复进行介绍,,详细看下下方代码注释。

在这里插入图片描述

#include "gameselect.h"
#include "gamehall.h"
#include <QPainter>
#include <QPixmap>
#include <QPushButton>
#include <QIcon>
#include <QSound>
GameSelect::GameSelect(QWidget *parent) : QWidget(parent)
{//设置窗口大小this->setFixedSize(1000,800);//设置窗口的图标this->setWindowIcon(QIcon(":/res/ico.png"));//设置窗口标题this->setWindowTitle("关卡选择");//创建返回按钮QPushButton * returnbutton = new QPushButton(this);returnbutton->resize(50,50);returnbutton->setIcon(QIcon(":/res/back.png"));returnbutton->setIconSize(returnbutton->size());returnbutton->move(900,700);//建立信号和槽函数的联系connect(returnbutton,&QPushButton::clicked,[=](){//创建游戏大厅窗口GameHall * gamehall = new GameHall;//关闭当前窗口this->close();//展开游戏大厅窗口gamehall->show();//添加音效QSound::play(":/res/clicked.wav");});//创建文本样式QFont font("黑体",30);//创建简单难度按钮QPushButton * simplebutton = new QPushButton("简单模式",this);//将样式设置到按钮中simplebutton->setFont(font);//设置按钮在窗口中的位置simplebutton->move(400,170);//进行信号与槽的连接//创建普通难度按钮QPushButton * commonbutton = new QPushButton("普通模式",this);//将样式设置到按钮中commonbutton->setFont(font);//设置按钮在窗口中的位置commonbutton->move(400,270);//创建困难难度按钮QPushButton * difficultybutton = new QPushButton("困难模式",this);//将样式设置到按钮中difficultybutton->setFont(font);//设置按钮在窗口中的位置difficultybutton->move(400,370);//创建历史记录按钮QPushButton * hisbutton = new QPushButton("历史记录",this);//将样式设置到按钮中hisbutton->setFont(font);//设置按钮在窗口中的位置hisbutton->move(400,470);}void GameSelect::paintEvent(QPaintEvent *event)
{//实例化画家,this:让画家在当前窗口进行绘制QPainter painter(this);//实例化绘图设备QPixmap pix(":/res/game_select.png");//绘画painter.drawPixmap(0,0,this->width(),this->height(),pix);
}
3. 游戏房间

3.1 创建GameRoom类

根据上面步骤后,新建GameRoom类
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


3.2 对游戏房间数据结构进行封装
#ifndef GAMEROOM_H
#define GAMEROOM_H#include <QWidget>
#include<QSound>
enum class SnakeDirect{UP=0,DOWN,LEFT,RIGHT};
class GameRoom : public QWidget
{Q_OBJECT
public:explicit GameRoom(QWidget *parent = nullptr);//重写绘图事件void paintEvent(QPaintEvent *event);void moveUp(); //向上移动void moveDown();//向下移动void moveLeft();//向左移动void moveRight();//向右移动bool checkFail();//判断游戏结束void createNewFood();//创建食物void setTimeout(int timeout){moveTimeout =timeout;}private:const int KSnakeNodeWidth = 20;  //蛇节点的宽度const int KSnakeNodeHeight = 20; //蛇节点的高度const int KDefaultTimeout =200;  //蛇的默认移动速度QList<QRectF> snakeList; //表示贪吃蛇链表QRectF foodRect;  //表示食物节点SnakeDirect moveDirect = SnakeDirect::UP; //设置蛇移动方向默认向上QTimer *timer; //定时器bool isGameStart =false; //表示是否开始游戏QSound *sound;int moveTimeout =  KDefaultTimeout;};#endif // GAMEROOM_H

3.3 初始化游戏房间界面
//设置窗口大小this->setFixedSize(1000,800);//设置窗口的图标this->setWindowIcon(QIcon(":/res/ico.png"));//设置窗口标题this->setWindowTitle("游戏房间");

3.4 绘制界面窗口
void GameRoom::paintEvent(QPaintEvent *event)
{QPainter painter(this);QPixmap pix;pix.load(":/res/game_room.png");painter.drawPixmap(0,0,800,800,pix);pix.load(":/res/bg1.png");painter.drawPixmap(800,0,200,850,pix);
}

3.5 蛇的移动

贪吃蛇的持续动态移动,本质上是定时器不断发出信号,调用moveup等移动函数,更新链表结构,最后重新绘图呈现给我们。

//创建上下左右按钮QPushButton * up = new QPushButton("↑",this);QPushButton * down = new QPushButton("↓",this);QPushButton * left = new QPushButton("←",this);QPushButton * right = new QPushButton("→",this);up->move(880,400);down->move(880,480);left->move(840,440);right->move(920,440);up->setFont(font);down->setFont(font);left->setFont(font);right->setFont(font);up->setStyleSheet("QPushButton{border:0px}");down->setStyleSheet("QPushButton{border:0px}");left->setStyleSheet("QPushButton{border:0px}");right->setStyleSheet("QPushButton{border:0px}");//按钮控制移动方向,不能直接掉头connect(up,&QPushButton::clicked,[=](){if(moveDirect != SnakeDirect::DOWN)moveDirect = SnakeDirect::UP;});connect(down,&QPushButton::clicked,[=](){if(moveDirect != SnakeDirect::UP)moveDirect = SnakeDirect::DOWN;});connect(left,&QPushButton::clicked,[=](){if(moveDirect != SnakeDirect::RIGHT)moveDirect = SnakeDirect::LEFT;});connect(right,&QPushButton::clicked,[=](){if(moveDirect != SnakeDirect::LEFT)moveDirect = SnakeDirect::RIGHT;});
void GameRoom::moveUp()
{QPointF leftTop; //左上角坐标QPointF rightBottom; //右下角坐标auto snakeNode = snakeList.front();//头int headX = snakeNode.x();int headY = snakeNode.y();if(headY<0){leftTop = QPointF(headX, this->height()- KSnakeNodeHeight);}else {leftTop=QPointF(headX,headY-KSnakeNodeHeight);}rightBottom = leftTop + QPointF(KSnakeNodeWidth,KSnakeNodeHeight);snakeList.push_front(QRectF(leftTop,rightBottom));
}void GameRoom::moveDown()
{QPointF leftTop; //左上角坐标QPointF rightBottom; //右下角坐标auto snakeNode = snakeList.front();//头int headX = snakeNode.x();int headY = snakeNode.y();if(headY>this->height()){leftTop = QPointF(headX,0);}else {leftTop=snakeNode.bottomLeft();}rightBottom = leftTop + QPointF(KSnakeNodeWidth,KSnakeNodeHeight);snakeList.push_front(QRectF(leftTop,rightBottom));
}void GameRoom::moveLeft()
{QPointF leftTop; //左上角坐标QPointF rightBottom; //右下角坐标auto snakeNode = snakeList.front();//头int headX = snakeNode.x();int headY = snakeNode.y();if(headX<0){leftTop=QPointF(800-KSnakeNodeWidth,headY);}else{leftTop=QPointF(headX-KSnakeNodeWidth,headY);}rightBottom = leftTop + QPointF(KSnakeNodeWidth,KSnakeNodeHeight);snakeList.push_front(QRectF(leftTop,rightBottom));
}void GameRoom::moveRight()
{QPointF leftTop; //左上角坐标QPointF rightBottom; //右下角坐标auto snakeNode = snakeList.front();//头int headX = snakeNode.x();int headY = snakeNode.y();if(headX>800-2*KSnakeNodeWidth){leftTop=QPointF(0,headY);}else{leftTop=snakeNode.topRight();}rightBottom = leftTop + QPointF(KSnakeNodeWidth,KSnakeNodeHeight);snakeList.push_front(QRectF(leftTop,rightBottom));
}

3.6 绘制蛇头身体尾巴
//绘制蛇//蛇头if(moveDirect==SnakeDirect::UP){pix.load(":/res/up.png");}else if (moveDirect==SnakeDirect::DOWN) {pix.load(":/res/down.png");}else if(moveDirect==SnakeDirect::LEFT){pix.load(":/res/left.png");}else{pix.load(":/res/right.png");}auto snakeHead = snakeList.front();painter.drawPixmap(snakeHead.x(),snakeHead.y(),snakeHead.width(),snakeHead.height(),pix);//蛇身pix.load(":/res/Bd.png");for(int i = 1; i < snakeList.size()-1; i++){auto node = snakeList.at(i);painter.drawPixmap(node.x(),node.y(),node.width(),node.height(),pix);}//蛇尾auto snakeTail = snakeList.back();painter.drawPixmap(snakeTail.x(),snakeTail.y(),snakeTail.width(),snakeTail.height(),pix);

3.6 绘制食物与分数
//绘制食物节点//先进行加载食物pix.load(":/res/food.bmp");painter.drawPixmap(foodRect.x(),foodRect.y(),foodRect.width(),foodRect.height(),pix);//绘制分数pix.load(":res/sorce_bg.png");painter.drawPixmap(this->width()*0.85,this->height()*0.03,100,50,pix);QPen pen;pen.setColor(Qt::black);painter.setPen(pen);QFont font("黑体",22);painter.setFont(font);painter.drawText(this->width()*0.9,this->height()*0.08,QString("%1").arg(snakeList.size()));//往文件中写分数int c = snakeList.size();QFile file("C:/Users/26256/Desktop/his.txt");if(file.open(QIODevice::WriteOnly | QIODevice::Text)){QTextStream out(&file);int num = c;out << num;file.close();}
3.7 判定游戏结束
bool GameRoom::checkFail()
{for(int i=0;i < snakeList.size();i++){for(int j=i+1;j < snakeList.size();j++){if(snakeList.at(i) == snakeList.at(j)){return true;}}}return false;
}
3.8 随机生成食物节点
void GameRoom::createNewFood()
{foodRect=QRectF(qrand() %(800/KSnakeNodeWidth)*KSnakeNodeWidth,qrand() %(this->height()/KSnakeNodeHeight)*KSnakeNodeHeight,KSnakeNodeWidth,KSnakeNodeHeight);}
3.9 创建游戏开始和暂停按钮
//开始游戏   结束游戏QPushButton * startButton = new QPushButton("开始",this);QPushButton *failButton = new QPushButton("暂停",this);startButton->move(860,100);failButton->move(860,150);startButton->setFont(font2);failButton->setFont(font2);connect(startButton,&QPushButton::clicked,[=](){isGameStart=true;timer->start(moveTimeout);sound = new QSound(":res/Trepak.wav");sound->play();sound->setLoops(-1);});connect(failButton,&QPushButton::clicked,[=](){isGameStart=false;timer->stop();sound->stop();
3.10 实现定时器的超时槽函数
  timer = new QTimer(this);connect(timer,&QTimer::timeout,[=](){int cont =1;if(snakeList.front().intersects(foodRect)){createNewFood();cont++;QSound::play(":/res/eatfood.wav");}while(cont--){switch (moveDirect) {case SnakeDirect::UP :moveUp();break;case SnakeDirect::DOWN:moveDown();break;case SnakeDirect::LEFT:moveLeft();break;case SnakeDirect::RIGHT:moveRight();break;}}snakeList.pop_back();update();});
3.11 设置游戏退出按钮
//退出游戏按钮QPushButton *backButton = new QPushButton("退出",this);backButton->move(860,700);backButton->setFont(font2);QMessageBox * messbox = new QMessageBox(this);QPushButton * ok = new QPushButton("ok");QPushButton * no = new QPushButton("no");messbox->addButton(ok,QMessageBox::AcceptRole);messbox->addButton(no,QMessageBox::ResetRole);messbox->setText("确定要退出游戏吗?");connect(backButton,&QPushButton::clicked,[=](){messbox->show();messbox->exec();QSound::play("clicked.wav");GameSelect* select = new GameSelect;if(messbox->clickedButton()==ok){this->close();select->show();}else{messbox->close();}});
3.12 获取历史战绩
//创建历史记录按钮QPushButton * hisbutton = new QPushButton("历史记录",this);//将样式设置到按钮中hisbutton->setFont(font);//设置按钮在窗口中的位置hisbutton->move(400,470);connect(hisbutton,&QPushButton::clicked,[=](){QWidget * widget = new QWidget();widget->setFixedSize(200,80);widget->setWindowTitle("历史战绩");QTextEdit * edit = new QTextEdit(widget);edit->setFixedSize(200,80);edit->setFont(font);QFile file("C:/Users/26256/Desktop/his.txt");file.open(QIODevice::ReadOnly);QTextStream in(&file);int data = in.readLine().toInt();edit->append("得分为:");edit->append(QString::number(data));widget->show();});

四.贪吃蛇移动的逻辑讲解

 1.贪吃蛇的一次普通移动:

调用moveup等移动函数,创建一个新的头结点,头插到蛇的链表结构中,此时链表多一个节点。

调用链表的pop_back()函数尾删,保持链表整体长度与原来一致。

2.贪吃蛇吃到食物的一次移动:

记录吃到的食物数量cont,调用cont+1次移动函数,使链表头部多cont+1个节点。最后尾删一次,使链表长度比原来长cont。

3.贪吃蛇的持续移动:

创建定时器,将信号与相应逻辑的槽函数关联。定时发送信号,执行槽函数,实现逻辑。

原文链接:

这篇关于【Qt】贪吃蛇的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1106430

相关文章

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

C++如何通过Qt反射机制实现数据类序列化

《C++如何通过Qt反射机制实现数据类序列化》在C++工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作,所以本文就来聊聊C++如何通过Qt反射机制实现数据类序列化吧... 目录设计预期设计思路代码实现使用方法在 C++ 工程中经常需要使用数据类,并对数据类进行存储、打印、调试等操作。由于数据类

Qt中QGroupBox控件的实现

《Qt中QGroupBox控件的实现》QGroupBox是Qt框架中一个非常有用的控件,它主要用于组织和管理一组相关的控件,本文主要介绍了Qt中QGroupBox控件的实现,具有一定的参考价值,感兴趣... 目录引言一、基本属性二、常用方法2.1 构造函数 2.2 设置标题2.3 设置复选框模式2.4 是否

QT进行CSV文件初始化与读写操作

《QT进行CSV文件初始化与读写操作》这篇文章主要为大家详细介绍了在QT环境中如何进行CSV文件的初始化、写入和读取操作,本文为大家整理了相关的操作的多种方法,希望对大家有所帮助... 目录前言一、CSV文件初始化二、CSV写入三、CSV读取四、QT 逐行读取csv文件五、Qt如何将数据保存成CSV文件前言

Qt中QUndoView控件的具体使用

《Qt中QUndoView控件的具体使用》QUndoView是Qt框架中用于可视化显示QUndoStack内容的控件,本文主要介绍了Qt中QUndoView控件的具体使用,具有一定的参考价值,感兴趣的... 目录引言一、QUndoView 的用途二、工作原理三、 如何与 QUnDOStack 配合使用四、自

Qt spdlog日志模块的使用详解

《Qtspdlog日志模块的使用详解》在Qt应用程序开发中,良好的日志系统至关重要,本文将介绍如何使用spdlog1.5.0创建满足以下要求的日志系统,感兴趣的朋友一起看看吧... 目录版本摘要例子logmanager.cpp文件main.cpp文件版本spdlog版本:1.5.0采用1.5.0版本主要

Qt 中 isHidden 和 isVisible 的区别与使用小结

《Qt中isHidden和isVisible的区别与使用小结》Qt中的isHidden()和isVisible()方法都用于查询组件显示或隐藏状态,然而,它们有很大的区别,了解它们对于正确操... 目录1. 基础概念2. 区别清见3. 实际案例4. 注意事项5. 总结1. 基础概念Qt 中的 isHidd

QT移植到RK3568开发板的方法步骤

《QT移植到RK3568开发板的方法步骤》本文主要介绍了QT移植到RK3568开发板的方法步骤,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录前言一、获取SDK1. 安装依赖2. 获取SDK资源包3. SDK工程目录介绍4. 获取补丁包二

Qt把文件夹从A移动到B的实现示例

《Qt把文件夹从A移动到B的实现示例》本文主要介绍了Qt把文件夹从A移动到B的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录如何移动一个文件? 如何移动文件夹(包含里面的全部内容):如何删除文件夹:QT 文件复制,移动(

Qt实现发送HTTP请求的示例详解

《Qt实现发送HTTP请求的示例详解》这篇文章主要为大家详细介绍了如何通过Qt实现发送HTTP请求,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、添加network模块2、包含改头文件3、创建网络访问管理器4、创建接口5、创建网络请求对象6、创建一个回复对