实验容
玩家通键盘左右方键控制球移动终达出口游戏通关
求:
1 游戏分成3关第关第二关第三关界面图:
第关
第二关
第三关
2 启动游戏进入第关胜利进入第二关果第三关通关游戏重新回第关
3 游戏玩法通关控制键盘左右方键控制球运动单击方键球获该方直线运动速度果球遇方块球停止运动果遇黑洞游戏结束重新开始该游戏遇出口通关
4 球静止状态会箭头指示球运动方运动状态箭头消失果球运动出世界边界游戏结束重新回该游戏
二实验指南
实验 开始实验
实验务
步骤开FunCode创建C++语言项目
步骤二导入GolfGame场景
实验思路
实验指导完成
实验指导
1 开FunCode点击项目菜单选择创建C++工程
注意:工程名名称求字母开头包含字母数字名字中间空格
2 点击菜单项目中导入图模块图跳出话框选中GolfGame模板点击导入工程钮图二
图 图 二
3 导入成功界面图示:
图仅包括界面设计包括该游戏精灵添加场景中精灵已取名称根程序求设置中心点链接点等学生需直接编程
实验二 游戏关卡初始化
实验容
步骤关卡图初始化
步骤二清关卡数
步骤三根前关卡选择关卡数
实验思路
游戏开始时候首先清关游戏数关创建精灵图中删掉
游戏图分成12*12方格界面游戏总分成三关需三二维数组m_iLevelData1[GRID_COUNT][GRID_COUNT]
m_iLevelData2[GRID_COUNT][GRID_COUNT]
m_iLevelData3[GRID_COUNT][GRID_COUNT]
(中GRID_COUNT值12)
存放三关数二维数组中0表示该位置创建精灵否根值创建精灵RIGID_BLOCK(值1)表示创建方块精灵BLACK_HOLE(值2)表示创建黑洞精灵GOLF_EXIT(值3)表示创建出口精灵次代表该关卡二维数组数拷贝存储前关卡m_iGridData二维数组中
实验指导
1 进入LessonXhCGameMain类中添加成员变量声明:
static const float m_fGridStartX
第块方块起始坐标 (GRID_COUNT * g_fGridSize * 05 g_fGridSize 2)
static const float m_fGridStartY
static const float m_fGridSize 块包括球出口等
int m_iRigidBlockCount 关卡创建阻挡物方块数量
int m_iBlackHoleCount 关卡创建黑洞数量
int m_iGolfExitCount 关卡创建出口数量
int m_iCurLevel 前关卡
int m_iMoveState 控制球移动状态:0前静止移动 1234:代表左右4方移动中键响应
int m_iGridData[GRID_COUNT][GRID_COUNT] 二维数组存储 前关卡N*N矩阵方块信息
static const int m_iLevelData1[GRID_COUNT][GRID_COUNT]
static const int m_iLevelData2[GRID_COUNT][GRID_COUNT]
static const int m_iLevelData3[GRID_COUNT][GRID_COUNT]
vector
vector
vector
int m_iControlStartX 控制球初始X坐标根关卡数行指定
int m_iControlStartY 球初始Y坐标
2 进入LessonXh中头文件声明面添加面宏定义代码:
#define GRID_COUNT 12 N * N 矩阵方块N
#define MAX_LEVEL 3 关卡数量果增加关卡请先修改值
#define RIGID_BLOCK 1 3分方块阻挡物黑洞出口值
#define BLACK_HOLE 2
#define GOLF_EXIT 3
3 进入LessonXcpp中添加面成员变量初始化:
1) 构造函数中m_iGameState值0改1:
m_iGameState 1
2) 构造函数中添加面代码:
m_iRigidBlockCount 0 关卡创建阻挡物方块数量
m_iBlackHoleCount 0 关卡创建黑洞数量
m_iGolfExitCount 0
m_iCurLevel 1
m_iControlStartX 0 球初始X坐标
m_iControlStartY 0 球初始Y坐标
3) const类型成员变量需函数外面单独进行初始化文件面添加代码:
const float CGameMainm_fGridStartX 275f
const float CGameMainm_fGridStartY 275f
const float CGameMainm_fGridSize 5f
const int CGameMainm_iLevelData1[GRID_COUNT][GRID_COUNT] {
{0 0 0 0 0 0 0 0 0 0 0 0}
{0 0 0 0 0 0 0 0 0 0 0 0}
{0 0 0 0 0 0 0 0 0 0 0 0}
{0 0 0 RIGID_BLOCK RIGID_BLOCK RIGID_BLOCK RIGID_BLOCK RIGID_BLOCK RIGID_BLOCK 0 0 0}
{0 0 0 RIGID_BLOCK 0 0 0 0 RIGID_BLOCK 0 0 0}
{0 0 0 RIGID_BLOCK 0 0 0 0 RIGID_BLOCK 0 0 0}
{0 0 0 RIGID_BLOCK 0 0 0 0 BLACK_HOLE 0 0 0}
{0 0 0 0 0 0 0 GOLF_EXIT RIGID_BLOCK 0 0 0}
{0 0 0 0 0 0 0 0 0 0 0 0}
{0 0 0 0 0 0 0 0 0 0 0 0}
{0 0 0 0 0 0 0 0 0 0 0 0}
{0 0 0 0 0 0 0 0 0 0 0 0}
}
const int CGameMainm_iLevelData2[GRID_COUNT][GRID_COUNT]{
{0 RIGID_BLOCK RIGID_BLOCK RIGID_BLOCK 0 RIGID_BLOCK RIGID_BLOCK RIGID_BLOCK RIGID_BLOCK RIGID_BLOCK RIGID_BLOCK 0}
{0 RIGID_BLOCK 0 0 0 0 0 0 0 0 RIGID_BLOCK 0}
{0 RIGID_BLOCK 0 0 0 0 0 0 0 0 RIGID_BLOCK 0}
{0 RIGID_BLOCK 0 0 0 0 0 0 0 0 RIGID_BLOCK 0}
{0 RIGID_BLOCK 0 0 0 0 0 0 0 0 RIGID_BLOCK 0}
{0 RIGID_BLOCK 0 0 0 0 0 0 0 0 RIGID_BLOCK 0}
{0 RIGID_BLOCK 0 0 0 RIGID_BLOCK RIGID_BLOCK RIGID_BLOCK 0 0 RIGID_BLOCK 0}
{0 RIGID_BLOCK 0 0 0 0 0 RIGID_BLOCK 0 0 RIGID_BLOCK 0}
{0 RIGID_BLOCK 0 0 0 0 0 0 GOLF_EXIT RIGID_BLOCK RIGID_BLOCK 0}
{0 RIGID_BLOCK 0 0 0 0 0 0 0 0 0 0}
{0 RIGID_BLOCK 0 0 0 0 0 0 0 0 RIGID_BLOCK 0}
{0 RIGID_BLOCK 0 RIGID_BLOCK RIGID_BLOCK RIGID_BLOCK RIGID_BLOCK RIGID_BLOCK RIGID_BLOCK 0 RIGID_BLOCK 0}
}
const int CGameMainm_iLevelData3[GRID_COUNT][GRID_COUNT]{
{0 0 0 0 0 0 0 0 RIGID_BLOCK RIGID_BLOCK 0 0}
{0 0 RIGID_BLOCK RIGID_BLOCK RIGID_BLOCK 0 0 0 0 0 0 RIGID_BLOCK}
{RIGID_BLOCK 0 0 0 0 0 0 0 0 0 0 RIGID_BLOCK}
{0 0 0 0 0 0 0 0 0 0 0 RIGID_BLOCK}
{0 0 0 0 0 0 0 0 0 0 0 0}
{0 0 0 0 GOLF_EXIT 0 0 0 0 0 0 0}
{0 0 0 0 0 0 0 RIGID_BLOCK RIGID_BLOCK 0 0 0}
{0 0 0 0 0 0 0 0 0 0 0 0}
{0 0 0 0 0 0 0 0 0 0 RIGID_BLOCK 0}
{0 0 0 RIGID_BLOCK 0 0 0 0 0 0 RIGID_BLOCK 0}
{0 0 0 0 BLACK_HOLE RIGID_BLOCK 0 0 0 0 0 0}
{0 0 0 0 0 0 0 0 0 0 0 0}
}
二维数组中0表示该位置创建精灵否根值创建精灵RIGID_BLOCK(值1)表示创建方块精灵BLACK_HOLE(值2)表示创建黑洞精灵GOLF_EXIT(值3)表示创建出口精灵
4) 进入GameInit函数里面球运动状态初始化静止添加面代码:
m_iMoveState0
4 游戏初始化时候首先需前边添加精灵全部删掉需定义创建清精灵函数ClearAllSprite()实现功
1) 进入LessonXh文件CGameMain类中添加该函数声明:
void ClearAllSprite()
2) LessonXcpp面添加该函数定义:
void CGameMain ClearAllSprite()
{
}
3) 3循环分关卡创建3种精灵删掉边定义函数中添加代码:
int iLoop 0
for( iLoop 0 iLoop < m_vRigidBlocksize() iLoop++ )
{
m_vRigidBlock[iLoop]>DeleteSprite()
}
for( iLoop 0 iLoop < m_vBlackHolesize() iLoop++ )
{
m_vBlackHole[iLoop]>DeleteSprite()
}
for( iLoop 0 iLoop < m_vGolfExitsize() iLoop++ )
{
m_vGolfExit[iLoop]>DeleteSprite()
}
中m_vRigidBlockm_vBlackHolem_vGolfExit存储三种精灵量数组循环遍历遍量数组调数组中精灵DeleteSprite函数
m_vRigidBlocksize()m_vBlackHolesize()m_vGolfExitsize()表示种精灵总数
4) GameInit()中添加调函数代码:
ClearAllSprite()
5 GameInit()中需关卡进行选择初始化需定义初始化关卡函数InitLevel ()实现功
1) 进入LessonXh文件CGameMain类中添加该函数声明:
void InitLevel()
2) LessonXcpp面添加该函数定义:
void CGameMain InitLevel()
{
}
3) 初始化关卡根前关卡选择关卡数代表关卡二维数组中数拷贝m_iGridData中时设置控制球数组中起始位置首先需数初始化0代码:
总数置0重新创建
m_iRigidBlockCount 0
m_iBlackHoleCount 0
m_iGolfExitCount 0
4) 选择关卡switchcase结构程序通判断switch中参数进入case中case种情况实现代码:
根前关卡选择关卡数
switch( m_iCurLevel )
{
case 2
{
m_iControlStartX 5
m_iControlStartY 9
memcpy( m_iGridData m_iLevelData2 sizeof(int) * GRID_COUNT * GRID_COUNT )
}
break
case 3
{
m_iControlStartX 3
m_iControlStartY 6
memcpy( m_iGridData m_iLevelData3 sizeof(int) * GRID_COUNT * GRID_COUNT )
}
break
Level1 者g_iCurLevel错误
case 1
default
{
m_iControlStartX 5
m_iControlStartY 6
memcpy( m_iGridData m_iLevelData1 sizeof(int) * GRID_COUNT * GRID_COUNT )
}
break
}
memcpy函数作源src指存址起始位置开始拷贝n字节目标dest指存址起始位置中二维数组存中存放方式连续源址拷贝m_iGridData起始址系统动根m_iGridData标找正确值
5) GameInit()中添加调函数代码:
InitLevel()
实验结束
实验三 初始化游戏精灵
实验容
步骤创建精灵
步骤二初始化精灵位置
实验思路
遍历二维数组m_iGridData根数组值生成应精灵实例:值0时候创建需创建精灵名字前缀(宏定义123序):RigidBlock BlackHole GolfExit创建种精灵总数加1 :m_iRigidBlockCount m_iBlackHoleCountm_iGolfExitCount
实验指导
1 进入LessonXhCGameMain类中添加面成员变量声明:
CSprite* m_pControlBall 控制球精灵
CSprite* m_pGolfArrow 指示箭头精灵
LessonXcpp中CGameMain类构造函数里面添加面成员变量初始化:
m_pControlBall new CSprite(ControlBall)
m_pGolfArrow new CSprite(GolfArrow)
2 创建精灵需精灵移特定位置需定义定义函数MoveSpriteToBlock实现功
6) 进入LessonXh中添加该函数声明:
void MoveSpriteToBlock( CSprite* tmpSprite const int iIndexX const int iIndexY )
7) LessonXcpp面添加该函数定义:
void CGameMainMoveSpriteToBlock( CSprite* tmpSprite const int iIndexX const int iIndexY )
{
}
8) 传入该函数精灵实体xy坐标参数通SetSpritePosition函数设置精灵位置该函数里面添加代码:
float fPosX m_fGridStartX + iIndexX * m_fGridSize
float fPosY m_fGridStartY + iIndexY * m_fGridSize
tmpSprite>SetSpritePosition(fPosX fPosY)
3 里定义函数CreateAllSprite()创建控制球方块精灵出口精灵黑洞精灵然函数部添加代码创建精灵
原理通两for循环判断m_iGridData值果0创建果RIGID_BLOCK创建方块精灵 BLACK_HOLE创建黑洞精灵GOLF_EXIT创建出口精灵预先图中摆放三模板精灵需CloneSprite函数创建新精灵然调MoveSpriteToBlock函数精灵移动指定位置创建实现精灵添加相应精灵量数组中
1) 进入LessonXh文件CGameMain类中添加该函数声明:
void CreateAllSprite()
2) LessonXcpp面添加该函数定义:
void CGameMain CreateAllSprite()
{
}
3) 定义汗函数中添加变量声明:
int iLoopX 0 iLoopY 0
CSprite* tmpSprite
char *szName NULL
4) 实现两for循环:
for( iLoopY 0 iLoopY < GRID_COUNT iLoopY++ )
{
for( int iLoopX 0 iLoopX < GRID_COUNT iLoopX++ )
{
}
}
5) 里面循环添加判断代码:
果0创建精灵continue表示跳出次循环继续循环
if( 0 m_iGridData[iLoopY][iLoopX] )
continue
果方块创建方块精灵:
if( RIGID_BLOCK m_iGridData[iLoopY][iLoopX] )
{
szName CSystemMakeSpriteName(RigidBlockm_iRigidBlockCount )
tmpSpritenew CSprite(szName)
tmpSprite>CloneSprite(RigidBlockTemplate)
MoveSpriteToBlock( tmpSprite iLoopX iLoopY )
m_vRigidBlockpush_back(tmpSprite)
m_iRigidBlockCount++
}
果黑洞创建黑洞精灵:
else if( BLACK_HOLE m_iGridData[iLoopY][iLoopX] )
{
szName CSystemMakeSpriteName( BlackHole m_iBlackHoleCount )
tmpSpritenew CSprite(szName)
tmpSprite>CloneSprite(BlackHoleTemplate)
MoveSpriteToBlock( tmpSprite iLoopX iLoopY )
m_vBlackHolepush_back(tmpSprite)
m_iBlackHoleCount++
}
果出口创建出口精灵:
else if( GOLF_EXIT m_iGridData[iLoopY][iLoopX] )
{
szName CSystemMakeSpriteName( GolfExit m_iGolfExitCount )
tmpSpritenew CSprite(szName)
tmpSprite>CloneSprite(GolfExitTemplate)
MoveSpriteToBlock( tmpSprite iLoopX iLoopY )
m_vGolfExitpush_back(tmpSprite)
m_iGolfExitCount++
}
6) 控制球指示箭头摆放初始位置时球静止指示箭头见面两循环面添加面代码:
m_pControlBall>SetSpriteLinearVelocity( 0f 0f)
MoveSpriteToBlock(m_pControlBallm_iControlStartXm_iControlStartY)
MoveSpriteToBlock(m_pGolfArrow m_iControlStartX m_iControlStartY )
m_pGolfArrow>SetSpriteVisible(1)
7) GameInit()中调函数:
CreateAllSprite()
实验结束
实验四 移动球
实验容
步骤响应键盘键消息
步骤二球精灵坐标转换二维格子数组索引
步骤三判断移动方球获取速度
实验思路
首先响应系统键消息函数然获取精灵坐标转换二维格子中坐标判断旁边格子否方块果球移动速度
实验指导
1 进入LessonXh中添加定义键盘消息处理函数OnKeyDown声明:
void OnKeyDown( const int iKey const int iAltPress const int iShiftPress const int iCtrlPress )
2 LessonXcpp中添加该函数定义:
void CGameMainOnKeyDown( const int iKey const int iAltPress const int iShiftPress const int iCtrlPress )
{
}
3 首先判断游戏状态游戏中已移动状态响应键面函数中添加面代码:
if( 2 m_iGameState || 0 m_iMoveState )
return
4 获取控制球精灵坐标转换二维格子数组索引里需定义两函数SpritePosXToIndexXSpritePosXToIndexY分处理精灵坐标转换二维格子X索引Y索引:
1) 进入LessonXh中添加面两函数声明:
int SpritePosXToIndexX( const float fPosX )
int SpritePosYToIndexY( const float fPosY )
2) 进入LessonXcpp中添加SpritePosXToIndexX定义:
int CGameMain SpritePosXToIndexX ( const float fPosX )
{
}
3) 首先左右边界坐标值m_fGridStartX方块中心需减半方块宽度左边边界SpritePosXToIndexX函数定义中添加面代码
const float fLeftSide m_fGridStartX m_fGridSize 2f
const float fRightSide fLeftSide + m_fGridSize * GRID_COUNT
4) 需判断坐标否出左右边界果没返回X索引值面函数里面添加面判断代码:
if( fPosX < fLeftSide || fPosX > fRightSide )
return 1
int iIndexX (int)( (fPosX fLeftSide) m_fGridSize )
return iIndexX
5) LessonXcpp中添加SpritePosYToIndexY函数定义:
int CGameMainSpritePosYToIndexY( const float fPosY )
{
}
6) 首先获取边界坐标值m_fGridStartY方块中心需减半方块宽度边边界面函数定义中添加面代码:
const float fTopSide m_fGridStartY m_fGridSize 2f
const float fBottomSide fTopSide + m_fGridSize * GRID_COUNT
7) 判断否超边界没返回Y索引值:
if( fPosY < fTopSide || fPosY > fBottomSide )
return 1
int iIndexY (int)( (fPosY fTopSide) m_fGridSize )
return iIndexY
5 面两函数控制球精灵坐标转换二维格子数组索引判断坐标否超出边界OnKeyDown函数中添加面代码:
float fPosX m_pControlBall>GetSpritePositionX()
float fPosY m_pControlBall>GetSpritePositionY()
int iIndexX SpritePosXToIndexX( fPosX )
int iIndexY SpritePosYToIndexY( fPosY )
if( iIndexX < 0 || iIndexX > GRID_COUNT || iIndexY < 0 || iIndexY > GRID_COUNT )
return
6 根左右方键先判断控制球旁边否方块果方块移动方块予控制球速度iIndexX iIndexY时候注意判断否边缘索引果判断进行加1减1访问数组会造成标溢出果判断左边否方块阻挡索引值 IndexX 1 时必须先判断iIndexX0减果iIndexX0代表直接移动
1) 果方键:
if( KEY_UP iKey )
{
if( iIndexY > 0 && RIGID_BLOCK m_iGridData[iIndexY 1][iIndexX] )
return
予控制球方速度设置移动状态隐藏指示箭头
m_iMoveState 1
m_pControlBall>SetSpriteLinearVelocityY(30f)
m_pGolfArrow>SetSpriteVisible(0)
}
2) 果方键:
else if( KEY_DOWN iKey )
{
if( iIndexY < GRID_COUNT 1 && RIGID_BLOCK m_iGridData[iIndexY + 1][iIndexX] )
return
予控制球方速度设置移动状态隐藏指示箭头
m_iMoveState 2
m_pControlBall>SetSpriteLinearVelocityY(30f)
m_pGolfArrow>SetSpriteVisible(0)
}
3) 果左方键:
else if( KEY_LEFT iKey )
{
if( iIndexX > 0 && RIGID_BLOCK m_iGridData[iIndexY][iIndexX 1] )
return
予控制球方速度设置移动状态隐藏指示箭头
m_iMoveState 3
m_pControlBall>SetSpriteLinearVelocityX(30f)
m_pGolfArrow>SetSpriteVisible(0)
}
4) 果右方键:
else if( KEY_RIGHT iKey )
{
if( iIndexX < GRID_COUNT 1 && RIGID_BLOCK m_iGridData[iIndexY][iIndexX + 1] )
return
予控制球方速度设置移动状态隐藏指示箭头
m_iMoveState 4
m_pControlBall>SetSpriteLinearVelocityX(30f)
m_pGolfArrow>SetSpriteVisible(0)
}
7 Maincpp中OnKeyDown函数里面添加定义函数调:
g_GameMainOnKeyDown(iKeybAltPressbShiftPressbCtrlPress)
实验结束
实验五球运动情况处理
实验容
步骤获球边缘格子信息
步骤二格子分情况处理
实验思路
获取球精灵前坐标转换二维格子坐标判断运动中球边缘情况果已出边界需判断否果方块球停黑洞重新开始关卡出口通关
实验指导
1 进入LessonXcpp中GameRun函数中移动状态移动中时刻监测控制球移动情况根移动方方块进行应处理添加面if判断:
if( 0 m_iMoveState )
{
}
2 先控制球精灵坐标转换二维格子数组索引果控制球已出边界需判断面判断里面添加面代码:
float fPosX m_pControlBall>GetSpritePositionX()
float fPosY m_pControlBall>GetSpritePositionY()
int iIndexX SpritePosXToIndexX( fPosX )
int iIndexY SpritePosYToIndexY( fPosY )
控制球已出边界需判断
if( iIndexX < 0 || iIndexX > GRID_COUNT || iIndexY < 0 || iIndexY > GRID_COUNT )
return
3 根前方获控制球边缘格子信息(球坐标中心点加球半)总4中方左右分1234表示添加面代码:
float fNextPosX fPosX
float fNextPosY fPosY
if( 1 m_iMoveState )
{
fNextPosY m_fGridSize * 05f
}
else if( 2 m_iMoveState )
{
fNextPosY + m_fGridSize * 05f
}
else if( 3 m_iMoveState )
{
fNextPosX m_fGridSize * 05f
}
else if( 4 m_iMoveState )
{
fNextPosX + m_fGridSize * 05f
}
4 面坐标转换二维格子坐标判断否越出边界添加面代码:
int iNextIndexX SpritePosXToIndexX( fNextPosX )
int iNextIndexY SpritePosYToIndexY( fNextPosY )
该边缘已出边界需判断
if( iNextIndexX < 0 || iNextIndexX > GRID_COUNT || iNextIndexY < 0 || iNextIndexY > GRID_COUNT )
return
5 根球边缘前格子信息进行处理:方块球停黑洞重新开始关卡出口通关:
1) 方块:
if( RIGID_BLOCK m_iGridData[iNextIndexY][iNextIndexX] )
{
清零移动状态
m_iMoveState 0
速度清零显示指示箭头
m_pControlBall>SetSpriteLinearVelocity(0f 0f)
m_pGolfArrow>SetSpriteVisible(1)
球指示箭头设置方块中心
MoveSpriteToBlock( m_pControlBall iIndexX iIndexY )
MoveSpriteToBlock( m_pGolfArrow iIndexX iIndexY )
}
2) 黑洞:
else if( BLACK_HOLE m_iGridData[iNextIndexY][iNextIndexX] )
{
游戏状态设置1重新开始关卡
m_iGameState 1
}
3) 出口:
else if( GOLF_EXIT m_iGridData[iNextIndexY][iNextIndexX] )
{
游戏状态设置1开始新关卡
m_iGameState 1
关卡果已值返回第关
m_iCurLevel++
if( m_iCurLevel > MAX_LEVEL )
m_iCurLevel 1
}
实验结束
实验六球出边界处理
实验容
步骤控制球出边界游戏重新开始
实验思路
部分较简单通系统判断球精灵否越世界边界数定义函数里面处理
实验指导
1 进入LessonXh中添加定义处理函数OnSpriteColWorldLimit声明:
void OnSpriteColWorldLimit( const char *szName const int iColSide )
2 进入LessonXcpp中添加该函数定义:
void CGameMainOnSpriteColWorldLimit( const char *szName const int iColSide )
{
}
3 面函数定义中知道系统OnSpriteColWorldLimit函数中返回szName否球精灵名称果话局游戏结束重新开始游戏面定义里面添加面代码:
处理控制球
if( stricmp( szName m_pControlBall>GetName()) 0 )
return
游戏状态设置1重新开始关卡
m_iGameState 1
4 进入Maincpp文件OnSpriteColWorldLimit函数里面添加定义函数调填入面行代码:
g_GameMainOnSpriteColWorldLimit(szNameiColSide)
5 开Funcode点击图中球精灵右侧编辑>世界边界限制中选择限制模式NULL样系统会定义函数处理球越边界事件
实验结束
文档香网(httpswwwxiangdangnet)户传
《香当网》用户分享的内容,不代表《香当网》观点或立场,请自行判断内容的真实性和可靠性!
该内容是文档的文本内容,更好的格式请下载文档