当前位置:天才代写 > C++/C代写,c语言代写代考-100%安全,包过 > 代写CS之C++ object oriented curriculum design outer space-warship

代写CS之C++ object oriented curriculum design outer space-warship

2018-07-27 08:00 星期五 所属: C++/C代写,c语言代写代考-100%安全,包过 浏览:1395

FunCode程序设计实验教材系列

 

 

C++面向对象课程设计

实验指南

 

 

课程设计三 太空战机

一、游戏介绍

太空战机是玩家用键盘控制战机移动并发射子弹,消灭敌方的战机。敌方战机从右到左移动,同时上下浮动。

 

二、实验目的

综合应用C++语言和面向对象的知识开发一款小游戏。

 

三、实验内容

在外星球上,玩家通过键盘WSAD键控制己方战机,消灭外星球的邪恶战机。

要求如下:

1、 游戏运行时,初始界面如下图。

2、 按下空格键,游戏开始,玩家通过WSAD键控制己方战机移动;己方战机不能超出世界边界。

3、 玩家战机每隔0.3秒发射一发子弹;

4、 添加敌方战机,每隔5秒创建一架敌方战机;

5、 敌方战机每隔3秒发射一发子弹;

6、 记录游戏的最高分。

image.png 

游戏初始界面

四、实验指南

实验一 游戏开始和控制我方战机移动

【实验内容】

1、 按空格键,游戏开始,空格开始字样消失。

2、 创建CMyFighter类,并创建对象实例玩家控制的战机。

3、 战机碰到世界边界时,静止。

4、 游戏开始后,通过键盘WSAD键控制战机移动。

5、 战机左右运动的速度为30上下运动的速度为15

6、 在游戏中显示游戏的当前积分和最高积分。

 

【实验思路】

按空格键开始游戏,属于键盘按下事件,我们在OnKeyDown函数中编写代码。

在游戏中,我们运用面向对象的知识将战机看成一个对象,并为这个对象添加一个类叫CMyFighter。类具有属性和方法,要控制战机能在各个方向上自由的游动,我们为CMyFighter类添加上下左右四个方向的速度,并且我们为战机添加OnMove方法控制战机的游动状态。

 

【实验指导】

1、 CGameMain中定义类成员变量:

CSprite*  m_pBeginSprite ; //GameBegin为“空格开始”精灵
CTextSprite* m_pCurScoreText;//显示当前积分
CTextSprite* m_pMaxScoreText;// 显示最高分

2、 CGameMain类的构造函数中添加代码,对变量进行初始化。

m_pBeginSprite   = new CSprite("GameBegin");
m_pCurScoreText   = new CTextSprite("CurScoreText");
m_pMaxScoreText   = new CTextSprite("MaxScoreText");

3、 OnKeyDown中,当按下的按键为空格键并且此时的游戏状态为0,则设置游戏的状态为10表示此时游戏为等待状态,未开始。1表示游戏进行初始化,2表示初始化后会进入游戏运行状态。

// 按下空格,游戏开始
if( KEY_SPACE == iKey && 0 == GetGameState() )
{
SetGameState( 1 );
}

4、 在游戏初始化函数GameInit中隐藏 "按空格开始游戏"图片。

m_pBeginSprite->SetSpriteVisible( false );

5、 通过类向导创建CMyFighter类,其继承于CSprite。以VC++ 6.0为例:

第一步、点击菜单“插入”〉“新建类”。

image.png 

第二步、在“New Class”对话框中输入类名和父类名。

image.png 

第三步、点击“更改”按钮,在新对话框中修改CMyFighter类的头文件和cpp文件的路径。将头文件保存到项目文件夹的\SourceCode\Header文件夹中,将cpp文件保存到项目文件夹下的\SourceCode\Src文件夹中。

image.png 

这里需要特别注意的是创建文件路径的问题,所有的.h头文件应该在项目文件夹\SourceCode\Header中,所有的.cpp源文件应该放在项目文件夹下的\SourceCode\Src文件夹中。

1CMyFighter的父类是CSprite类(具体声明查看CommonClass.h),构造函数为CSprite( const char *szName )

MyFighter.cpp的首部包含“CommonClass.h”。

将系统自动生成构造函数CMyFighter()改为

CMyFighter (const char* szName)。
CMyFighter:: CMyFighter (const char* szName):CSprite(szName) //对构造函数进行实现
{
 
}

子类对象创建时,要先调用父类的构造函数完成父类部分的构造。如果父类没有默认构造函数,子类的构造函数必须显示调用父类的构造函数。CMyFighter构造函数调用CSprite类构造函数,并将参数szName的值传递给它,从而将名称为szName的精灵图片与CMyFighter对象绑定起来。

