C语言——坦克大战

Posted 机智蛋蛋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言——坦克大战相关的知识,希望对你有一定的参考价值。

最近在学习C语言,闲来无事,花了3天搞了个坦克大战。代码粗陋,大佬勿喷~

坦克大战效果图:

坦克大战流程图:

1、键盘信号获取
由 _kbhit(),_getch() ,函数获取
_kbhit()检测有没有键按下
_getch()读取键值
2、坦克模型

typedef struct Tank
{
	int id;//坦克ID
	int x;
	int y;
	int tankType;//0 普通坦克  1 打三次才会爆炸的坦克   2速度型坦克
	int blood;//血条
	int moveSpeed;//移动速度
	int moveCount;//计数,当计数等于moveSpeed 则移动一步
	int lives;//生命
	int distance;//移动距离  1 ~ 20 格
	int invincibleCount;//无敌时间计数
	Bullet bullet;//子弹 结构体
	bool overLapping;//检测坦克刚出来时敌我双方是否重叠
	bool hasShow;//坦克是否已经显示在地图上
 	bool propsTank;//爆炸后随机出现道具
 	BYTE camp;//阵营  0 我方   1 敌方
 	BYTE direction; //移动方向  0 上  1 右  2下   3左
	Tank *pNextTank;
}TANK, *PTANK;

(1)坦克在控制台上表现是9个方块,显示上下左右的图案。
(2)敌方坦克数据使用链表存储
(3)敌方坦克自动移动,随机移动距离,随机移动方向

3、子弹模型

struct Bullet
{
	int x;
	int y;
	int speed;//子弹速度
	int speedCount;//子弹速度计数,当计数等于speed则子弹移动一步
	int shootCount;//发射子弹倒计时
	BYTE direction;//子弹方向  0 上  1 右  2下   3左
	bool fly;//子弹是否还在飞行
};

(1)在控制台上表现是一个小方块,随着线程循环移动

4、道具模型

typedef struct Props
{
	int x;
	int y;
	int disappear;//道具消失计时
	BYTE type;//道具类型  0 生命+1    1 城堡临时加固     2无敌金身     3地雷敌军全体爆炸
	Props* pNext;
}PROPS, *PPROPS;

(1)条件有限,道具就在控制台上打印了中文字符:生命、地雷、加固、无敌,共4种道具

5、光标跳转到指定位置

void gotoxy(int x, int y, int ForgC)
{
	if(ForgC == -1)
	{
		ForgC = LIGHTGREEN;
	}
	

    // 更新光标位置 
    COORD pos;
	WORD wColor;
    HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    pos.X = x;
    pos.Y = y;
    SetConsoleCursorPosition(hOutput, pos);
	
	CONSOLE_SCREEN_BUFFER_INFO csbi;
	
	if(GetConsoleScreenBufferInfo(hOutput, &csbi))
	{
		//设置字体颜色
		wColor = (csbi.wAttributes & 0xF0) + (ForgC & 0x0F);
		SetConsoleTextAttribute(hOutput, wColor);
	}
	// 隐藏光标 
    CONSOLE_CURSOR_INFO cursor;
    cursor.bVisible = FALSE;
    cursor.dwSize = 1;	//值介于1 ~ 100 之间 单元格底部为下划线 ~ 完全填充单元格
    SetConsoleCursorInfo(hOutput, &cursor);
	
}

这样方便将光标移动到指定位置打印字符或者删除字符。

6、判断游戏是否结束
(1)敌方全部消灭
(2)我方生命清零
(3)城堡被攻陷

7、子弹碰撞检测
(1)检测子弹是否碰到游戏边界
(2)检测子弹是否碰到游戏障碍物(砖块或铁块)
(3)检测我方子弹是否碰到敌方坦克,敌方子弹是否碰到我方坦克
(4)检测我方子弹是否碰到敌方坦克
(5)检测子弹是否攻入城堡

8、坦克碰撞检测
(1)检测坦克是否撞到游戏边界
(2)检测坦克是否撞到地图内障碍物(砖块或铁块)
(3)检测坦克是否互撞

以下是坦克大战游戏完整C语言源代码:

// 坦克大战.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "string.h"
#include "stdlib.h"
#include "windows.h"
#include "conio.h"
#include "time.h"
#include "math.h"

