09 C++课程设计 - 坦克大战 下载本文

3、这是因为,我们创建的类集成了CSprite类,但是却没有把这个类的声明文件include

进来。因此我们在新建类的头文件中,做如下操作: #include \4、编译程序,发现如下提示:

打开CommonClass.h文件,找到CSprite类的定义,可以发现该类没有缺省构造函数,只有一个带参数的构造函数。因此,作为它的子类,构造函数也必须带参数,并且将参数传递给父类。构造函数的声明和定义修改如下: CTankPlayer(const char* szName);

CTankPlayer::CTankPlayer(const char* szName):CSprite(szName) { }

5、为CTankPlayer类添加m_iDir,m_fSpeedX,m_fSpeedY,m_iHp四个成员变量(成员变

量。用来表示坦克在X轴和Y轴方向上的速度以及运行的方向,并且在构造函数中初始化为0。这里规定,m_iDir的值为0、1、2、3,分别表示上、右、下、左。 成员函数的声明和定义如何添加,访问权限是什么,可参考实验一,下文不再继续提示),分别表示运动方向、X轴、Y轴速度以及血量值。本文档的命名采用匈牙利命名法,m_表示类成员变量,i表示整型,f表示float型,sz表示字符指针,g_表示全局变量等。

同时需要在public权限下定义获取和设置这些变量的Get和Set方法,可在LessonX.h文件中完成:

//set方法

void SetHp(int hp) {m_iHp = hp;} void SetDir(int dir) {m_iDir = dir;} void SetSpeedX(float speedX) {m_fSpeedX = speedX;} void SetSpeedY(float speedY) {m_fSpeedY = speedY;} //get方法

8

上海锐格软件有限公司 int GetHp() {return m_iHp;} int GetDir() {return m_iDir;} float GetSpeedX() {return m_fSpeedX;} float GetSpeedY() {return m_fSpeedY;}

6、在CTankPlayer类的构造函数完成上面四个成员变量的初始化。

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

m_iDir=0; m_fSpeedX=0.f; m_fSpeedY=0.f;

m_iHp=2;

}

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

7、为CTankPlayer类添加Init函数,该函数主要用来完成该类的初始化工作。这里,先

调用setHp方法设置血量。然后调用父类的SetSpritePosition函数将坦克精灵设置在屏幕中央(0,0)处。接下来给坦克精灵设置时间边界的大小,与世界边界的碰撞模式为WORLD_LIMIT_NULL,表示精灵与世界边界碰撞的响应由代码完成,同时设置坦克碰撞模式为发送碰撞和接收碰撞。

void CTankPlayer::Init() {

SetHp(2);

SetSpritePosition(0.f,0.f);

SetSpriteWorldLimit(WORLD_LIMIT_NULL, -26, -22, 26, 22);

SetSpriteCollisionActive(1,1);//设置为可以接受和发生碰撞

SetSpriteVisible(true); }

8、完成CTankPlayer类相关定义后,在CGameMain类中增加一个私有成员变量

m_pTankplayer,类型为CTankPlayer*。 注意在LessonX.h添加头文件:

#include\

9、按下空格键后,程序会调用键盘按下事件响应函数,将m_iGameState的值改为1,

游戏进入开始状态(见实验一)。程序再次执行CGameMain::GameMainLoop函数时,根据m_iGameState的值调用并执行CGameMain::GameInit函数。因此,可以在该函数中创建我方坦克,并调用CTankPlayer::Init函数来完成该类对象的初始化工作。

m_pTankPlayer=new CTankPlayer(\新建一个名字是myPlayer的我方坦克对象

m_pTankPlayer->CloneSprite(\我方坦克克隆在funcode模板中存在的名字为player的坦克,表示新建的坦克对象有现在精灵的所有属性 m_pTankPlayer->Init();

10、接下来,我们为CTankPlayer类添加OnMove函数,参数iKey、bPress分别表示按

下的是哪个按键和按键是否按下。首先声明该函数,访问权限为public:

9

void OnMove(int iKey, bool bPress);

11、接着,完成OnMove方法。

void CTankPlayer::OnMove(int iKey, bool bPress) {

if(bPress) {

switch (iKey) {

case KEY_W: SetDir(0); SetSpeedX(0); SetSpeedY(-8); break; case KEY_D: SetDir(1); SetSpeedX(8); SetSpeedY(0); break; case KEY_S: SetDir(2); SetSpeedX(0); SetSpeedY(8); break; case KEY_A: SetDir(3); SetSpeedX(-8); SetSpeedY(0); break; }

SetSpriteRotation(float(90*GetDir())); //用方向值乘于90得到精灵旋转度数 SetSpriteLinearVelocity(GetSpeedX(),GetSpeedY()); } else {

if(iKey == KEY_W || iKey == KEY_D || iKey == KEY_S || iKey == KEY_A) {

SetSpeedX(0); SetSpeedY(0);

SetSpriteLinearVelocity(GetSpeedX(),GetSpeedY()); } } }

用参数bPress来判断键盘是按下还是弹起。如果bPress为false,表示键盘弹起,且弹起的键是WASD键时,设置坦克的X轴和Y轴移动速度都为0。如果bPress为

10

上海锐格软件有限公司

true,表示键盘按下,根据按下的键,为m_iDir,m_fSpeedX,m_fSpeedY赋予相应的值。SetSpriteRotation和SetSpriteLinearVelocity函数用来设置精灵的角度和线性速度,具体含义参考CommonClass.h文件。 12、在CGameMain类的OnKeyDown函数中,通过调用CTankPlayer类的OnMove方法,

根据按下的键,控制坦克朝指定方向运动。只有游戏进入开始状态,按键才有效。注意:OnMove参数bPress的值为true。在OnKeyDown函数中添加代码如下:

if(m_iGameState == 2) {

m_pTankPlayer->OnMove(iKey, true); }

13、编译并运行程序。按空格键开始,按WASD键,坦克会向规定的方向运动。但是松

开按键后,坦克继续前进,不会停止下来。

14、在CGameMain::OnKeyUp函数中调用CTankPlayer的OnMove方法,参数bPress的

值为false。

void CGameMain::OnKeyUp(const int iKey) {

if(m_iGameState == 2) {

m_pTankPlayer->OnMove(iKey, false); } }

15、编译并运行程序,按下WASD键,坦克运行;松开按键,坦克停止。接下来,我们

来实现坦克运行到黑色区域边界停止运动的效果。

16、当坦克精灵碰到边界时,将精灵的速度都设为0,精灵停止运动。首先,我们需要

给该精灵设置世界边界的碰撞模式。可以在CTankPlayer::GameInit()中完成。 17、用字符串处理函数strstr()来判断碰到世界边界的精灵是否为我方坦克。当碰到世界

边界的精灵名字中含有”player”的时候,strstr会返回一个非空值。因此代码如下:

void CGameMain::OnSpriteColWorldLimit( const char *szName, const int iColSide ) {

if(strstr(szName,\判断碰到世界边界的坦克是否为我方坦克 {

m_pTankPlayer->SetSpriteLinearVelocity(0,0); } }

实验三 坦克开炮

【实验内容】

1、创建子弹类CBullet;

2、通过按键J控制坦克开炮; 【实验运行结果】

11