2CMyFighter类添加m_fVelocityLeftm_fVelocityRightm_fVelocityUpm_fVelocityDown四个成员变量,分别表示飞机上下左右的速度,权限为private

本文档的命名采用匈牙利命名法,m_表示类成员变量,i表示整型,f表示float型,sz表示字符指针,g_表示全局变量等。

6、 CMyFighter类的构造函数中,首先初始4个方向的速度为0

m_fVelocityLeft = 0.f;
m_fVelocityRight = 0.f;
m_fVelocityUp  = 0.f;
m_fVelocityDown = 0.f;

7、 添加成员函数OnMove控制战机的游动,其参数bKeyDown表示键盘按键是否按下,iKey表示相应的是哪个按键。

void OnMove(bool bKeyDown, int iKey);

8、 编写CMyFighterOnMove方法代码。首先判断当前按键是按下还是松开的,其次判断是哪个按键的消息,根据这两个判断,为4个方向的速度矢量赋值。再次算出X后和Y轴上的速度,并设置战机的速度。

void CMyFighter::OnMove(bool bKeyDown, int iKey)
{
if(bKeyDown)
{
switch(iKey)
{
case KEY_A:  // 左
m_fVelocityLeft  = 30.f;
break;
case KEY_D:  // 右
m_fVelocityRight = 30.f;
break;
case KEY_W:  // 上
m_fVelocityUp  = 15.f;
break;
case KEY_S:  // 下
m_fVelocityDown  = 15.f;
break;
}
}
else
{
switch(iKey)
{
case KEY_A:  // 左
m_fVelocityLeft  = 0.f;
break;
case KEY_D:  // 右
m_fVelocityRight = 0.f;
break;
case KEY_W:  // 上
m_fVelocityUp  = 0.f;
break;
case KEY_S:  // 下
m_fVelocityDown  = 0.f;
break;
}
}
float fVelX = m_fVelocityRight - m_fVelocityLeft;
float fVelY = m_fVelocityDown - m_fVelocityUp;
SetSpriteLinearVelocity( fVelX,fVelY );
}

9、 CGameMain类中

1首先添加一个成员变量,代表玩家战机对象的指针m_pMyFighter

CMyFighter*   m_pMyFighter;    //玩家战机

注意需要包含头文件:

#include
 
"MyFighter.h"

2在构造函数中将m_pMyFighter赋予NULL的初始值。

3GameInit方法中初始化m_pMyFighter并设置和世界编辑的碰撞属性为WORLD_LIMIT_STICKY,当碰到世界边界时,战机静止不动。

// 创建玩家控制的Sprite
if( NULL == m_pMyFighter )
{
m_pMyFighter = new CMyFighter("ControlSprite");
m_pMyFighter->SetSpriteWorldLimit(WORLD_LIMIT_STICKY,CSystem::GetScreenLeft()-10.f,CSystem::GetScreenTop(),CSystem::GetScreenRight(),CSystem::GetScreenBottom());
}

因为用new方法创建了m_pMyFighter对象,分配了内存所以在CGameMain类的析构函数中需要调用delete方法将m_pMyFighter使用的内存释放掉。

10、 OnKeyDownOnkeyUp中响应战机OnMove方法,它们的区别只是第一个参数的值不同。下面是OnKeyDown方法中的调用。

if( 2 == GetGameState() ) //当游戏状态为2时
{
m_pMyFighter->OnMove(true,iKey);
}

在OnKeyUp中调用

if( 2 == GetGameState() )
{
m_pMyFighter->OnMove(false,iKey);
}

11、 CGameMain类的GameInit方法中显示当前积分和最高积分(初值为0)。

m_pCurScoreText->SetTextValue(0);
m_pMaxScoreText->SetTextValue(0);

 

实验二 添加子弹类,实现战机开炮

【实验内容】

1、 创建子弹类CBullet

2、 通过空格键控制飞机发射子弹;

3、 当空格键按下时,飞机每隔0.3秒发射一发子弹;

 

【实验思路】

运用面向对象的知识,我们将游戏中的元素都看为一个对象,因此我们将子弹对象抽象为CBullet类。当子弹与世界边界碰撞时,子弹消失。

当空格键按下时飞机每隔0.3发射一发子弹,因此我们在飞机类中增加一个bool型的属性m_bCanFire,控制子弹是否发射。然后增加方法OnFire,参数为游戏循环一次的时间间隔,当时间间隔大于0.3时并且m_ bCanFiretrue时,飞机发射一发子弹。飞机发射的子弹,我们在CGameMain类中进行创建。

在游戏循环的GameRun函数中调用飞机的OnFire方法,实现飞机每隔三秒发射一发子弹。

CGameMain类中添加一个创举子弹的方法,当战机发射子弹时,调用此方法。

 

