“坦克大战”小游戏(C语言)源代码及其详解注释
运行实现之后的图片结果如下:
笔记
1.敌人必须先移动再创造,不然会出现尸体复活。
原因:敌人死亡之后,中心点是无法再次定位的,敌人刷新的那一帧会出现两个中心点。
解决方法:再主函数里把敌人移动的函数放在创造敌人的函数之前。
2.敌人子弹和玩家子弹相撞时,必定只会有一方的子弹消失,看概率。
原因:两方子弹相撞只会有一方的子弹先到达另一方的前面然后消失,跟子弹移动速度(停留时间)有关。
解决方法:把子弹的消失判定点往前加一个点来判断是否是敌方的子弹(暂时不解决)
3.敌人发射子弹时,有时候会出现发射子弹的方向和敌人的方向不一致。
原因:敌人转向时是先改变方向,下一次移动时再转过去,子弹发射的时间被卡在了两者之间。
解决方法:将发射子弹写在移动的里面,这样会改变敌人射击的频率,移动的条件符合,再判断射击条件,两者都符合才会射击。(不优)
添加一个坦克属性来设置坦克预备转向。
4.敌人的子弹在接近玩家附近一格时,玩家向反方向移动会消除子弹,反之相同。(触发几率很小)
原因:玩家移动的时候会把之前的所在的一条三个格子全都清零。
解决方法:暂无
5.当玩家的前方是敌方坦克时,无法发射子弹,反之相同。不能贴脸射击。
原因:发射子弹的条件是坦克的前方无阻挡物,才会生成子弹,在子弹生成之后才会飞行和击毁。
解决方法:在发射子弹时添加条件判断。(不优,感觉会影响游戏体验)
6.敌人A和B的行动模式是一样的,可以把他们的移动写在一个函数里,但是运行的时候会出错只有一个坦克会动。
原因:函数传入的参数是在函数里改变了不会影响外面的参数,这需要用到指针。
解决方法:把所有的坦克参数全都变成指针类型?(太复杂了)
7.敌人坦克在移动的时候会被自己的子弹挡住然后转向,玩家也是(几率很小,不过不影响游戏)
#pragma warning(disable:4996)
#include<stdio.h>
#include<iostream>
#include<conio.h>
#include<time.h>
#include<windows.h>
#include<graphics.h>
#define ROW 48
int map[ROW][ROW];//正方形的地图
int refresh;//记录当前刷新的次数
int FlyBullet_P_C, FlyBullet_E_C;//控制玩家和敌人子弹的飞行速度
struct Tank{//坦克的参数
int x;//横向坐标
int y;//纵向坐标
int dir;//方向
int rdir;//预备转向
int dirt;//记录转向的时间
int dirc;//控制转向频率
int life;//坦克的生命
int maxl;//坦克最大生命值
int dietime;//坦克的死亡时间
int str;//子弹的伤害
int mt;//记录移动时间
int mc; //控制移动速度
int st;//记录射击时间
int sc;//控制射速
int score;//击败敌人的得分/玩家积累的分数
int shape[3][3];//坦克的外形
} player, enemyA, enemyB, enemyC, enemyD, enemyE;//创建玩家敌人
int Player[3][3]{ {0,2,0},
{2,4,2},
{2,2,2} };//玩家的坦克
int empty[3][3];//空数组用于转向
struct CreatePoint {//敌人的刷新点
int x;//刷新点横向坐标
int y;//纵向坐标
}cp[5];
int propbox;//道具编号;
int propt, propc;//记录,控制道具刷新时间
int propflag;//判断场上是否有道具
//游戏开始时的初始化
void GameStart() {
initgraph(640, 480);//窗口大小
setbkcolor(WHITE);//背景颜色
memset(map, 0, sizeof(map));//初始化数组为0
for (int i = 0; i < ROW; i++) map[0][i] = map[ROW - 1][i] = 1;
for (int i = 1; i < ROW - 1; i++) map[i][0] = map[i][ROW - 1] = 1;
for (int y = 0; y < ROW; y++) {//y轴向下
for (int x = 0; x < ROW; x++) {//x轴向右
if (map[y][x]) {
setlinecolor(BLACK);
setfillcolor(RGB(213, 222, 217));
fillrectangle(x * 10, y * 10 + 10, x * 10 + 10, y * 10);
}
}
}
refresh = 0;
map[45][23] = 4;//玩家的出生点
map[44][23] = map[46][23] = map[45][22] = map[45][24] = map[46][22] = map[46][24] = 2;
player.life = 3;
player.score = 0;
player.dir = 1;
player.str = 1;
player.mc = 3;
player.sc = 10;
player.maxl = 3;
FlyBullet_P_C = 1;
FlyBullet_E_C = 3;
enemyA.life = enemyB.life = enemyC.life = enemyD.life = enemyE.life = -1;
enemyA.dir = enemyB.dir = enemyC.dir = enemyD.dir = enemyE.dir = 2;
enemyA.rdir = enemyB.rdir = enemyC.rdir = enemyD.rdir = enemyE.rdir = 2;
int Enemy[3][3]{ {15,15,0},
{0,20,15},
{15,15,0} };//敌人的坦克
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (Enemy[i][j]) {
enemyA.shape[i][j] = Enemy[i][j];//敌人A 中心为20 外壳为15
enemyB.shape[i][j] = Enemy[i][j] + 1;//敌人B 中心为21 外壳为16
enemyC.shape[i][j] = Enemy[i][j] + 2;//敌人C 中心为22 外壳为17
enemyD.shape[i][j] = Enemy[i][j] + 3;//敌人D 中心为23 外壳为18
enemyE.shape[i][j] = Enemy[i][j] + 4;//敌人E 中心为24 外壳为19
}
}
}
//地图地形
for (int i = 0; i < 5; i++) map[10][10 + i] = map[37][10 + i] = map[10][37 - i] = map[37][37 - i] = 1;
for (int i = 0; i < 4; i++) map[11 + i][10] = map[36 - i][10] = map[11 + i][37] = map[36 - i][37] = 1;
map[23][23] = map[23][24] = map[24][23] = map[24][24] = 1;
//初始化敌人的刷新点
cp[0].x = 2;
cp[0].y = 2;
cp[1].x = 24;
cp[1].y = 2;
cp[2].x = 45;
cp[2].y = 2;
cp[3].x = 2;
cp[3].y = 23;
cp[4].x = 45;
cp[4].y = 23;
//道具的刷新率
propt = 0;
propc = 300;
propflag = -1;
}
//绘制地图
void DrawMap() {
for (int y = 1; y < ROW-1; y++) {//y轴向下
for (int x = 1; x < ROW-1; x++) {//x轴向右
switch (map[y][x]) {
case 0:break;
case 1:
setlinecolor(BLACK);
setlinestyle(NULL, 1);
setfillcolor(RGB(213,222,217));//灰色
fillrectangle(x * 10, y * 10 + 10, x * 10 + 10, y * 10);
break;//墙壁
case 2://玩家坦克的外壳
case 4://玩家的中心点
setlinecolor(BLACK);
setlinestyle(NULL, 1);
setfillcolor(RGB(0, 140, 158));//青蓝色
fillrectangle(x * 10, y * 10 + 10, x * 10 + 10, y * 10);
break;
case 19://敌人E的外壳
setlinecolor(BLACK);
setlinestyle(NULL, 1);
setfillcolor(RED);
fillrectangle(x * 10, y * 10 + 10, x * 10 + 10, y * 10);
break;
case 18://敌人D的外壳
case 17://敌人C的外壳
setlinecolor(BLACK);
setlinestyle(NULL, 1);
setfillcolor(RGB(89, 79, 79));//褐色
fillrectangle(x * 10, y * 10 + 10, x * 10 + 10, y * 10);
break;
case 16://敌人B的外壳
case 15://敌人A的外壳
setlinecolor(BLACK);
setlinestyle(NULL, 1);
setfillcolor(RGB(85, 98, 112));//深灰色
fillrectangle(x * 10, y * 10 + 10, x * 10 + 10, y * 10);
break;
case 24://敌人E的中心点
setlinecolor(BLACK);
setlinestyle(NULL, 2);
switch (enemyE.life) {
case 0:setfillcolor(RGB(255, 255, 255)); break;
case 1:setfillcolor(RGB(255, 0, 0)); break;
case 2:setfillcolor(RGB(255, 165, 0)); break;
case 3:setfillcolor(RGB(255, 255, 0)); break;
case 4:setfillcolor(RGB(0, 255, 0)); break;
case 5:setfillcolor(RGB(0, 255, 255)); break;
case 6:setfillcolor(RGB(0, 0, 255)); break;
case 7:setfillcolor(RGB(160, 32, 240)); break;
}
【】fillrectangle(x * 10, y * 10 + 10, x * 10 + 10, y * 10);//边框填充矩形
break;
case 23://敌人D的中心点
setlinecolor(BLACK);
setlinestyle(NULL, 2);
switch (enemyD.life) {
case 0:setfillcolor(RGB(255, 255, 255)); break;
case 1:setfillcolor(RGB(255, 0, 0)); break;
case 2:setfillcolor(RGB(255, 165, 0)); break;
case 3:setfillcolor(RGB(255, 255, 0)); break;
case 4:setfillcolor(RGB(0, 255, 0)); break;
case 5:setfillcolor(RGB(0, 255, 255)); break;
case 6:setfillcolor(RGB(0, 0, 255)); break;
case 7:setfillcolor(RGB(160, 32, 240)); break;
}
fillrectangle(x * 10, y * 10 + 10, x * 10 + 10, y * 10);
break;
case 22://敌人C的中心点
setlinecolor(BLACK);
setlinestyle(NULL, 2);
switch (enemyC.life) {
case 0:setfillcolor(RGB(255, 255, 255)); break;
case 1:setfillcolor(RGB(255, 0, 0)); break;
case 2:setfillcolor(RGB(255, 165, 0)); break;
case 3:setfillcolor(RGB(255, 255, 0)); break;
case 4:setfillcolor(RGB(0, 255, 0)); break;
case 5:setfillcolor(RGB(0, 255, 255)); break;
case 6:setfillcolor(RGB(0, 0, 255)); break;
case 7:setfillcolor(RGB(160, 32, 240)); break;
}
fillrectangle(x * 10, y * 10 + 10, x * 10 + 10, y * 10);
break;
case 21://敌人B的中心点
setlinecolor(BLACK);
setlinestyle(NULL, 2);
switch (enemyB.life) {
case 0:setfillcolor(RGB(255, 255, 255)); break;
case 1:setfillcolor(RGB(255, 0, 0)); break;
case 2:setfillcolor(RGB(255, 165, 0)); break;
case 3:setfillcolor(RGB(255, 255, 0)); break;
case 4:setfillcolor(RGB(0, 255, 0)); break;
case 5:setfillcolor(RGB(0, 255, 255)); break;
case 6:setfillcolor(RGB(0, 0, 255)); break;
case 7:setfillcolor(RGB(160, 32, 240)); break;
}
fillrectangle(x * 10, y * 10 + 10, x * 10 + 10, y * 10);
break;
case 20://敌人A的中心点
setlinecolor(BLACK);
setlinestyle(NULL, 2);
switch (enemyA.life) {
case 0:setfillcolor(RGB(255, 255, 255)); break;//黑
case 1:setfillcolor(RGB(255, 0, 0)); break;//红
case 2:setfillcolor(RGB(255, 165, 0)); break;//橙
case 3:setfillcolor(RGB(255, 255, 0)); break;//黄
case 4:setfillcolor(RGB(0, 255, 0)); break;//绿
case 5:setfillcolor(RGB(0, 255, 255)); break;//青
case 6:setfillcolor(RGB(0, 0, 255)); break;//蓝
case 7:setfillcolor(RGB(160, 32, 240)); break;//紫
}
fillrectangle(x * 10, y * 10 + 10, x * 10 + 10, y * 10);
break;
case 5://玩家向上的子弹
case 6://玩家向右的子弹
case 7://玩家向下的子弹
case 8://玩家向左的子弹
setlinecolor(BLACK);
setlinestyle(NULL, 1);
circle(x * 10 + 5, y * 10 + 5, 3);//空心圆 玩家的子弹
break;
case 11://敌人向上的子弹
case 12://敌人向右的子弹
case 13://敌人向下的子弹
case 14://敌人向左的子弹
setlinecolor(BLACK);
setlinestyle(NULL, 1);
setfillcolor(BLACK);
fillcircle(x * 10 + 5, y * 10 + 5, 3);//黑色实心圆 敌人的子弹
break;
case 25://装道具的盒子
switch (propbox) {
case 1:
setlinecolor(BLACK);
setlinestyle(NULL, 2);
setfillcolor(RED);
fillcircle(x * 10 + 5, y * 10 + 5, 5);
break;
case 2:
setlinecolor(BLACK);
setlinestyle(NULL, 2);
setfillcolor(RGB(242, 196, 90));
fillcircle(x * 10 + 5, y * 10 + 5, 5);
break;
case 3:
setlinecolor(BLACK);
setlinestyle(NULL, 2);
setfillcolor(RGB(77, 188, 233));
fillcircle(x * 10 + 5, y * 10 + 5, 5);
break;
case 4:
setlinecolor(BLACK);
setlinestyle(NULL, 2);
setfillcolor(RGB(42, 4, 74));
fillcircle(x * 10 + 5, y * 10 + 5, 5);
break;
case 5:
setlinecolor(BLACK);
setlinestyle(NULL, 5);
setfillcolor(RGB(254, 67, 101));
fillrectangle(x * 10, y * 10 + 10, x * 10 + 10, y * 10);
break;
}
break;
case 10:
setfillcolor(RGB(250, 105, 0));
setlinecolor(RGB(204, 51, 63));
setlinestyle(NULL, 2);
POINT pts[] = { {x * 10 - 10, y * 10 - 8}, {x * 10, y * 10}, {x * 10 - 10, y * 10 + 5},{x * 10 + 1,y * 10 + 7},{x * 10 - 5,y * 10 + 11},{x * 10 + 4,y * 10 + 12},{x * 10 + 3,y * 10 + 18},{x * 10 + 8,y * 10 + 11},{x * 10 + 12,y * 10 + 20},{x * 10 + 10,y * 10 + 9},{x * 10 + 20,y * 10 + 11},{x * 10 + 13,y * 10 + 5},{x * 10 + 20,y * 10 - 4},{x * 10 + 10,y * 10 + 2},{x * 10 + 10,y * 10 - 10},{x * 10 + 7,y * 10 - 2} };
fillpolygon(pts, 16);
break;//爆炸效果
}
}
}
}
//右半部分显示游戏状态
void GameState() {
//刷新的帧数
char s[10];
settextcolor(BLUE);
sprintf(s, "%d", refresh);
outtextxy(490, 460, s);
outtextxy(490, 0, "当前生命值:");
//显示生命值
if (player.life > 0) {
setfillcolor(RGB(254, 67, 101));
}
else {
setfillcolor(BLACK);
}
setlinecolor(RED);
setlinestyle(NULL, 2);
//第一颗心
POINT pts[] = { {490, 30}, {498, 22}, {505, 30},{512, 22},{520, 30},{505, 45} };
fillpolygon(pts, 6);
if (player.life > 1) {
setfillcolor(RGB(254, 67, 101));
}
else {
setfillcolor(BLACK);
}
//第二颗心
POINT pts1[] = { {530, 30}, {538, 22}, {545, 30},{552, 22},{560, 30},{545, 45} };
fillpolygon(pts1, 6);
if (player.life > 2) {
setfillcolor(RGB(254, 67, 101));
}
else {
setfillcolor(BLACK);
}
//第三颗心
POINT pts2[] = { {570, 30}, {578, 22}, {585, 30},{592, 22},{600, 30},{585, 45} };
fillpolygon(pts2, 6);
if (player.maxl > 3) {
setlinecolor(RED);
}
else {
setlinecolor(BLACK);
}
if (player.life > 3) {
setfillcolor(RGB(254, 67, 101));
}
else {
setfillcolor(BLACK);
}
//第四颗心
POINT pts3[] = { {510, 55}, {518, 47}, {525, 55},{532, 47},{540, 55},{525, 70} };
fillpolygon(pts3, 6);
if (player.maxl > 4) {
setlinecolor(RED);
}
else {
setlinecolor(BLACK);
}
if (player.life > 4) {
setfillcolor(RGB(254, 67, 101));
}
else {
setfillcolor(BLACK);
}
//第五颗心
POINT pts4[] = { {550, 55}, {558, 47}, {565, 55},{572, 47},{580, 55},{565, 70} };
fillpolygon(pts4, 6);
//伤害面板
outtextxy(490, 75, "伤害:");
setlinecolor(RGB(255, 130, 58));
setlinestyle(NULL, 2);
if (player.str > 1) {
setfillcolor(RGB(242, 196, 90));
}
else {
setfillcolor(BLACK);
}
fillrectangle(545, 75, 570, 92);
if (player.str > 2) {
setfillcolor(RGB(242, 196, 90));
}
else {
setfillcolor(BLACK);
}
fillrectangle(575, 75, 600, 92);
if (player.str > 3) {
setfillcolor(RGB(242, 196, 90));
}
else {
setfillcolor(BLACK);
}
fillrectangle(605, 75, 630, 92);
//速度面板
outtextxy(490, 100, "速度:");
setlinecolor(RGB(38, 173, 228));
setlinestyle(NULL, 2);
if (player.mc < 3)