最近在學習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 = pProps1->pNext->pNext;
free(pProps2);
}
memset(G_ScreenMap, 0, sizeof(G_ScreenMap));//地圖大陣列清零
G_CastleWallChangeCount = 0;
result = false;
break;
}
}
}
if(! result) //不同意讀檔或無存檔
{
gotodelete(GameX - 5, 18, 15);
gotoxy(GameX - 5, 18);
printf("PLEASE ENTER YOUR NAME:");
scanf("%s", name);
}
system("CLS");
gotoxy((GameX+1) * 2, 15);
printf("Your life remains %d", G_Tank.lives);
gotoxy((GameX+1) * 2, 20);
printf("hello %s,Welcome To Play", name);
gotoxy((GameX+1) * 2, 25);
printf("Your Score Is:%d = ̄ω ̄= ", score);
gotoxy((GameX+1) * 2, 30);
printf("This Game Is Created By 機智蛋");
return result;
}
/************************************************************************/
/* 初始化游戲開始界面(函式多載)*/
/************************************************************************/
bool initGameScreen()
{
return initGameScreen(0);
}
/************************************************************************/
/* 游戲結束處理*/
/************************************************************************/
void FinishGame()
{
system("CLS");
gotoxy(GameX - 10, 10);
printf("/**********************************************/");
gotoxy(GameX - 10, 20);
printf("/**********************************************/");
gotoxy(GameX - 5, 14);
printf("GAME OVER o(* ̄▽ ̄*)o");
gotoxy(GameX - 5, 16);
printf("Your Score is %d ", score);
gotoxy(GameX - 5, 18);
printf("還不錯哦, 繼續努力O(∩_∩)O");
gotoxy(0, 27);
system("pause");
}
/************************************************************************/
/*列印分數*/
/************************************************************************/
void printScore()
{
gotoxy((GameX+1) * 2, 15);
printf("Your life remains %d", G_Tank.lives);
gotoxy((GameX+1) * 2, 25);
printf("Your Score Is:%d = ̄ω ̄= ", score);
}
/************************************************************************/
/*讀檔游戲*/
/************************************************************************/
bool readGameFile()
{
FILE *fp;
int i;
PTANK p1, p2;
TANK tmpTank;
PPROPS pProps1, pProps2;
PROPS tmpProps;
int tmpScreenMap[GameX + 1][GameY + 1] = {0};
int tmpCastleWallChangeCount = 0;
bool readSucc;
readSucc = true;
i = 0;
if((fp = fopen(FilePath, "rb")) == NULL)
{
return false;
}
fread(DIRECTIONDATA, sizeof(DIRECTIONDATA), 1, fp);
p1 = G_pEnemyTankHead;
do
{
fread(&tmpTank, sizeof(TANK), 1, fp);//讀取鏈表頭
if(i++ > 0)
{
if(tmpTank.camp != 1 || tmpTank.lives <= 0)//檢測資料合法性
{
readSucc = false;
break;
}
tmpTank.hasShow = false;//這里置為false方便后面呼叫方法顯示出來
p2 = (PTANK)malloc(sizeof(TANK));
MoveMemory(p2, &tmpTank, sizeof(TANK));
p1->pNextTank = p2;
p1 = p2;
}
} while (tmpTank.pNextTank != NULL);
fread(&tmpCastleWallChangeCount, sizeof(int), 1, fp);//讀取城堡圍墻材質更改倒計時
fread(tmpScreenMap, sizeof(G_ScreenMap), 1, fp);//讀取地圖各點狀態
fread(&tmpTank, sizeof(TANK), 1, fp);
tmpTank.hasShow = false;
fread(name, sizeof(name), 1, fp);
fread(&score, sizeof(int), 1, fp);
i = 0;
pProps1 = G_PropsHead;
do
{
fread(&tmpProps, sizeof(PROPS), 1, fp);//讀取鏈表頭
if(i++ > 0)
{
if(tmpProps.type < 0 || tmpProps.type > 3)//檢測資料合法性
{
readSucc = false;
break;
}
pProps2 = (PPROPS)malloc(sizeof(PROPS));
MoveMemory(pProps2, &tmpProps, sizeof(PROPS));
pProps1->pNext = pProps2;
pProps1 = pProps2;
}
} while (tmpProps.pNext != NULL && ! feof(fp));
fclose(fp);
//檢測資料合法性
if(tmpTank.lives <=0 || tmpTank.pNextTank != NULL || tmpTank.camp != 0)
{
readSucc = false;
}
if(readSucc)//讀取成功
{
MoveMemory(G_ScreenMap, tmpScreenMap, sizeof(G_ScreenMap));
MoveMemory(&G_Tank, &tmpTank, sizeof(TANK));
G_CastleWallChangeCount = tmpCastleWallChangeCount;
}
else//讀取失敗釋放記憶體
{
DeleteFileA(FilePath);
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 = pProps1->pNext->pNext;
free(pProps2);
}
}
return readSucc;
}
/************************************************************************/
/*保存游戲*/
/************************************************************************/
void saveGame()
{
FILE *fp;
PTANK pTank;
PPROPS pProps;
if((fp = fopen(FilePath, "wb")) == NULL)
{
gotoxy(0, GameY + 2);
printf("游戲保存失敗\n");
return;
}
fwrite(DIRECTIONDATA, sizeof(DIRECTIONDATA), 1, fp);
pTank = G_pEnemyTankHead;
while(pTank != NULL)
{
fwrite(pTank, sizeof(TANK), 1, fp);
pTank = pTank->pNextTank;
}
fwrite(&G_CastleWallChangeCount, sizeof(int), 1, fp);
fwrite(G_ScreenMap, sizeof(G_ScreenMap), 1, fp);
fwrite(&G_Tank, sizeof(G_Tank), 1, fp);
fwrite(name, sizeof(name), 1, fp);
fwrite(&score, sizeof(int), 1, fp);
pProps = G_PropsHead;
while(pProps != NULL)
{
fwrite(pProps, sizeof(PROPS), 1, fp);
pProps = pProps->pNext;
}
fclose(fp);
}
/************************************************************************/
/*判斷游戲是否結束*/
/************************************************************************/
bool checkGameOver()
{
PTANK pTank;
if(G_pEnemyTankHead->pNextTank == NULL)
{
return true;
}
if(G_Tank.lives == 0)
{
return true;
}
//檢測敵方子彈有沒有攻入城堡
pTank = G_pEnemyTankHead->pNextTank;
while(pTank != NULL)
{
if(pTank->bullet.fly)
{
if(pTank->bullet.x >= GameX / 2 - 1 && pTank->bullet.x <= GameX / 2 + 1 && pTank->bullet.y >= GameY - 3)
{
return true;
}
}
pTank = pTank->pNextTank;
}
//檢測我方子彈有沒有攻入城堡
if(G_Tank.bullet.x >= GameX / 2 - 1 && G_Tank.bullet.x <= GameX / 2 + 1 && G_Tank.bullet.y >= GameY - 3)
{
return true;
}
return false;
}
/************************************************************************/
/*改變城堡城墻材質 0 磚頭 1 鐵塊*/
/************************************************************************/
void castleWallChangeState(int state)
{
int i;
if(state == 1)
{
G_CastleWallChangeCount = 1000;
}
for (i = 0; i < 26; i++)
{
if(state == 0)//城堡城墻變成磚頭
{
gotoprint(G_CastleWallArr[i].x, G_CastleWallArr[i].y , LIGHTGRAY);
*(G_CastleWallArr[i].pScreenPoint) = 1;
}
else if(state == 1)//城堡城墻變成鐵塊
{
gotoprint(G_CastleWallArr[i].x, G_CastleWallArr[i].y , YELLOW);
*(G_CastleWallArr[i].pScreenPoint) = 2;
}
}
}
/************************************************************************/
/*繪制坦克*/
/************************************************************************/
void drawTank(PTANK pTank, bool clear)
{
int i, color;
if(pTank->invincibleCount > 0)//坦克無敵金身
{
color = YELLOW;
}
else
{
color = pTank->blood + LIGHTBLUE;//坦克顏色隨血量變化
}
for (i = 0; i < 9; i++)
{
gotoxy((pTank->x + i % 3)* 2, pTank->y + i / 3, color);
if(DIRECTIONDATA[pTank->direction][i] == 1)
{
if(clear)
{
printf(" ");
}
else
{
printf("■");
}
}
else
{
printf(" ");
}
}
}
void drawTank(PTANK pTank)
{
drawTank(pTank, false);
}
void clearTank(PTANK pTank)
{
drawTank(pTank, true);
}
/************************************************************************/
/*繪制子彈*/
/************************************************************************/
void drawBullet(PTANK pTank, bool clear)
{
if(clear)
{
gotodelete(pTank->bullet.x, pTank->bullet.y);
}
else
{
if(pTank->bullet.fly)
{
gotoprint(pTank->bullet.x, pTank->bullet.y, LIGHTBLUE);
}
}
}
void drawBullet(PTANK pTank)
{
drawBullet(pTank, false);
}
void clearBullet(PTANK pTank)
{
drawBullet(pTank, true);
}
/************************************************************************/
/*檢測坦克位置是否撞墻或撞到其他坦克*/
/************************************************************************/
bool checkTankLocation(PTANK pTank, bool checkOverLapping)
{
int i, j;
PTANK p;
p = G_pEnemyTankHead->pNextTank;
for (i = 0; i < 3; i++)
{
for (j = 0; j< 3; j++)
{
if(G_ScreenMap[pTank->x + i][pTank->y + j] != 0)//檢測坦克是否撞墻或撞到圖內磚頭
{
return false;
}
}
}
while(p != NULL)
{
if(p != pTank && p->hasShow && abs(p->x - pTank->x) < 3 && abs(p->y - pTank->y) < 3)//檢測坦克是否互撞
{
if(checkOverLapping)
{
pTank->overLapping = true;
}
return false;
}
p = p->pNextTank;
}
// if(pTank != &G_Tank)//檢測敵方坦克有沒有撞到我方坦克
// {
// if(! checkOverLapping && pTank->overLapping)
// {
// return true;
// }
// if(G_Tank.hasShow && abs(G_Tank.x - pTank->x) < 3 && abs(G_Tank.y - pTank->y) < 3)//檢測坦克是否互撞
// {
// if(checkOverLapping)
// {
// pTank->overLapping = true;
// }
// return false;
//
// }
// }
return true;
}
bool checkTankLocation(PTANK pTank)
{
return checkTankLocation(pTank, false);
}
/************************************************************************/
/*檢測敵我雙方坦克是否有重疊*/
/************************************************************************/
void checkTankOverLapping()
{
PTANK pTank;
pTank = G_pEnemyTankHead->pNextTank;
while(pTank != NULL)
{
if(pTank->overLapping)
{
pTank->overLapping = false;
checkTankLocation(pTank, true);
}
pTank = pTank->pNextTank;
}
if(G_Tank.overLapping)
{
G_Tank.overLapping = false;
checkTankLocation(&G_Tank, true);
}
}
/************************************************************************/
/*坦克移動*/
/************************************************************************/
bool moveTank(PTANK pTank)
{
bool canMove;
TANK tankTemp;
if(! pTank->hasShow)
{
return false;
}
// if(pTank->overLapping)
// {
// return true;
// }
if(++ pTank->moveCount < pTank->moveSpeed)//
{
return false;
}
pTank->moveCount = 0;
MoveMemory(&tankTemp, pTank, sizeof(TANK));
if(pTank->direction == 0)//上
{
pTank->y --;
}
else if(pTank->direction == 1)//右
{
pTank->x += 1;
}
else if(pTank->direction == 2)//下
{
pTank->y ++;
}
else if(pTank->direction == 3)//左
{
pTank->x -= 1;
}
if(! (canMove = checkTankLocation(pTank)))
{
MoveMemory(pTank, &tankTemp, sizeof(TANK));
}
clearTank(&tankTemp);
drawTank(pTank);
if(pTank->camp == 1)//敵方坦克
{
pTank->distance --;
if(! canMove || pTank->distance <= 0)
{
pTank->distance = rand() % 20 + 1;//隨機行進距離
pTank->direction = rand() % 4;//隨機行進方向
}
}
return canMove;
}
/************************************************************************/
/*檢測坦克是否顯示在地圖上*/
/************************************************************************/
void checkShowTank()
{
PTANK pTank = G_pEnemyTankHead->pNextTank;
while(pTank != NULL)
{
if(! pTank->hasShow && checkTankLocation(pTank))
{
pTank->hasShow = true;
drawTank(pTank);
}
pTank = pTank->pNextTank;
}
// if(! G_Tank.hasShow)
// {
if(G_Tank.invincibleCount > 0)
{
G_Tank.invincibleCount --;
}
G_Tank.hasShow = true;
drawTank(&G_Tank);
// }
}
/************************************************************************/
/*創建敵方坦克資料*/
/************************************************************************/
PTANK createTank(PTANK pTank)
{
if(pTank == NULL)//如果傳的引數不為NULL,則代表坦克復活
{
pTank = (PTANK)malloc(sizeof(TANK));
pTank->pNextTank = NULL;
pTank->lives = 5;
pTank->bullet.fly = false;
pTank->bullet.shootCount = rand() % 100;
pTank->bullet.speed = 1;
pTank->bullet.speedCount = 0;
pTank->bullet.x = 0;
pTank->bullet.y = 0;
}
pTank->x = G_xArr[rand() % 3];
pTank->y = 1;
pTank->tankType = rand() % 3;//坦克型別
pTank->blood = 1;//血量
pTank->moveSpeed = 10;//移動速度,數值越大速度越慢
pTank->moveCount = 0;//移動距離,當數值等于distance則移動一步
pTank->direction = 2;
pTank->camp = 1;
pTank->invincibleCount = 0;
pTank->hasShow = false;
pTank->overLapping = false;
pTank->distance = rand() % 20 + 1;
pTank->propsTank = rand() % 2 == 1;
if(pTank->tankType == 1)
{
pTank->blood = 3;
}
else if(pTank->tankType == 2)
{
pTank->moveSpeed = 3;
}
//checkTankLocation(pTank, true);
return pTank;
}
/************************************************************************/
/*初始化敵我雙方坦克資料*/
/************************************************************************/
void initTank()
{
int i, j;
PTANK pTank;
pTank = G_pEnemyTankHead;
//初始化方向狀態陣列 上下左右
for (i = 0; i < 4; i++)
{
for (j = 0; j < 9; j++)
{
if(i == 0)
{
if(j != 0 && j != 2)
{
DIRECTIONDATA[i][j] = 1;//上
}
}
else if(i == 1)
{
if(j != 2 && j != 8)
{
DIRECTIONDATA[i][j] = 1;//右
}
}
else if(i == 2)
{
if(j != 6 && j != 8)
{
DIRECTIONDATA[i][j] = 1;//下
}
}
else if(i == 3)
{
if(j != 0 && j != 6)
{
DIRECTIONDATA[i][j] = 1;//左
}
}
}
}
//初始化敵方坦克資料
for (i = 0; i < ENEMYNUM; i++)
{
pTank->pNextTank = createTank(NULL);
pTank = pTank->pNextTank;
//drawTank(pTank);
}
//初始化我方坦克資料
G_Tank.id = 1;
G_Tank.x = GameX / 2 - 8;
G_Tank.y = GameY - 3;
G_Tank.tankType = 1;
G_Tank.blood = 1;
G_Tank.moveSpeed = 1;
G_Tank.moveCount = 0;
G_Tank.direction = 0;
G_Tank.camp = 0;
G_Tank.lives = 5;
G_Tank.distance = 0;
G_Tank.invincibleCount = 0;
G_Tank.hasShow = false;
G_Tank.bullet.fly = false;
G_Tank.bullet.shootCount = 1;
G_Tank.bullet.speed = 1;
G_Tank.bullet.speedCount = 0;
G_Tank.bullet.x = 0;
G_Tank.bullet.y = 0;
G_Tank.pNextTank = NULL;
}/************************************************************************/
/*子彈碰撞檢測*/
/************************************************************************/
bool bulletImpactCheck(PTANK pTank)
{
PTANK p, p1;
if(G_ScreenMap[pTank->bullet.x][pTank->bullet.y] == 3 || G_ScreenMap[pTank->bullet.x][pTank->bullet.y] == 2
|| pTank->bullet.y >= GameY || pTank->bullet.x >= GameX)//子彈撞邊界或撞到鐵塊
{
return true;
}
else if(G_ScreenMap[pTank->bullet.x][pTank->bullet.y] == 1)//碰到磚頭
{
if(pTank->bullet.direction == 0 || pTank->bullet.direction == 2)//子彈向上或向下飛行
{//洗掉磚塊位置
G_ScreenMap[pTank->bullet.x][pTank->bullet.y] = 0;
G_ScreenMap[pTank->bullet.x + 1][pTank->bullet.y] = 0;
G_ScreenMap[pTank->bullet.x - 1][pTank->bullet.y] = 0;
gotodelete(pTank->bullet.x, pTank->bullet.y);
gotodelete(pTank->bullet.x + 1, pTank->bullet.y);
gotodelete(pTank->bullet.x - 1, pTank->bullet.y);
}
else if(pTank->bullet.direction == 1 || pTank->bullet.direction == 3)//子彈向右或向左飛行
{//洗掉磚塊位置
G_ScreenMap[pTank->bullet.x][pTank->bullet.y] = 0;
G_ScreenMap[pTank->bullet.x][pTank->bullet.y + 1] = 0;
G_ScreenMap[pTank->bullet.x][pTank->bullet.y - 1] = 0;
gotodelete(pTank->bullet.x, pTank->bullet.y);
gotodelete(pTank->bullet.x, pTank->bullet.y + 1);
gotodelete(pTank->bullet.x, pTank->bullet.y - 1);
}
return true;
}
else
{
if(pTank->camp == 0)//如果是我方的子彈,則判斷是否打到敵人
{
p = G_pEnemyTankHead->pNextTank;
p1 = G_pEnemyTankHead;
while(p != NULL)
{
if(p->hasShow && pTank->bullet.x - p->x < 3 && pTank->bullet.x - p->x >= 0
&& pTank->bullet.y - p->y < 3 && pTank->bullet.y - p->y >= 0)
{
p->blood --;
if(p->blood == 0)//判斷血量為0
{
if(p->propsTank)//如果是道具坦克
{
createProps();//創建道具
}
if(p->tankType == 0)//普通坦克
{
score += 100;
}
else if(p->tankType == 1)//裝甲坦克
{
score += 300;
}
else if(p->tankType == 2)//速度坦克
{
score += 200;
}
printScore();
clearTank(p);//清除界面上坦克影像
p->lives --;//生命-1
if(p->lives == 0)//如果生命清零,則洗掉該敵方坦克資料
{
if(p->bullet.fly)//如果敵方坦克生命清零,則需要停止其子彈飛行并擦除影像,否則子彈會停留在地圖中
{
p->bullet.fly = false;
clearBullet(p);
}
p1->pNextTank = p->pNextTank;
free(p);
}
else//否則初始化坦克位置
{
p = createTank(p);
}
}
return true;//子彈打到坦克,停止遍歷
}
else if(p->bullet.fly && p->bullet.x == pTank->bullet.x && p->bullet.y == pTank->bullet.y)
{//判斷我方子彈是否跟敵方子彈對撞
p->bullet.fly = false;
clearBullet(p);
pTank->bullet.fly = false;
return true;
}
p1 = p;
p = p->pNextTank;
}
}
else if(pTank->camp == 1)//如果是敵方子彈,則判斷是否打到我方坦克
{
if(G_Tank.hasShow && pTank->bullet.x - G_Tank.x < 3 && pTank->bullet.x - G_Tank.x >= 0
&& pTank->bullet.y - G_Tank.y < 3 && pTank->bullet.y - G_Tank.y >= 0)
{
if(G_Tank.invincibleCount > 0)//我方坦克處于無敵金身狀態,則子彈無效
{
return true;
}
G_Tank.blood --;
if(G_Tank.blood == 0)
{
G_Tank.lives --;
G_Tank.blood = 1;
clearTank(&G_Tank);//清除界面上坦克影像
G_Tank.hasShow = false;
G_Tank.direction = 0;
G_Tank.x = GameX / 2 - 8;
G_Tank.y = GameY - 3;
G_Tank.overLapping = false;
//checkTankLocation(&G_Tank, true);
printScore();
}
return true;
}
else if(G_Tank.bullet.fly && G_Tank.bullet.x == pTank->bullet.x && G_Tank.bullet.y == pTank->bullet.y)
{//判斷敵方子彈是否跟我方子彈對撞
G_Tank.bullet.fly = false;
clearBullet(&G_Tank);
pTank->bullet.fly = false;
return true;
}
}
}
return false;
}
/************************************************************************/
/*子彈飛行*/
/************************************************************************/
void bulletFlying(PTANK pTank)
{
if(pTank->bullet.fly)
{
clearBullet(pTank);
if(pTank->bullet.direction == 0)//上
{
pTank->bullet.y --;
}
else if(pTank->bullet.direction == 1)//右
{
pTank->bullet.x ++;
}
else if(pTank->bullet.direction == 2)//下
{
pTank->bullet.y ++;
}
else if(pTank->bullet.direction == 3)//左
{
pTank->bullet.x --;
}
if(! bulletImpactCheck(pTank))//子彈未碰撞到任何物體,則畫出下個子彈位置
{
drawBullet(pTank);
}
else//如子彈碰撞到物體,則將子彈狀態置為不在飛行
{
pTank->bullet.fly = false;
}
}
}
/************************************************************************/
/*發射子彈*/
/************************************************************************/
void shootBullet(PTANK pTank)
{
if(pTank->hasShow && ! pTank->bullet.fly)
{
if(pTank->camp == 1)
{
if(pTank->bullet.shootCount-- > 0)
{
return;
}
else
{
pTank->bullet.shootCount = rand() % 100;//重置下次發射子彈的時間間隔
}
}
pTank->bullet.fly = true;//標志子彈正在飛行
pTank->bullet.direction = pTank->direction;//子彈飛行方向跟坦克當前行駛方向一致
if(pTank->direction == 0)//上
{
pTank->bullet.x = pTank->x + 1;
pTank->bullet.y = pTank->y;
}
else if(pTank->direction == 1)//右
{
pTank->bullet.x = pTank->x + 2;
pTank->bullet.y = pTank->y + 1;
}
else if(pTank->direction == 2)//下
{
pTank->bullet.x = pTank->x + 1;
pTank->bullet.y = pTank->y + 2;
}
else if(pTank->direction == 3)//左
{
pTank->bullet.x = pTank->x;
pTank->bullet.y = pTank->y + 1;
}
}
}
/************************************************************************/
/*生成道具*/
/************************************************************************/
void createProps()
{
PPROPS pProps, pPropsNew;
pProps = G_PropsHead;
while(pProps->pNext != NULL)
{
pProps = pProps->pNext;
}
pPropsNew = (PPROPS)malloc(sizeof(PROPS));
do
{
pPropsNew->x = rand() % (GameX - 2) + 1;
pPropsNew->y = rand() % (GameY - 1) + 1;
pPropsNew->disappear = DISAPPEAR;
pPropsNew->type = rand() % 4;
pPropsNew->pNext = NULL;
if(G_ScreenMap[pPropsNew->x][pPropsNew->y] == 0 && G_ScreenMap[pPropsNew->x + 1][pPropsNew->y] == 0
&& ! (G_Tank.y - pPropsNew->y <= 0 && G_Tank.y - pPropsNew->y >-3 && (G_Tank.x >= pPropsNew->x && G_Tank.x - pPropsNew->x < 2
|| G_Tank.x < pPropsNew->x && pPropsNew->x - G_Tank.x < 3)))//判斷生成的道具不在障礙物上,且不在角色坐標上
{
break;
}
} while (1);//檢測地圖中對應坐標是否有障礙物
pProps->pNext = pPropsNew;
}
/************************************************************************/
/*顯示道具*/
/************************************************************************/
void showProps()
{
PPROPS pProps, pProsPre;
pProps = G_PropsHead->pNext;
pProsPre = G_PropsHead;
while(pProps != NULL)
{
pProps->disappear --;//道具消失計時
gotoxy(pProps->x * 2, pProps->y);
if(pProps->disappear > 0)
{//這里不停列印防止坦克走過影像被覆寫
if(pProps->type == 0)
{
printf("生命");
}
else if(pProps->type == 1)
{
printf("加固");
}
else if(pProps->type == 2)
{
printf("無敵");
}
else if(pProps->type == 3)
{
printf("地雷");
}
pProsPre = pProps;
pProps = pProps->pNext;
}
else
{
gotodelete(pProps->x, pProps->y, 2);//清除道具顯示
pProsPre->pNext = pProps->pNext;
free(pProps);
pProps = pProsPre->pNext;
}
}
}
/************************************************************************/
/*檢測是否吃到道具*/
/************************************************************************/
void checkGetProps()
{
PPROPS pProps, pPropsPre;
bool hasGet;
PTANK pTank, pTankPre;
pProps = G_PropsHead->pNext;
pPropsPre = G_PropsHead;
while(pProps != NULL)
{
hasGet = false;
if(G_Tank.y - pProps->y <= 0 && G_Tank.y - pProps->y >-3)
{
if(G_Tank.x >= pProps->x && G_Tank.x - pProps->x < 2)
{
hasGet = true;
}
else if(G_Tank.x < pProps->x && pProps->x - G_Tank.x < 3)
{
hasGet = true;
}
if(hasGet)
{
gotodelete(pProps->x, pProps->y, 2);//清除道具影像
if(pProps->type == 0)//生命
{
G_Tank.lives++;
printScore();
}
else if(pProps->type == 1)//加固
{
castleWallChangeState(1);
}
else if(pProps->type == 2)//無敵
{
G_Tank.invincibleCount = 1000;
}
else if(pProps->type == 3)//地雷,敵方坦克全體爆炸
{
pTank = G_pEnemyTankHead->pNextTank;
pTankPre = G_pEnemyTankHead;
while(pTank != NULL)
{
clearTank(pTank);//清除界面上坦克影像
pTank->lives --;//生命-1
if(pTank->lives == 0)//如果生命清零,則洗掉該敵方坦克資料
{
if(pTank->bullet.fly)//如果敵方坦克生命清零,則需要停止其子彈飛行并擦除影像,否則子彈會停留在地圖中
{
pTank->bullet.fly = false;
clearBullet(pTank);
}
pTankPre->pNextTank = pTank->pNextTank;
free(pTank);
pTank = pTankPre->pNextTank;
}
else//否則初始化坦克位置
{
pTank = createTank(pTank);
pTankPre = pTank;
pTank = pTank->pNextTank;
}
}
}
pPropsPre->pNext = pProps->pNext;
free(pProps);
pProps = pPropsPre->pNext;
}
}
if(! hasGet)
{
pPropsPre = pProps;
pProps = pProps->pNext;
}
}
}
/************************************************************************/
/*指令控制*/
/************************************************************************/
bool orderController(char key)
{
int i;
for (i = 0; i < sizeof(KEYVALUESET); i++)
{
if(key == KEYVALUESET[i])
{
break;
}
}
if(i >= sizeof(KEYVALUESET)) //判斷按鍵是否在指令集中,如不在其中則不做處理
{
return true;
}
if(key == 'o') //結束游戲并保存
{
saveGame();
FinishGame();
return false;
}
else if(key == 'p')//暫停游戲
{
gotoxy(0, GameY + 2);
printf("按任意鍵繼續......");
_getch();
gotodelete(0, GameY + 2, 10);
}
else if(key == 'w')//上
{
G_Tank.direction = 0;
moveTank(&G_Tank);
}
else if(key == 'a')//左
{
G_Tank.direction = 3;
moveTank(&G_Tank);
}
else if(key == 'd')//右
{
G_Tank.direction = 1;
moveTank(&G_Tank);
}
else if(key == 's')//下
{
G_Tank.direction = 2;
moveTank(&G_Tank);
}
else if(key == ' ')//開炮
{
shootBullet(&G_Tank);
}
return true;
}
int main(int argc, char* argv[])
{
char order;
int count;
PTANK p;
G_pEnemyTankHead = (PTANK)malloc(sizeof(TANK));
G_pEnemyTankHead->pNextTank = NULL;
G_PropsHead = (PPROPS)malloc(sizeof(PROPS));
G_PropsHead->pNext = NULL;
count = 0;
srand(time(0));
if(initGameScreen(readGameFile()))
{
recoveryScreenMap();//恢復地圖各點狀態
}
else
{
drawGameMap();//繪制地圖
castleWallChangeState(1);//改變城堡圍墻材質為鐵塊
initTank();//初始化敵我雙方坦克資料
}
printScore();//顯示分數
while(1)
{
checkShowTank();//檢測是否有坦克未顯示在地圖上
//checkTankOverLapping();//檢測所有坦克之間是否有位置重疊
p = G_pEnemyTankHead->pNextTank;
while(p != NULL)//移動敵方坦克,敵方坦克發射子彈,敵方坦克子彈飛行
{
moveTank(p);
shootBullet(p);
bulletFlying(p);
p = p->pNextTank;
}
bulletFlying(&G_Tank);//角色子彈飛行
showProps();//顯示道具
checkGetProps();//檢測是否吃到道具
if(count++ >= 3 && _kbhit())//延遲獲取鍵盤狀態
{
count = 0;
order = _getch();
if(! orderController(order))
{
return 0;
}
}
if(count > 3)
{
count = 0;
}
if(checkGameOver())//檢測游戲是否結束
{
FinishGame();
return 0;
}
//城堡外墻計時改變材質
if(G_CastleWallChangeCount > 0)
{
if(-- G_CastleWallChangeCount == 0)
{
castleWallChangeState(0);
}
}
Sleep(20);
}
return 0;
}
全篇完~各位兄弟留下一個贊再走唄!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/298741.html
標籤:其他