【实验指导】

1、 仿照创建我方战机的方法创建CBullet

class CBullet : public CSprite
{
public:
CBullet( const char *szName);
~CBullet();
};

2、 CMyFighter增加控制是否发射子弹的变量,权限为private

bool m_bCanFire;

并添加SetCanFire方法设置其值,权限为public

void
 
SetCanFire( const bool bCan )
  
{ m_bCanFire = bCan; }

添加GetCanFire方法获取其值:

bool GetCanFire(){return m_bCanFire;}

3、 CGameMain类中添加m_iCreatedBulletCount属性,表示游戏中发射子弹的数目注意在构造函数中初始化为0

4、 CGameMain类中添加CreateBullet()函数,参数为子弹的X轴和Y轴坐标。并在该方法中创建一个子弹类,并设置子弹的位置、速度、碰撞方式。因为模板子弹的方向是朝左,所以需要设置子弹翻转朝右。

void CGameMain::CreateBullet( const float fPosX, const float fPosY )
{
char szName[MAX_NAME_LEN];// MAX_NAME_LE为CommonClass.h中宏定义 值为128
sprintf( szName, "Bullet1_%d", m_iCreatedBulletCount);
m_iCreatedBulletCount++;
CBullet *pBullet = new CBullet(szName);
pBullet->CloneSprite( "Bullet1_Template" );
pBullet->SetSpritePosition( fPosX, fPosY );
pBullet->SetSpriteFlipX(true);
pBullet->SetSpriteLinearVelocityX( 60 );
pBullet->SetSpriteWorldLimit(WORLD_LIMIT_NULL,CSystem::GetScreenLeft()-10.f,CSystem::GetScreenTop(),CSystem::GetScreenRight() + 200.f,  CSystem::GetScreenBottom());
pBullet->SetSpriteCollisionActive(true,true);
}

这里用到CBullet类,所以应该在LessonX.h中包含头文件:

#include"Bullet.h"

5、 CMyFighter中添加成员变量m_fBulletCreateTime,表示子弹的发射间隔,注意在构造函数中将其初始化为0.3

6、 CMyFighter中添加成员函数OnFire(),处理玩家战机子弹的发射。参数为游戏的时间间隔;

// 处理子弹的发射
void CMyFighter::OnFire( float fDeltaTime )
{
m_fBulletCreateTime -= fDeltaTime;
if( m_fBulletCreateTime <= 0.f && m_bCanFire==true )
{
// 固定发射时间
m_fBulletCreateTime = 0.3f;
g_GameMain.CreateBullet(GetSpritePositionX(), GetSpritePositionY() );
}
}

这里用到了g_GameMain这个全局对象,所以在CMyFight.cpp中应该包含头文件:

#include
 
"LessonX.h"

7、 CGameMainGameRun方法中,调用CMyFighter类的OnFire方法,控制玩家战机发射子弹

void CGameMain::GameRun( float fDeltaTime )

{

// 执行我方战机的循环函数
if( m_pMyFighter )
m_pMyFighter->OnFire( fDeltaTime );

}

8、 玩家发射子弹需要有当空格键按下设置CMyFighterm_bCanFire值为true。在OnKeyDown方法中添加如下代码

// 游戏进行中,按下空格发射子弹
if( 2 == GetGameState() && KEY_SPACE == iKey && NULL != m_pMyFighter )
m_pMyFighter->SetCanFire( true );

9、 同理在OnKeyUp中设置m_bCanFire值为false

 

实验三 敌方战机

【实验内容】

1、 创建一个敌方战机类CEnemyFighter

2、 战机以编辑器中HorizontalSprite_Template精灵为模板;

3、 每隔几秒创建一架敌方战机;

 

【实验思路】

运用面向对象知识,创建CEnemyFighter类。该类具有点方战机的属性,战机隔一定的事件被复制出来,然后上下浮动,开始向我方战机发射子弹,这样有助于增加敌方战机的杀伤力,也增加了游戏的趣味性。

【实验指导】

1、 仿照方便的方法创建CEnemyFighter类,其继承与CSprite,修改其构造函数。

2、 为类增添两个静态变量,一个表示表示创建敌机的数量,一个表示创建敌机的时间;

static float m_fCreateTime;   // 创建敌机的时间间隔
static int m_m_iCreatedEnemyCount;//表示创建战机数量

并在EnemyFighter.cpp文件最后进行初始化:

float CEnemyFighter::m_fCreateTime = 0.f;
int CEnemyFighter:: m_iCreatedEnemyCount= 0;

3、 CEnemyFighter类添加一个创建敌方战机静态方法createEnemyFighter (float fDeltaTime)
1)在EnemyFighter类中添加函数的声明:

void static createEnemyFighter ( float fDeltaTime );

2其参数为游戏的时间间隔。当创建战机的时间间隔递减为0时,创建战机。并重新设置时间间隔时间为13秒。

void CEnemyFighter:: createEnemyFighter ( float fDeltaTime ) //创建敌方战机
{
// 是否到时间创建
m_fCreateTime -= fDeltaTime;
if( m_fCreateTime <= 0.f )
{
// 随机一个时间,作为下次出生的时间
m_fCreateTime = (float)CSystem::RandomRange( 1, 3 );
//在以下添加创建一架敌方战机的代码
……

}

}

3)从“HorizontalSprite_Template”模板创建CEnemyFighter类对象。在createEnemyFighter函数的if( m_fCreateTime <= 0.f )判断中添加以下代码:

char szName[MAX_NAME_LEN];
sprintf(szName,"HorizontalSprite_%d", m_iCreatedSpriteCount); //给新建的敌方战机起名
m_iCreatedEnemyCount++;
CEnemyFighter *pSprite = new CEnemyFighter( szName );
pSprite->CloneSprite( "HorizontalSprite_Template" );  //克隆模板

4设置敌方飞机X轴和Y轴的坐标、速度、世界边界碰撞属性、碰撞模式等。

创建战机时,只需要战机不显示在世界边界之外就可以,即Y轴坐标在比世界边界的上下边界稍微大一点的范围之间,在此我们设置比世界边界大10个世界坐标单位

int iPosBase=CSystem::RandomRange((int)CSystem::GetScreenTop()+10,(int)CSystem::GetScreenBottom() - 10);
int iRandom = CSystem::RandomRange( iPosBase - 10, iPosBase + 10 ); 
float fPosX = (int)CSystem::GetScreenRight() + 20.f;
pSprite->SetSpritePosition( fPosX, (float)iRandom );
pSprite->SetSpriteLinearVelocityX( -10.f );  
pSprite->SetSpriteWorldLimit(WORLD_LIMIT_KILL, CSystem::GetScreenLeft()-10.f,CSystem::GetScreenTop(),CSystem::GetScreenRight() + 200.f, CSystem::GetScreenBottom() );
pSprite->SetSpriteCollisionActive(true,true);

这里用到sprintf函数,所以应该在EnemyFighter.cpp中包含头文件:

#include<stdio.h>

4、 CGameRun中,调用CEnemyFighter类的静态方法createEnemyFighter,不停地创建敌方战机。

CEnemyFighter::
 
createEnemyFighter ( fDeltaTime );

在LessonX.cpp中包含敌机类文件:

#include "enemyFighter.h"

实验四 敌方战机发射子弹

【实验内容】

1、 创建一个精灵链接类

2、 将生成的战机添加到链表中

3、 敌方战机每隔1秒发射一发子弹

4、 敌方战机飞行中上下浮动;

 

【实验思路】

因为在游戏中不断地创建子弹和战机,并有子弹和战机不断地销毁,为了有效地管理内存,这里使用链表来存储子弹和战机,并在链表中实现子弹和战机精灵的查找、删除、添加等操作。

 

【实验指导】

(一)子弹类的相关操作

1、 CBullet添加一个表示该子弹是谁发射的变量。

int m_iType;

2、 CBullet类构造函数中为此变量赋值,更改构造函数为两个参数:

CBullet::CBullet(const int iType, const char *szName) : CSprite( szName )

{

m_iType = iType;

}

3、 修改CGameMain类的CreateBullet()函数,注意同时修改函数声明。

CreateBullet() 函数中,创建子弹对象时,传入类型变量iType1表示敌方子弹,0表示是玩家子弹。并根据iType取值,设置子弹的前进速度和子弹头方向。

void CGameMain::CreateBullet( int iType, const float fPosX, const float fPosY )

{

   ……

CBullet *pBullet = new CBullet(iType, szName);

……

if( 1 == iType ) //如果iType值为1,则说明子弹为敌方战机发射。
{  
pBullet->SetSpriteLinearVelocityX( -30 );
}
else//其他情况说明为我方战机反射
{
pBullet->SetSpriteFlipX( true );
pBullet->SetSpriteLinearVelocityX( 60 );
}
}

修改MyFighter.cpp调用CreateBullet()函数的代码:

MyFighter.cpp中的OnFire()函数中g_GameMain.CreateBullet(GetSpritePositionX(), GetSpritePositionY() );改为g_GameMain.CreateBullet(0,GetSpritePositionX(), GetSpritePositionY() ); 传入玩家子弹类型。

4、 CBullet类中添加成员函数IsMyBullet(),利用m_iType判断子弹是否是玩家发射的。

