在使用C#做的面向对象程序设计,做的虽然是坦克大战小游戏,结合上课内容,理解类图以及对应的语句,完成作业,也是一种收获,现在记录一下,也分享一下,共勉!有错误的话欢迎大家指出~
1.设计目的
通过该实验,掌握windows下C++程序设计的基本方法。掌握类图、代码图的分析方法。通过处理过程对计算机软件系统工作原理的进一步理解,促进对面向对象概念的系统理解以及面向对象方法的应用。
2.设计目标
1、基本目标
(1)完成代码编写设计;
(2)编译通过整个程序,并运行相应小游戏;
(3)界面成功显示,可以对坦克进行相应操作;
(4)能够正常更新己方坦克和敌方坦克的HP值;
(5)可以实现两个己方坦克的同时操作;
(6)在双人模式下,保证界面的正确运行;
(7)对最后的积分结果有着正确的显示。
2、额外目标
(1)可以任意改变墙的形状;
(2)长按空格键可以无限发射子弹;
(3)可以任意改变坦克的颜色大小;
(4)可以显示在线帮助和设置;
(5)其它自行设计的功能。
3 程序设计思路
3.1 类的设计
本设计在于用C++实现一个小游戏—坦克大战,经考虑可以用六个类来实现:
Class1:class Ctank:virtual public Draw
Class2:class Control : virtual public CTank, virtual public CBullet
Class3:class CBullet : virtual public Draw
Class4:class Draw : public CData
Class5:class CUnion
Class6:class CData
先给出整个程序的类图,类图(Class diagram)由许多(静态)说明性的模型元素(例如类、包和它们之间的关系,这些元素和它们的内容互相连接)组成。类图可以组织在(并且属于)包中,仅显示特定包中的相关内容。类图(Class diagram)是最常用的UML图,显示出类、接口以及它们之间的静态结构和关系;它用于描述系统的结构化设计。类图(Class diagram)最基本的元素是类或者接口。 类图主要用在面向对象软件开发的分析和设计阶段,描述系统的静态结构。类图图示了所构建系统的所有实体、实体的内部结构以及实体之间的关系。即类图中包含从用户的客观世界模型中抽象出来的类、类的内部结构和类与类之间的关系。它是构建其他设计模型的基础,没有类图,就没有对象图、状态图、协作图等其他UMI动态模型图,也就无法表示系统的动态行为。类图也是面向对象编程的起点和依据。
类图用于描述系统中所包含的类以及它们之间的相互关系,帮助我们简化对系统的理解,是系统分析和设计阶段的重要产物,也是系统编码和测试的重要模型依据。
类图如下:
3.1.1 CData
这个类的作用是获得和重置坦克大战地图的高和宽,下面给出一个40*45的地图程序实现,由于这个程序过长,故截图显示:“
3.1.2 class Draw
class Draw派生于class Cdata,Draw的类图是:
这个类旨在实现设置控制台窗口,如打印地图、打印字符、在一个界面显示主菜单(清屏、处理按上下键之后的显示)、设置界面、显示选项、显示选项后的参数、接受按键(如果退出、将设置更新、清除箭头、防止选项超、检测左右键、防止参数超出范围、处理指定行的内容)、清除指定行的内容、打印帮助……
下面给出显示主菜单的源码:
int Draw::showOption()
{
//清屏
Draw::clearConsole(8);
Draw::writeChar(15, 11, "坦克大战 v1.0", FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
char ch;
int option = 0;
writeChar(13, 13 , "→", FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
char * options[] = { "单人游戏", "双人游戏", "编辑地图", "设 置", "游戏帮助", "退 出" };
for (int i = 0; i < 6; i++)
{
writeChar(15, 13 + i, options[i], FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
}
while (true)
{
if (_kbhit())
{
ch = _getch();
if (ch == 27) //esc
{
return -1;
}
if (ch == 72 || ch == 80||ch == '\r') //只检测上下键
{
if (ch == 72) //UP
{
writeChar(12, 13 + option, " ", 0);
option--;
}
else if (ch == 80) //DOWN
{
writeChar(12, 13 + option, " ",0);
option++;
}
if (option < 0)
{
option = 0;
}
else if (option >= 6)
{
option--;
}
//处理按上下键之后的显示
writeChar(13, 13 + option, " ",0);
Sleep(100);
writeChar(13, 13 + option, "→", FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
writeChar(15, 13 + option, options[option], FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
if (ch == '\r')
{
return option;
}
}
}
}
}
3.1.3 class CBullet
class CBullet虛继承于class Draw,CBullet的类图如下:
class CBullet实现的功能是:清除子弹、子弹向着指定的方向移动一步、打印子弹如果是空道才打印返回true,否则返回false,然后调用attackSomeThing()等功能。
下面给出子弹移动的代码:
void CBullet::move(int direction)
{
this->clearBullet();
if (this->printBullet())
{
this->oldBulletY = BulletY;
this->oldBulletX = BulletX;
switch (direction)
{
case UP:
--BulletY;
break;
case DOWN:
++BulletY;
break;
case LEFT:
--BulletX;
break;
case RIGHT:
++BulletX;
break;
}
}
}
3.1.4 class Ctank:virtual public Draw
class Ctank虛继承于class Draw,Ctank实现的功能是:打印坦克、将玩家1(2)写入地图、将坦克坐标写到地图上、对坦克进行碰壁检测、清除坦克、移动坦克等。
它的类图是:
下面给出移动坦克的源码:
void CTank::move(int direction)
{
round(time(NULL));
//判断坦克是否可以通过
if (tankIsThrough(this->TankX,this->TankY, direction))
{
switch (direction)
{
case UP:
this->clearTank();
this->TankY--;
this->Direction = UP;
this->printTank();
break;
case DOWN:
this->clearTank();
this->TankY++;
this->Direction = DOWN;
this->printTank();
break;
case LEFT:
this->clearTank();
this->TankX--;
this->Direction = LEFT;
this->printTank();
break;
case RIGHT:
this->clearTank();
this->TankX++;
this->Direction = RIGHT;
this->printTank();
break;
}
}
else //不能通过就只打印
{
if (TankID >= 2) //用于敌方坦克在碰到障碍物时改变方向
{
switch (this->Direction)
{
case UP:
this->Direction = (int)rand() % 4; break;
case DOWN:
this->Direction = (int)rand() % 4; break;
case LEFT:
this->Direction = (int)rand() % 4; break;
case RIGHT:
this->Direction = (int)rand() % 4; break;
}
}
else
{
this->Direction = direction;
}
this->printTank();
}
}
3.1.5 class Control : virtual public CTank, virtual public CBullet
class Control虛继承于CTank和CBullet,Control的类图如下:
class Control实现的功能是逻辑算法,控制坦克和子弹,检测坦克是否可以通过、循环输出子弹夹里面的子弹、开始游戏(游戏人数)、画记分板、更新我方和敌方记分板、打印初始化坦克等功能。下面给出生成第一个子弹的源码:
void Control::sendBullet(CTank& tank)
{
//生成一个子弹
clock_t firstTime = clock();
switch (tank.Direction)
{
case UP:
bullet.InitBullet( tank.TankID, tank.TankX + 1, tank.TankY - 1, tank.Direction, true, firstTime, tank.TankX + 1, tank.TankY - 1 );
break;
case DOWN:
bullet.InitBullet(tank.TankID, tank.TankX + 1, tank.TankY + 3, tank.Direction, true, firstTime, tank.TankX + 1, tank.TankY + 3);
break;
case LEFT:
bullet.InitBullet(tank.TankID, tank.TankX - 1, tank.TankY + 1, tank.Direction, true, firstTime, tank.TankX - 1, tank.TankY + 1);
break;
case RIGHT:
bullet.InitBullet(tank.TankID, tank.TankX + 3, tank.TankY + 1, tank.Direction, true, firstTime, tank.TankX + 3, tank.TankY + 1 );
break;
}
//将子弹存入VBullet容器
CUnion::ListBullet.push_back(bullet);
//移动第一步
bullet.move(tank.Direction);
}
3.1.6 class CUnion
这个类所要实现的功能是敌军被子弹击中 更新HP、更新计分板、处理子弹碰到障碍物等问题,下面给出击中后更新HP和记分板的源码:
void CUnion::enemyBeAttack(int posX, int posY)
{
int tank = CData::GetTypeOfMap(posX, posY);
VTank[tank + 2].clearTank();
VTank[tank + 2].setnMaxHP(VTank[tank + 2].getMaxHP() - 1);
Control::updateTableau();
}
3.2主程序
#include "stdafx.h"
#include "Control.h"
int _tmain(int argc, _TCHAR* argv[])
{
Control con;
con.init();
while (true)
{
int option = Draw::showOption();
switch (option)
{
case 0:con.gameStart(1); break; //单人游戏
case 1:con.gameStart(2); break; //双人游戏
case 2:Draw::editMap(); break; //编辑地图
case 3:Draw::showConfig(); break; //设置
case 4:Draw::help(); break; //游戏帮助
case 5:return 0; break; //退出游戏
}
}
return 0;
}
}
可见,主程序先对Control类里面的成员变量进行初始化,然后进入循环,进入玩家选择界面,确定参与人数,是否需要编辑地图,是否需要进行设置以及游戏帮助和是否退出游戏。
3.3 Codemap:
Codemap可以更加清楚的看清程序之间的关系,可以通过创建代码图来可视化代码中的依赖项。 代码图可帮助查看代码如何相互配合,而无需读取文件和代码行。
可见,六个类之间的聚合链路都很广,它们之间的依赖关系都很强。
4 测试过程
4.1 进入游戏开始界面
4.2 选择单人模式,进入游戏
4.3 单人操作
可见,发射子弹,移动、HP、记分板等功能正常
4.4 双人模式
在运行过程中,功能也都按照最初想法实现了
4.5 运行设置和帮助
点击设置之后,可以调整敌方坦克数量、敌方坦克攻击力、敌方坦克血量、敌方坦克移动速度、敌方坦克自动寻路等
点击帮助之后,可以查看玩家1和玩家2的玩法操作。
综上,经过测试,最初的设想均已实现,坦克大战V1.0设计成功。
5.设计感想与总结
1)做大程序前,要学会做程序框架图。
以前,编写的都是小程序,可能不需要做框架图就可以在脑子中构思好,但是一旦程序量大了之后,脑子是运转不过来的,很容易混乱,这时候,做一个总的程序框架图是很有必要的,不用非常细腻,具体到每一个函数,只需要将程序的大体结构画出来,这样,你才知道具体的路该怎么走,从哪起步,接下来该干什么,对自己的行动有一个规划,这样做,可以使程序的结构很清晰,又能节省很多时间去思考接下来该干什么,这是一种很好的思想。
2)学会借鉴别人的程序
小程序看别人的,可能会被称为抄袭,但是如果大程序的每个语句都由自己来编写,在我看来是一种很愚蠢的方法,有个名人曾说过,天下文章一大抄,牛顿也说过,只有站在巨人的肩膀上,才能看的更远,所以对于大程序而言,有些可以借鉴别人的,没有必要全部自己来编写,可以在别人的基础上进一步来改进,这样既节省时间,又可以使自己的程序到达一个更高的水平。
3)学会用调试去发现和解决问题
程序量较小的时候,可能用脑子去模拟程序的运作就可以想出来错误在哪里,但是如果程序量大,不可能再去用脑子模拟,这时候就要用调试去解决,首先,需要找到错误的大概位置,设置断点,运行调试,一步一步,查看关键变量的数值,或者在关键位置设一个标志位,看标志位的值,同时看窗口的运行结果。这样,就能发现问题,解决问题。
4)写程序日志
每天对这天遇到的问题和解决方法,以及做的工作都记录下来,对编写程序能力的提升会有很大的帮助,这样做,解决问题的方法越来越多,遇到的问题也不会慌张,这样做,积累的是解决办法,而不是积累错误。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/99866.html