10 C语言课程设计_坦克大战(提高篇)

  • 格式:doc
  • 大小:179.00 KB
  • 文档页数:17

下载文档原格式

  / 17
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

C语言课程设计--坦克大战

一、游戏介绍

玩家坦克与敌方坦克在街道中进行巷战,玩家坦克被击中、玩家指挥部被击中或游戏时间到,一局游戏结束。

二、实验目的

综合应用C语言知识和设计知识开发一款小游戏。

三、实验内容

初始界面如下图。

按下空格键后游戏开始,“空格开始”消失,载入地图,并把玩家坦克设置在指挥部左侧。

游戏时间到,比如30秒,玩家坦克被敌方坦克摧毁,或者玩家指挥部被摧毁,一局游戏结束,游戏回到初始界面,并显示上一局的分数。

游戏区域为下图中最内部的黑色区域,左上角坐标[-26, -22],右下角坐标为[26, 22]。墙为正方形,边长为4,坦克也是正方形,比墙略小一点。

玩家用WASD键控制坦克上、下、左、右运行,按J键开炮。玩家坦克碰到墙就停下来,需要调转方向才能继续前进。玩家坦克开炮,一炮就能摧毁一块墙,或者一辆敌方坦克。玩家没摧毁一辆敌方坦克,加1分。

玩家指挥部被坦克或者炮弹(不管玩家还是敌方)碰上,都会被摧毁。

每隔几秒钟,比如3秒,就会产生一辆敌方坦克。敌方坦克每隔一段时间,比如1秒,就自动开炮。敌方坦克遇到墙就会停下来。停下来的坦克,前方的墙如果被摧毁了,又能继续前进。每隔几秒钟,比如2秒,敌方坦克就会顺时针变换一个方向前进。

四、实验准备

本实验中可能用到的C 语言标准库函数和FunCode API Stdio.h

Math.h

String.h

FunCode API

原图的角度

获得的旋转角度即为两张图片的

五、程序初步设计

如果程序规模比较小的时候,我们习惯一上手就写代码,边写边调整。但是当程序越来越大,代码越来越多的时候,如果我们还用这种方式编程,程序写到一半的时候,你可能会恨不得重写一遍。

此,我们在写代码之前,先把程序功能细化一下,并初步设计好程序结构,包括数据结构和自定义函数。有了比较清晰的思路以后,再开始开发程序。

在本项目中,我们要操作的对象有6个:玩家坦克、敌方坦克、玩家子弹、敌方子弹、墙、玩家指挥部。

其中,墙和指挥部都比较简单,主要是前4种,而且它们有共通性:名称、速度、位置,因此,可以考虑用一个结构体来表示。此外,我们需要用一种数据结构来管理它们。由于敌方坦克、子弹的数量都无法事先确定,所以我们选择链表而不是数组来管理它们。

struct Weapon{

char szName[128]; // 精灵名称

float fPosX, fPosY; // 精灵坐标

float fSpeedX, fSpeedY; // X和Y方向上速度

float fFireTime; // 敌方坦克距下一次开炮的剩余时间

int iHp; // 生命值

int iDir; // 朝向:0 - 上方;1 - 右方;2 - 下方;3 - 左方

int iType; // 类型: 0 - 我方坦克;1 - 敌方坦克;2 - 我方

// 子弹; 3 - 敌方子弹

Weapon* pNext; // 指向下一个节点的指针

};

其中,iDir和iType用不同整数表示不同含义。如果在小程序中,我们可以在代码里直接调用这些整数,但是想象一下下面情况:

如果你连续写了三小时代码,你还能清晰记得1表示什么含义吗?

你时不时需要找到Weapon结构体定义查看这些数字的含义,然后再引用,出错的概率有多大?

如果你一不小心,在某处搞错了,比如要处理的是敌方坦克,你却引用2,需要多少时间才能把错误找出来?

因此,在做一个比较大的程序时,我们强烈建议用定义一个枚举类型,用我们熟悉的单词来表示这种数字的含义。

enum Direction{

UP = 0, // 上方

RIGHT = 1, // 右方

DOWN = 2, // 下方

LEFT = 3 // 左方

};

enum Role

{

MYTANK = 0, // 我方坦克

ENEMYTANK = 1, // 敌方坦克

MYBULLET = 2, // 我方子弹

ENEMYBULLET = 3 // 敌方子弹

};

除此之外,我们还需要定义一些全局变量来控制程序,根据程序需求,我们目前能考虑到表示游戏状态的变量、表示游戏得分的变量、游戏剩余时间变量以及距离下一辆坦克产生的时间等变量;

// 游戏地图,0表示此处为空,1表示此处有墙。根据游戏空间大小、墙以及坦克大小,// 我们把地图分成11行,13列,每格大小刚好放一块墙。

i nt iMap[11][13];

正如前面所示,我们用枚举类型来表示一些数字的含义。出于同样的原因,我们也定义一些全局常量来存储某些数值。

const float GAME_TIME = 30.f; // 一局游戏时间

const float CREATE_TANK_TIME = 5.f; // 每批次生成坦克的时间间隔const float TANK_SPEED = 5.f; // 坦克速度

const float BULLET_SPEED = 8.f; // 子弹速度

const float FIRE_TIME = 2.f; // 坦克开炮时间间隔

const float WORLD_LEFT = -26.f; // 游戏场景边界左值

const float WORLD_TOP = -22.f; // 游戏场景边界左值

const float WORLD_RIGHT = 26.f; // 游戏场景边界左值

const float WORLD_BOTTOM = 22.f; // 游戏场景边界左值

好处有两点:第一、跟枚举类型一样,用有具体含义的单词,在具体调用时容易记住,不会搞错;第二、如果我们需要调整这些数值,只需在全局常量初始化这里调整就可以了。比如我们要调整坦克速度,没有定义全局常量的话,我们就要找到各处代码用到坦克速度赋值的地方修改。这样,既麻烦又容易出错。

程序本身由一个main.cpp文件组成,包含7个函数,一个主函数WinMain和6个事件函数(键盘按下、键盘弹起、鼠标移动、鼠标点击、精灵与精灵的碰撞、精灵与世界边界的碰撞)。

我们增加两个文件,List.h和List.cpp,主要用来声明和定义结构体以及链表操作的函数。链表操作至少包括下面四个操作:

AddToList // 往链表里添加一个节点;

DeleteNode // 从链表里删除一个节点;

FindeNode // 从链表里查找一个节点;

DeleteList // 删除整个链表。

一局游戏结束,我们需要把本局游戏中还没删除的精灵全部删除,从而保持下一局游戏