bool CBullet::IsMyBullet()
{
return m_iType==0;
}

(二)链表类的相关操作

 

1、 创建一个链表类CSpriteList用来管理精灵。此类不继承CSprite类,但因链表中要保存精灵,所以仍需在文件开头声明头文件:

#include
 
"CommonClass.h"

2、 SpriteList.h文件的首部创建一个精灵结构体SpriteStruct(链表的结点类型);

struct SpriteStruct
{
CSprite *pSprite;
SpriteStruct *pNext;
SpriteStruct *pPrev;
};

3、 链表类CSpriteList添加两个私有成员变量:头节点指针和链表结点数变量。

SpriteStruct *m_pListHeader;
int  m_iListSize;

同时添加获取m_iListSize值的成员函数:

int GetListSize()  {return m_iListSize;};

4、 为链表类添加增加结点的方法。

// 添加一个Sprite到链表里
SpriteStruct *CSpriteList::AddSprite( CSprite *pSprite )
{
if( NULL == pSprite )
return NULL;
SpriteStruct *pPtr = new SpriteStruct;
pPtr->pSprite = pSprite;
pPtr->pNext  = NULL;
pPtr->pPrev  = NULL;
// 插入链表表尾
if( NULL == m_pListHeader )
m_pListHeader = pPtr;
else
{
SpriteStruct *pTemp = m_pListHeader;
while( NULL != pTemp->pNext )
pTemp = pTemp->pNext;
pPtr->pPrev  = pTemp;
pTemp->pNext = pPtr;
}
m_iListSize++;
return pPtr;
}

5、 添加根据精灵名称将其从链表中删除的方法,第二个参数表示是否将其在游戏中的精灵也删除。

void CSpriteList::DeleteSprite( const char *szName, bool bDeleteImage )
{
SpriteStruct *pPtr = NULL;
for( pPtr = m_pListHeader; NULL != pPtr; pPtr = pPtr->pNext )
{
if( strcmp( szName, pPtr->pSprite->GetName() ) == 0 )
{
// 将本指针从链表中取出(即将链表中的前后指针重新指定)
// 假设目前链表如下:有ABC三个值,A <-> B <-> C,需要删除B
// 则需要将A的Next指向C,C的Prev指向A,删除后结果为A <->C
if( NULL != pPtr->pNext )
{
pPtr->pNext->pPrev = pPtr->pPrev;
}
if( NULL != pPtr->pPrev )
{
pPtr->pPrev->pNext = pPtr->pNext;
}
// 如果是表头
if( pPtr == m_pListHeader )
{
m_pListHeader = m_pListHeader->pNext;
}
// 删除Sprite
if( bDeleteImage )
pPtr->pSprite->DeleteSprite();
// 释放内存
delete pPtr;
m_iListSize--;
return;
}
}
}

6、 添加按位序查找链表中某个节点的方法。

CSprite *CSpriteList::GetSprite( const int iIndex )
{
int    iLoop = 0;
SpriteStruct *pPtr = m_pListHeader;
while( NULL != pPtr )
{
if( iLoop == iIndex )
return pPtr->pSprite;
iLoop++;
pPtr = pPtr->pNext;
}
return NULL;
}

7、 添加通过精灵名字获得结点的方法。

CSprite* CSpriteList::GetSprite( const char *szName )
{
SpriteStruct *pPtr = m_pListHeader;
while( NULL != pPtr )
{
if( strcmp( pPtr->pSprite->GetName(), szName ) == 0 )
return pPtr->pSprite;
pPtr = pPtr->pNext;
}
return NULL;
}

8、 添加删除所有精灵的方法。

void CSpriteList::DeleteAllSprite( bool bDeleteImage )
{
SpriteStruct *pPtr    = NULL;
SpriteStruct *pPtrhNext = m_pListHeader;
while( NULL != pPtrhNext )
{
pPtr   = pPtrhNext;
pPtrhNext = pPtrhNext->pNext;
if( bDeleteImage )
pPtr->pSprite->DeleteSprite();
delete pPtr;
};
m_pListHeader = NULL;
m_iListSize  = 0;
}

(三)添加敌机发射子弹的功能

1、 CEnemyFighter类中添加成员函数OnFire(),实现在游戏循环时,战机发射子弹和上下浮动飞行的功能。其参数为游戏的时间间隔。

1添加三个成员变量,分别表示子弹的发射间隔,战机飞行时上下浮动的时间间隔,战机飞行时是上浮还是下浮。

float m_fBulletCreateTime;

float m_fFloatTime;

bool m_bFloatUp;

   注意把这这些变量在构造函数中初始化。

2) 然后在EnemyFighter.h中声明函数:

void  OnFire ( float fDeltaTime );