#define FilePath "C:\\\\GameTank.dat"
#define GameX 36
#define GameY 36
#define ENEMYNUM 8  //地图中敌人数量
#define DISAPPEAR 1000   //道具消失时间间隔
//颜色
enum
{
	BLACK,
	BLUE,
	GREEN,
	CYAN,
	RED,
	MAGENTA,
	BROWN,
	LIGHTGRAY,
	DARKGRAY,
	LIGHTBLUE,
	LIGHTGREEN,
	LIGHTCYAN,
	LIGHTRED,
	LIGHTMAGENTA,
	YELLOW,
	WHITE
};
typedef struct Props
{
	int x;
	int y;
	int disappear;//道具消失计时
	BYTE type;//道具类型  0 生命+1    1 城堡临时加固     2无敌金身     3地雷敌军全体爆炸
	Props* pNext;
}PROPS, *PPROPS;
struct CastleWall//城墙结构体
{
	int x;
	int y;
	int* pScreenPoint;//指针指向城墙中每个砖块的内存,方便后续改变城墙材质
};
struct Bullet
{
	int x;
	int y;
	int speed;//子弹速度
	int speedCount;//子弹速度计数,当计数等于speed则子弹移动一步
	int shootCount;//发射子弹倒计时
	BYTE direction;//子弹方向  0 上  1 右  2下   3左
	bool fly;//子弹是否还在飞行
};
typedef struct Tank
{
	int id;//坦克ID
	int x;
	int y;
	int tankType;//0 普通坦克  1 打三次才会爆炸的坦克   2速度型坦克
	int blood;//血条
	int moveSpeed;//移动速度
	int moveCount;//计数,当计数等于moveSpeed 则移动一步
	int lives;//生命
	int distance;//移动距离  1 ~ 20 格
	int invincibleCount;//无敌时间计数
	Bullet bullet;//子弹 结构体
	bool overLapping;//检测坦克刚出来时敌我双方是否重叠
	bool hasShow;//坦克是否已经显示在地图上
 	bool propsTank;//爆炸后随机出现道具
 	BYTE camp;//阵营  0 我方   1 敌方
 	BYTE direction; //移动方向  0 上  1 右  2下   3左
	Tank *pNextTank;
}TANK, *PTANK;

TANK G_Tank;//我方坦克
PTANK G_pEnemyTankHead;//敌方坦克链表头
PPROPS G_PropsHead;//道具链表头

char name[200];
int score;//得分
//指令集:  w 向上  a 向左  s 向下  d 向右  o 结束游戏并保存   p 暂停游戏   空格  开炮
char KEYVALUESET[] = {'w', 'a', 's', 'd', 'o', 'p', ' '};
BYTE DIRECTIONDATA[4][9] = {0};//坦克各个方向的状态图
int G_ScreenMap[GameX + 1][GameY + 1] = {0};//初始化标记地图上的点  1  砖头   2 铁块   3地图墙壁  0  无障碍物
int G_xArr[] = {1, GameX / 2, GameX - 3};//敌方坦克随机出现的X轴位置
CastleWall G_CastleWallArr[26];//城堡围墙结构体
int G_CastleWallChangeCount = 1000;//城堡围墙从铁块变成砖头的时间计数