EnemyFighter.cpp中对函数进行实现:

void CEnemyFighter:: OnFire ( float fDeltaTime )

{

}

3) 在函数中添加代码,当表示战机创建之后,隔多久才可以开始发射子弹的变量递减到小于等于0时,开始可以创建子弹,然后开始递减子弹的发射间隔变量,当递减到小于等于0时,战机发射子弹。

m_fCanFireAfterCreated -= fDeltaTime;
if( m_fCanFireAfterCreated <= 0.f )
{
m_fBulletCreateTime -= fDeltaTime;
if( m_fBulletCreateTime <= 0.f )
{
m_fBulletCreateTime = 1.f;
g_GameMain.CreateBullet(1, GetSpritePositionX(),
GetSpritePositionY());   //1表示是敌方战机子弹
}
}

这里用到g_GameMain这个全局对象,所以应该在EnemyFighter.cpp中包含头文件:

#include"LessonX.h"

4) 添加战机上下浮动的代码。当战机浮动时,首先累计浮动的时间,当浮动时间大于1和小于0时,修改上浮还是下浮的变量值。然后获得战机此时的Y轴坐标,我们设置上下浮动的速度为6,这样就可以计算出浮动后的Y轴坐标。

if( m_bFloatUp )
{
m_fFloatTime += fDeltaTime;
if( m_fFloatTime >= 1.f )
{
m_bFloatUp = false;
}
float fPosY = GetSpritePositionY();
fPosY   += 6.f * fDeltaTime;
SetSpritePositionY( fPosY );
}
else
{
m_fFloatTime -= fDeltaTime;
if( m_fFloatTime <= 0.f )
{
m_bFloatUp = true;
}
float fPosY = GetSpritePositionY();
fPosY   -= 6.f * fDeltaTime;
SetSpritePositionY( fPosY );
}

(四)在CGameMain类中添加链表的操作

1、 CGameMain类中定义一个成员变量代表链表对象m_SpriteList

注意添加:#include  "spriteList.h"

2、 添加AddSprite方法,对链表类的添加函数进行包装,用于将游戏中的精灵添加到链表中。

void CGameMain::AddSprite( CSprite *pSprite )

{

m_SpriteList.AddSprite( pSprite );

}

3、 CGameMain类的createBullet()函数最后,将创建的子弹添加到链表中。

AddSprite(pBullet);

4、 CEnemyFighter类的createEnemyFighter()函数中,调用CGameMain类的AddSprite方法将创建好的敌方战机添加到链表中。

g_GameMain.AddSprite( pSprite );

5、 CGameMain类的GameRun方法中,遍历链表中的每个节点,获得所有敌方战机的结点,让战机执行OnFire()方法,实现战机发射子弹和上下浮动。

  int iListSize = m_SpriteList.GetListSize();
for( int iLoop = 0; iLoop < iListSize; iLoop++ )
{
CSprite * pSprite = m_SpriteList.GetSprite(iLoop);
if (pSprite != NULL && (strstr(pSprite->GetName(), "HorizontalSprite") != NULL))
{
((CEnemyFighter *)pSprite)->OnFire(fDeltaTime);
}
}

5GameEnd中添加代码,清空所有精灵,显示空格开始。

m_pBeginSprite->SetSpriteVisible(true);
m_SpriteList.DeleteAllSprite(true);
m_pMyFighter->SetSpriteVisible(false);
delete m_pMyFighter;
m_pMyFighter = NULL;

实验五 添加碰撞检测

【实验内容】

1、 创建一个精灵父类CWeapon

2、 将战机类和子弹类改为继承于CWeapon类;

3、 为游戏中的精灵添加HP属性,并为子弹添加破坏力的属性。

4、 CWeapon类添加检测碰撞的虚函数,并在各子类中实现;

5、 当玩家战机的HP值小于0是游戏结束。

 

【实验思路】

检测碰撞时,我们先获取碰撞的双方,然后再将其各自做碰撞检测。并且产生碰撞特效,是游戏看起来更加逼真。用虚函数的方式实现多态。

 

【实验指导】

(一)创建公共父类CWeapon

1、 分析我方战机类、敌方战机类、子弹类的共同特性,我们提取它们的这些共性,创建它们的父类CWeapon,使得玩家战机、敌方战机和子弹类都继承于CWeapon类。仿照上边方法创建CWeapon类:

CWeapon类添加数据成员生命值m_iHp、碰上敌方,给敌方造成的伤害值m_iDamage击毁本Sprite将获得的积分值m_iScore以及精灵类型m_iType

int  m_iHp;
int  m_iDamage;
int  m_iScore;
int  m_iType;

为这四个个属性添加SetGet方法

2、 CBulletCMyFighterCEnemyFighter三个类的父类改为CWeapon,注意需要修改各自的构造函数,并包含头文件:

#include"weapon.h"

其中,子弹类CBullet中的数据成员m_iType,因为父类CWeapon中已具有,所以将其删除(原IsMyBullet函数做相应修改)。在CWeapon中增加构造函数CWeapon(int iType, const char* szName)

class CWeapon : public CSprite
{
private:
public:
CWeapon( const char *szName );
CWeapon(int iType, const char* szName);  //为CBullet类准备
virtual ~CWeapon() { };
};
CBullet::CBullet(int iType, const char* szName):CWeapon(iType, szName)
{
}
CMyFighter::CMyFighter(const char* szName):CWeapon(szName)
{
……
}
CEnemyFighter::CEnemyFighter(const char* szName):CWeapon(szName)
{
……
}

3、 CWeapon类中添加成员函数IsDead。当m_iHp小于等于0时,精灵为死亡状态。

bool  IsDead() { return m_iHp <= 0; }

4、 CWeapon类中添加虚成员函数IsMyBullet,方法判断子弹是否是玩家战机发射的。默认返回false由子弹类CBullet重写,实现运行时多态。

virtual bool IsMyBullet()  { return false; }
bool CBullet::IsMyBullet()
{
return GetType()==0;
}

5、 CWeapon类中添加虚成员函数IsMyFighter,判断是否为玩家战机。

virtual bool IsMyFighter()  { return false; }

默认返回false由玩家战机CMyFighter重写,实现运行时多态。

bool CMyFighter::IsMyFighter()  

{

return true;

}

6、 CWeapon类中添加虚函数OnColOtherSprite,处理精灵之间的碰撞。

virtual void OnColOtherSprite( CWeapon *pOther ){}

由CBullet、CMyFighterCEnemyFighter类分别重写,实现运行时多态。

7、 修改CSpriteList类中的函数参数以及返回值,将原先所有的CSprite * 更改为CWeapon *;并将结构体中的CSprite * pSprite; 改为CWeapon * pSprite;

8、 修改CGameMainAddSprite(CSprite *pSprite );中的CSprite * CWeapon *

 

(二)为子弹、玩家战机、敌方战机做初始化

1、 GameInit函数中添加玩家战机的初始化代码,在GameInit函数最后添加代码:

m_pMyFighter->SetHp( 500 );
m_pMyFighter->SetScore( 0 );
2、 在CEnemyFighter的createEnemyFighter ( float fDeltaTime )函数中,添加如下代码,对创建的敌机进行初始化:
pSprite->SetHp(300);
pSprite->SetScore(100);
pSprite->SetDamage(200);

3、 CGameMain:CreateBullet( int iType, const float fPosX, const float fPosY )函数中,添加如下代码,对子弹进行初始化:

pBullet->SetDamage(100);

pBullet->SetHp(10);

(三)包装链表操作

添加通过索引值查找精灵、通过名字查找精灵、删除精灵的函数,对链表类的操作在CGameMain中进行包装。

CWeapon *CGameMain::GetSprite( const int iIndex )
{
return m_SpriteList.GetSprite(iIndex);
}
 
CWeapon *CGameMain::GetSprite( const char *szName )
{
return m_SpriteList.GetSprite(szName);
}
//包装删除精灵
void CGameMain::DeleteSprite( const char *szName, bool bDeleteImage )
{
m_SpriteList.DeleteSprite( szName, bDeleteImage );
}

(四)进行碰撞处理

1、 CGameMain中添加函数,通过名字判断是否是我方坦克:

bool CGameMain::IsMyFighter( const char *szName )
{
  return (strcmp( m_pMyFighter ->GetName(), szName ) == 0); 
}

2、 CGameMain类中的OnSpriteColSprite方法中添加碰撞检测。

void CGameMain::OnSpriteColSprite( const char *szSrcName, const char 
*szTarName )
{
if( 2 != GetGameState() )
return;
CWeapon *pSrcSprite = IsMyFighter(szSrcName ) ? m_pMyFighter : GetSprite( szSrcName );
CWeapon *pTarSprite = IsMyFighter(szTarName ) ? m_pMyFighter : GetSprite( szTarName );
if( NULL == pSrcSprite || NULL == pTarSprite )
return;
 
pSrcSprite->OnColOtherSprite( pTarSprite );
pTarSprite->OnColOtherSprite( pSrcSprite );
if( !pSrcSprite-> IsMyFighter () )
{
if( pSrcSprite->IsDead() )
g_GameMain.DeleteSprite( szSrcName, true );
}
if( !pTarSprite-> IsMyFighter () )
{
if( pTarSprite->IsDead() )
g_GameMain.DeleteSprite( szTarName, true );
}
}