//函数声明
void createProps();//生成道具
/************************************************************************/
/*光标跳转到指定位置*/
/************************************************************************/
void gotoxy(int x, int y, int ForgC)
{
	if(ForgC == -1)
	{
		ForgC = LIGHTGREEN;
	}
	

    // 更新光标位置 
    COORD pos;
	WORD wColor;
    HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    pos.X = x;
    pos.Y = y;
    SetConsoleCursorPosition(hOutput, pos);
	
	CONSOLE_SCREEN_BUFFER_INFO csbi;
	
	if(GetConsoleScreenBufferInfo(hOutput, &csbi))
	{
		//设置字体颜色
		wColor = (csbi.wAttributes & 0xF0) + (ForgC & 0x0F);
		SetConsoleTextAttribute(hOutput, wColor);
	}
	// 隐藏光标 
    CONSOLE_CURSOR_INFO cursor;
    cursor.bVisible = FALSE;
    cursor.dwSize = 1;	//值介于1 ~ 100 之间 单元格底部为下划线 ~ 完全填充单元格
    SetConsoleCursorInfo(hOutput, &cursor);
	
}
/************************************************************************/
/*光标跳转到指定位置(函数重载)*/
/************************************************************************/
void gotoxy(int x, int y)
{
	gotoxy(x, y, -1);
}
/************************************************************************/
/*指定位置打印游戏边框*/
/************************************************************************/
int switchFlag = 0;
void gotoprint(int x, int y, int color)
{
    gotoxy(x * 2, y, color);
    printf("■");
}
void gotoprint(int x, int y)
{
	int color = (switchFlag = ! switchFlag) ? LIGHTGRAY : LIGHTRED;
	gotoprint(x, y, color);
}
/************************************************************************/
/*从指定位置开始清除指定长度元素*/
/************************************************************************/
void gotodelete(int x, int y, int length)
{
	int i;
    
	gotoxy(x * 2, y);
	for (i = 0; i < length; i++)
	{
		printf("  ");
	}
}
/************************************************************************/
/*清除指定位置元素*/
/************************************************************************/
void gotodelete(int x, int y)
{
	gotodelete(x, y, 1);
}
/************************************************************************/
/* 绘制游戏边框 */
/************************************************************************/
void drawGameMap()
{
	int i, j, count;
	//初始化游戏地图
	for (i = 0; i < GameX; i++)
	{
		gotoprint(i, 0);
		G_ScreenMap[i][0] = 3;//墙壁
	}
	for (i = 0; i < GameX; i++)
	{
		gotoprint(i, GameY);
		G_ScreenMap[i][GameY] = 3;//墙壁
	}
	for (i = 0; i < GameY; i++)
	{
		gotoprint(0, i);
		G_ScreenMap[0][i] = 3;//墙壁
	}
	for (i = 0; i <= GameY; i++)
	{
		gotoprint(GameX, i);
		G_ScreenMap[GameX][i] = 3;//墙壁
	}

	//初始化图内砖块
	for (i = 0; i < GameX; i++)
	{
		for (j = 0; j < GameY; j++)
		{
			if((i >= 5 && i <= 10 || i >= 15 && i <= 20 || i >= 25 && i <= 30) && j >=6 && j <= 30)
			{
				gotoprint(i, j, LIGHTGRAY);
				G_ScreenMap[i][j] = 1;//砖块
			}
		}
	}
	//初始化城堡
	count = 0;

	for (i = GameX / 2 - 3; i <= GameX / 2 + 3; i++)
	{
		for (j = GameY - 5; j < GameY; j ++)
		{
			if(! (i >= GameX / 2 - 1 && i <= GameX / 2 + 1 && j >= GameY - 3))
			{
				G_ScreenMap[i][j] = 1;//砖块
				G_CastleWallArr[count].x = i;
				G_CastleWallArr[count].y = j;
				G_CastleWallArr[count].pScreenPoint = &G_ScreenMap[i][j];
				count++;
				gotoprint(i, j , LIGHTGRAY);
			}
			else if(i == GameY / 2 || j == GameY - 2)
			{
				gotoprint(i, j , LIGHTGREEN);
			}
		}
	}

}
/************************************************************************/
/*游戏读档后恢复地图*/
/************************************************************************/
void recoveryScreenMap()
{
	int i, j, count;

	count = 0;

	for (i = 0; i < GameX + 1; i++)
	{
		for (j = 0; j < GameY + 1; j++)
		{
			if(G_ScreenMap[i][j] == 1)//砖块
			{
				gotoprint(i, j, LIGHTGRAY);
			}
			else if(G_ScreenMap[i][j] == 2)//铁块
			{
				gotoprint(i, j, YELLOW);
			}
			else if(G_ScreenMap[i][j] == 3)//游戏边界
			{
				if(i == 0 || i == GameX)
				{
					gotoprint(i, j);
				}
				else
				{
					gotoprint(i, j, i % 2 == 1 ? LIGHTRED : LIGHTGRAY);
				}
			}
		}
	}
	//恢复城堡数据
	for (i = GameX / 2 - 3; i <= GameX / 2 + 3; i++)
	{
		for (j = GameY - 5; j < GameY; j ++)
		{
			if(! (i >= GameX / 2 - 1 && i <= GameX / 2 + 1 && j >= GameY - 3))
			{
				G_CastleWallArr[count].x = i;
				G_CastleWallArr[count].y = j;
				G_CastleWallArr[count].pScreenPoint = &G_ScreenMap[i][j];
				count++;
			}
			else if(i == GameY / 2 || j == GameY - 2)
			{
				gotoprint(i, j , LIGHTGREEN);
			}
		}
	}
}

/************************************************************************/
/* 初始化游戏开始界面*/
/************************************************************************/
bool initGameScreen(bool state)
{
	bool result;
	char keyValue;
	PTANK p1, p2;
	PPROPS pProps1, pProps2;

	system("title 坦克大战 by 机智蛋");
	result = false;

    gotoxy(GameX - 10, 10);
    printf("/**********************************************/");
    gotoxy(GameX - 10, 22);
    printf("/**********************************************/");
    gotoxy(GameX- 5, 13);
    printf("WELCOME TO THE BATTLE OF TANKS");
    gotoxy(GameX - 10, 16);
	printf("W:左移 D:右移 S:下移  空格:开炮  P暂停  O结束游戏并保存");
    gotoxy(GameX - 5, 18);
	if(state)
	{
		printf("游戏有存档,是否读取?Y/N");
		while(1)
		{
			keyValue = _getch();
			if(keyValue == 'Y' || keyValue == 'y')//同意读档
			{
				result = true;
				break;
			}
			else if(keyValue == 'N' || keyValue == 'n')//不同意读档
			{
				//DeleteFileA(FilePath); //删除存档
				//以下清除已读取的数据
				score = 0;
				p1 = G_pEnemyTankHead;
				while(p1->pNextTank != NULL)
				{
					p2 = p1->pNextTank;
					p1->pNextTank = p1->pNextTank->pNextTank;
					free(p2);
				}
				pProps1 = G_PropsHead;
				while(pProps1->pNext != NULL)
				{
					pProps2 = pProps1->pNext;
					pProps1->pNext C/C++游戏项目完整教程:《坦克大战》

C#WinForm开发坦克大战

学习 Python 之 Pygame 开发坦克大战

坦克大战游戏设计(C++)

坦克大战

java实现经典坦克大战及源代码下载