3、 CBullet添加OnColOtherSprite方法,并实现此方法。

子弹发生碰撞后,进行血量的消耗。

void CBullet::OnColOtherSprite( CWeapon *pOther )
{
if( NULL == pOther )
return;
if(IsMyBullet () )
{
if( pOther->IsMyFighter () )
return;
SetHp( GetHp() - pOther->GetDamage() );
}
else
{
if( pOther->IsMyFighter () || pOther->IsMyBullet () )
{
SetHp( GetHp() - pOther->GetDamage() );
}
}
}

4、 CMyFighter添加OnColOtherSprite方法,并实现此方法。

void CMyFighter::OnColOtherSprite( CWeapon *pOther )
{
if( NULL == pOther )
return;
if( pOther-> IsMyBullet () )
return;
SetHp( GetHp() - pOther->GetDamage() );
if( GetHp() <= 200 )
{
SetSpriteColorGreen( 0 );
SetSpriteColorBlue( 0 );
}
else if( GetHp() <= 500 )
{
SetSpriteColorGreen( 128 );
SetSpriteColorBlue( 128 );
}
else
{
SetSpriteColorGreen( 255 );
SetSpriteColorBlue( 255 );
}
}

5、 CEnemyFighter添加OnColOtherSprite方法,并实现此方法。

void CEnemyFighter::OnColOtherSprite( CWeapon *pOther )
{
if( NULL == pOther )
return;
if( pOther-> IsMyFighter () || pOther-> IsMyBullet () )
{
SetHp( GetHp() - pOther->GetDamage() );
if (IsDead())
{
    g_GameMain.GetMyFight()->SetScore(g_GameMain.GetMyFight()->GetScore() + GetScore());
}
}
}

因为在CEnemyFighter中需要获取玩家战机,所以此操作前先在CGameMain中添加GetMyFighter()成员函数:

CMyFight * CGameMain::GetMyFighter()

{

return m_pMyFighter;

    }

6、 显示玩家战机得分。

在构造函数中创建对象:

m_pCurScoreText   = new CTextSprite("CurScoreText");

在GameInit()函数中,显示得分初值(0):

m_pCurScoreText->SetTextValue(m_pMyFighter->GetScore());

在GameRun()函数中,实时显示当前得分:

m_pCurScoreText->SetTextValue(m_pMyFighter->GetScore());

7、 当我方战机的HP值小于0是,游戏结束。增加IsGameLost方法。

bool CGameMain::IsGameLost()

{

return ( m_pMyFighter ? m_pMyFighter->IsDead() : false );

}

8、 GameMainLoop中的switch语句中的case 2中调用:

if( !IsGameLost() )

{

GameRun( fDeltaTime );

}

实验六 读写游戏记录

【实验内容】

1、 读取游戏最高分记录;

2、 写入游戏最高分记录;

 

【实验思路】

用流方式读写文件。

 

【实验指导】

1、 CGameMain中添加表示最高分数的私有成员变量m_iMaxScore,并在构造函数中初始化为0

2、 CGameMain类的GameInit方法中读取游戏记录。 

fstream ScoreFile("Score.dat",fstream::in | fstream::binary); 
if( ScoreFile.is_open() )
{
ScoreFile >> m_iMaxScore;
ScoreFile.close();
}
//更新最大积分
m_pMaxScoreText ->SetTextValue( m_iMaxScore );

 

注意需要包含头文件,并声明命名空间:

#include "fstream"

using namespace std;

3、 CGameMain类的GameEnd方法中写入记录。

if( m_iMaxScore < GetControlSprite()->GetScore() )
{
m_iMaxScore = GetControlSprite()->GetScore();
// 写文件
fstream ScoreFile("Score.dat",fstream::out | fstream::binary); 
if( ScoreFile.is_open() )
{
ScoreFile << m_iMaxScore;
ScoreFile.close();
}    
}

至此,本游戏全部结束。

 

代写CS&Finance|建模|代码|系统|报告|考试

编程类:C代写,JAVA代写 ,数据库代写,WEB代写,Python代写,Matlab代写,GO语言,R代写

金融类统计,计量,风险投资,金融工程,R语言,Python语言,Matlab,建立模型,数据分析,数据处理

服务类:Lab/Assignment/Project/Course/Qzui/Midterm/Final/Exam/Test帮助代写代考辅导

天才写手,代写CS,代写finance,代写statistics,考试助攻

E-mail:850190831@qq.com   微信:BadGeniuscs  工作时间:无休息工作日-早上8点到凌晨3点


如果您用的手机请先保存二维码到手机里面,识别图中二维码。如果用电脑,直接掏出手机果断扫描。

1513067809116994.png

 

    关键字:

天才代写-代写联系方式