C语言实现坦克大战
期末设计和两个同学用C语言合作做了个坦克大战,就是模仿着fc上的坦克大战做的 注:虽说是用C语言实现的,但其中用到了C++中的一些东西,比如多线程,vector容器,当遇到时我会提供相应知识点的链接供大家了解;因为代码中有较详细的注释,所以只做个人认为比较重要的注释如果各位有疑问可以评论交流,我看到尽量及时回复
效果图
需要工具
1.项目是在vs2019上做出来的,所以推荐大家也使用vs2019进行操作,直接在官网下社区版就行,免费好用,贴个官网地址:https://visualstudio.microsoft.com/zh-hans/ 2.easyx库,针对C/C++的图形库,里面有封装好的各种绘图函数,上手比较简单,适合新手使用。 下载地址: 链接:https://pan.baidu.com/s/1EycRtZ8i7EeXYDfnWjjt6w 提取码:qji3 下载完之后打开程序选择对应的vs版本安装就行了,在线文档推荐也安装,会在桌面放一个文档,方便你看相关代码,里面还有示例,建议对easyx有一定了解后在来看本篇文章。
项目打包
为了方便大家观看,这里提供本项目的压缩包,解压后在vs2019中打开即可注意内部的文件不要随意更改位置。开场背景音乐是黑道圣徒3的背景音乐,如果喜欢也推荐玩一下游戏, 链接:https://pan.baidu.com/s/1dxZH2uRWTdkcrx4RxWG1Ig 提取码:b4md 里面的打包程序压缩包里是我用vs2019的打包程序打包好的程序,解压后打开exe文件即可安装对打包感兴趣的可以看VS 2019简单快速的打包可安装项目(图文教程)
整体结构
本项目用了多个文件分别存储代码,其中包括了用于声明的头文件,以及分别用于游戏开始、1p模式、2p模式、自定义模式的cpp文件。
代码展示
头文件 game.h
#pragma once
#include<graphics.h>
#include<cstdlib>
#include<stdio.h>
#include<thread>
#include<math.h>
#include<ctime>
#include<vector>
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")
using namespace std;
typedef struct direction {
int a = 0;
int b = 0;
int c = 0;
int d = 0;
}direction;
typedef struct tank{
IMAGE img[4];
IMAGE mask[4];
int x;
int y;
int dir = 1;
int vx = 6;
int life = 1;
int width;
int height;
int type;
int stop = 0;
bool if_bullet = 1;
int enemy_tank = 1;
struct direction direct;
}Tank;
typedef struct bullet{
int x;
int y;
int vy = 15;
int dir;
tank* host;
int bullet_attribute = 0;
int enemy_tank;
bool if_delete = 0;
}Bullet;
typedef struct boom {
int x;
int y;
int type = 0;
int seq = 0;
}Boom;
void load_play_audio(const char s[],int type,int volume);
void shoot(int pw, int ph);
int gamestart();
int choosegame(int ori);
void blink(RECT r,TCHAR s[]);
bool constructionmode();
void handlekey(int *pw, int *ph,int w,int h);
void setBuilding(int type, int x, int y,int w,int h);
void drawmap(int map[36][24]);
void savemap();
void initmap_construction();
void puttank(int x, int y);
void _1pmode(bool *if_construction);
void _2pmode(bool* if_construction);
void bonus();
void putplayertank(tank* tank);
void handlekeys(tank* _1p, int player);
bool checkhit(tank* tank, int enmid);
bool checkturn_bug(int x, int y,int width,int height,int id);
void checkgrass();
void drawgrass(int x, int y, int type);
void loadimagetank(tank* tank, const char s[]);
void load_map(int level);
void drawbullet();
void shoot(tank* tank);
void checkbullet();
void boom_draw();
void boom_update();
bool create_enm();
int gameend( int mode);
void gameend_play(int type, IMAGE bk);
void put_enmtank();
void AI_attack(int x, int y, int i, int tank_x, int tank_y, int tank_dir);
void enemy_move(tank* tank, int i);
void AI_terminator(int x, int y, int dir,int i);
void if_boundary(int i, int dir, int a);
void search_path(tank* tank, int i);
extern int width, height;
extern const int row, column ;
extern int map[36][24];
extern int total_enm;
extern int enm;
extern int max_enm;
extern int time0, timetrigger;
extern vector<Bullet> bullet_list;
extern vector<Tank> tank_enemy;
extern vector<Boom> boom_list;
extern tank _1p,_2p;
extern int bonus_item;
extern int counttime;
extern int onetank1killNum;
extern int twotank1killNum;
extern int onetankscore;
extern int twotankscore;
extern int pattern;
void PrintScore(int onetankHP, int twotankHP);
void SaveScore(int onetankscore, int twotankscore, int pattern);
这里只说第一个graphic.h,其实就是easyx,把这个头文件包含进来就能使用其中的函数了。其他的后面遇到时会再进行说明。
游戏开始界面 gamestart.cpp
#include"game.h"
using namespace std;
int width = 1280, height = 864;
int gamestart() {
load_play_audio("saints.mp3", 1, 500);
for (int i = 0; i < 255; i++)
{
setfillcolor(RGB(i, i, i));
solidrectangle(0, 0, width, height);
Sleep(40);
}
setfillcolor(BLACK);
solidrectangle(0, 0, width, height);
settextcolor(RED);
settextstyle(192, 160, _T("Fixedsys 常规"));
RECT a = { 0,60,width,384 };
drawtext(_T("BATTLE"), &a, DT_CENTER);
a.top = 252,a.bottom = 516;
drawtext(_T("CITY"), &a, DT_CENTER);
int ori = a.bottom - 50;
int part = 70;
RECT r[3] = {
{0,ori,width,ori + part},
{0,ori + part + 30,width,ori + 2 * part + 30},
{0,ori + part * 2 + 60,width,ori + 3 * part + 60}
};
settextcolor(WHITE);
settextstyle(70, 0, _T("Fixedsys 常规"));
TCHAR s[3][20] = { _T("1 Player"),_T("2 Player"),_T("Construction") };
drawtext(s[0], &r[0], DT_CENTER);
drawtext(s[1], &r[1], DT_CENTER);
drawtext(s[2], &r[2], DT_CENTER);
int mode = choosegame(ori);
blink(r[mode],s[mode]);
load_play_audio("saints.mp3", 2, 1000);
return mode;
}
void blink(RECT r, TCHAR s[])
{
for (int i = 0; i < 5; i++)
{
clearrectangle(r.left, r.top, r.right, r.bottom);
Sleep(100);
drawtext(s, &r, DT_CENTER);
Sleep(100);
}
}
int choosegame(int ori)
{
IMAGE point;
loadimage(&point, _T("Res/tank0.jpg"));
int ph[3] = { ori + 3,ori + 3 + 100,ori + 3 + 200 };
int pw[3] = { 300,280,230 };
int i = 0;
setfillcolor(BLACK);
putimage(pw[0], ph[0], &point);
while (1)
{
if (GetAsyncKeyState('W') < 0)
{
Sleep(200);
solidrectangle(pw[i], ph[i], pw[i] + 102, ph[i] + 64);
if (i == 0)
i = 2;
else
i--;
}
else if (GetAsyncKeyState('S') < 0)
{
Sleep(200);
solidrectangle(pw[i], ph[i], pw[i] + 102, ph[i] + 64);
if (i == 2)
i = 0;
else
i++;
}
else if (GetAsyncKeyState(' ') < 0)
{
shoot(pw[i]+112, ph[i]+32);
break;
}
putimage(pw[i], ph[i], &point);
}
return i;
}
void shoot(int pw, int ph)
{
mciSendString("play fire", NULL, 0, NULL);
for (int i = pw; i < pw + 90; i+=3)
{
setfillcolor(RGB(rand() % 255, rand() % 255, rand() % 255));
solidcircle(i, ph, 10);
Sleep(60);
setfillcolor(BLACK);
solidcircle(i, ph, 10);
}
IMAGE img[2];
loadimage(&img[0],_T( "Res/boom0.jpg"));
loadimage(&img[1], _T("Res/boom1.jpg"));
for (int i = 0; i < 2; i++)
{
putimage(pw + 40, ph - 32, &img[i], SRCPAINT);
Sleep(300);
}
}
void load_play_audio(const char s[],int type,int volume)
{
char a[5][50];
sprintf_s(a[0], "open Res/audio/%s alias %s", s,s);
sprintf_s(a[1], "setaudio %s volume to %d", s,volume);
sprintf_s(a[2], "play %s repeat", s);
sprintf_s(a[3], "close %s", s);
sprintf_s(a[4], "play %s wait", s);
mciSendString(a[0], NULL, 0, NULL);
mciSendString(a[1], NULL, 0, NULL);
if (type == 1)
mciSendString(a[2], NULL, 0, NULL);
else if(type == 0)
{
mciSendString(a[4], NULL, 0, NULL);
mciSendString(a[3], NULL, 0, NULL);
}
else if(type == 2)
{
mciSendString(a[3], NULL, 0, NULL);
}
}
int main() {
int mode;
bool cst = false;
initgraph(1280, 864);
while (1)
{
mode = gamestart();
clearrectangle(0, 0, width, height);
switch (mode)
{
case 0:_1pmode(&cst); break;
case 1:_2pmode(&cst); break;
case 2:cst = constructionmode(); break;
}
}
cleardevice();
closegraph();
return 0;
}
这里主要说一下load_play_audio函数,里面包括了播放音效的基础操作,具体可看另一位的贴子c/c++播放音乐(PlaySound、mciSendString、mciSendCommand)以及格式化字符串:sprinf sprintf_s 的用法 还有关于键盘的响应函数如
GetAsyncKeyState('w' < 0);
GetAsyncKeyState(VK_W < 0);
判断w键按下,其中VK_W是w键的键值
自定义模式实现 constructionmode.cpp
#include"game.h"
using namespace std;
const int row = 36, column = 24;
static int map[36][24] = { 0 };
bool constructionmode()
{
initmap_construction();
int pw = 0, ph = 0;
int w = 40, h = 24;
int orx = 0, ory = 0;
setlinecolor(RED);
line(960, 0, 960, 864);
int i = 0;
int time = 0, timetrigger = 0;
while (1)
{
time = GetTickCount();
if (time > timetrigger)
{
timetrigger = time + 200;
drawmap(map);
handlekey(&pw, &ph, w, h);
if (GetAsyncKeyState('J') < 0)
{
if (orx != pw || ory != ph)
orx = pw, ory = ph, i--;
if (i == 13)
i = 0;
else
i++;
setBuilding(i, pw, ph, w, h);
drawmap(map);
}
else if (GetAsyncKeyState('K') < 0)
{
if (orx != pw || ory != ph)
orx = pw, ory = ph, i++;
if (i == 0)
i = 13;
else
i--;
setBuilding(i, pw, ph, w, h);
drawmap(map);
}
else if (GetAsyncKeyState(' ') < 0)
{
break;
}
}
}
savemap();
return true;
}
void initmap_construction()
{
for (int i = 32; i < 34; i++)
for (int j = 9; j < 15; j++)
map[i][j] = 1;
map[34][10] = map[35][10] = map[34][9] = map[35][9] = map[34][13] = map[35][13] = map[34][14] = map[35][14] = 1;
map[34][11] = 6;
map[34][12] = map[35][11] = map[35][12] = 8;
}
void setBuilding(int type, int x, int y, int w, int h)
{
int i = y / 24;
int j = x / 40;
int x0 = i * 24 + j, x1 = i * 24 + j + 1, x2 = (i + 1) * 24 + j, x3 = (i + 1) * 24 + j + 1;
switch (type)
{
case 0:map[i][j] = map[i][j+1] = map[i+1][j] = map[i+1][j+1] = 0; break;
case 1:map[i][j] = map[i][j+1] = 1; map[i+1][j] = map[i+1][j+1] = 0; break;
case 2:map[i][j+1] = map[i+1][j+1] = 1; map[i][j] = map[i+1][j] = 0; break;
case 3:map[i+1][j] = map[i+1][j+1] = 1; map[i][j] = map[i][j+1] = 0; break;
case 4:map[i][j] = map[i+1][j] = 1; map[i][j+1] = map[i+1][j+1] = 0; break;
case 5:map[i][j] = map[i][j+1] = map[i+1][j] = map[i+1][j+1] = 1; break;
case 6:map[i][j] = map[i][j+1] = 4; map[i+1][j] = map[i+1][j+1] = 0; break;
case 7:map[i][j+1] = map[i+1][j+1] = 4; map[i][j] = map[i+1][j] = 0; break;
case 8:map[i+1][j] = map[i+1][j+1] = 4; map[i][j] = map[i][j+1] = 0; break;
case 9:map[i][j] = map[i+1][j] = 4; map[i][j+1] = map[i+1][j+1] = 0; break;
case 10:map[i][j] = map[i][j+1] = map[i+1][j] = map[i+1][j+1] = 4; break;
case 11:map[i][j] = map[i][j+1] = map[i+1][j] = map[i+1][j+1] = 2; break;
case 12:map[i][j] = map[i][j+1] = map[i+1][j] = map[i+1][j+1] = 3; break;
case 13:map[i][j] = map[i][j+1] = map[i+1][j] = map[i+1][j+1] = 5; break;
}
}
void drawmap(int map[36][24])
{
IMAGE img[9];
loadimage(&img[0], _T("Res/bk.png"), 40, 24, 1);
loadimage(&img[1], _T("Res/brick.jpg"), 40, 24, 1);
loadimage(&img[2], _T("Res/grass.jpg"), 40, 24, 1);
loadimage(&img[3], _T("Res/ice.jpg"), 40, 24, 1);
loadimage(&img[4], _T("Res/iron.jpg"), 40, 24, 1);
loadimage(&img[5], _T("Res/river.jpg"), 40, 24, 1);
loadimage(&img[6], _T("Res/headquarter/01.jpg"),80,48,1);
loadimage(&img[7], _T("Res/headquarter/02.jpg"), 80, 48, 1);
for (int i = 0; i < 36; i++) {
for (int j = 0; j < 24; j++) {
putimage(40 * j, 24 * i, &img[map[i][j]]);
}
}
}
void handlekey(int* pw, int* ph, int w, int h)
{
IMAGE tank;
int time;
int timetrigger = 0;
loadimage(&tank, _T("Res/1p/tank0.jpg"));
setfillcolor(BLACK);
if (GetAsyncKeyState('W') < 0)
{
if (*ph != 0)
*(ph) -= 2 * h;
}
else if (GetAsyncKeyState('S') < 0)
{
if (*ph != 816)
*(ph) += 2 * h;
}
else if (GetAsyncKeyState('A') < 0)
{
if (*pw != 0)
*(pw) -= 2 * w;
}
else if (GetAsyncKeyState('D') < 0)
{
if (*pw != 880)
*(pw) += 2 * w;
}
puttank(*pw, *ph);
}
void puttank(int x, int y)
{
IMAGE tank, mask;
loadimage(&tank, _T("Res/construction_tank/tank0.jpg"));
loadimage(&mask, _T("Res/construction_tank/mask.jpg"));
putimage(x, y, &mask, SRCAND);
putimage(x, y, &tank, SRCPAINT);
}
void savemap()
{
map[34][11] = 6;
map[34][12] = map[35][11] = map[35][12] = 8;
for (int i = 0; i < 24; i++)
map[0][i] = map[1][i] = 0;
FILE* fp;
fopen_s(&fp, "Res/level 0.txt", "w");
for (int i = 0; i < 36; i++)
{
for (int j = 0; j < 24; j++)
fprintf(fp, "%d ", map[i][j]);
fprintf(fp, "\n");
}
fclose(fp);
}
这里涉及到的主要是文件的操作具体可看C语言文件读写函数详解 同时要说的是游戏地图我们按单位分成了36行24列,便于放置砖块等地形。
###1P模式 _1pmode.cpp
#include"game.h"
#pragma warning(disable:4996)
using namespace std;
#define tank1score 1000;
int map[36][24];
int total_enm = 30;
int enm = 0;
int max_enm = 4;
int time0 = 0, timetrigger = 0;
int bonus_item = 3;
int counttime = 0;
vector<Bullet> bullet_list;
vector<Tank> tank_enemy;
vector<Boom> boom_list;
tank _1p,_2p;
int onetank1killNum = 0;
int twotank1killNum = 0;
int onetankscore = 0;
int twotankscore = 0;
int pattern = 1;
void _1pmode(bool *if_construction)
{
int level = 1;
int if_win = 0;
load_play_audio("bk.mp3", 1, 1000);
IMAGE bk;
_1p.x = 280, _1p.y = 816, _1p.vx = 5, _1p.dir = 0, _1p.life = 5, _1p.enemy_tank = 0;
loadimagetank(&_1p, "1p");
tank_enemy.push_back(_1p);
if (*if_construction)
load_map(0), * if_construction = false;
else
load_map(level);
int frame = 0;
while (1)
{
time0 = GetTickCount();
if (time0 > timetrigger)
{
frame++;
timetrigger = time0 + 40;
if_win = gameend(0);
if (if_win == 0)
{
BeginBatchDraw();
bonus();
while (total_enm > 0 && enm < max_enm)
{
if (create_enm())
{
total_enm--;
enm++;
}
else
break;
}
if (counttime == 0)
{
for (int i = 1; i + tank_enemy.begin() != tank_enemy.end(); i++)
{
enemy_move(&tank_enemy[i], i);
}
}
else
counttime--;
if (counttime == 0)
{
if (frame % 15 == 0)
{
Tank mid;
mid = tank_enemy[0];
for (int i = 1; i + tank_enemy.begin() != tank_enemy.end(); i++) {
if (!(rand() % 2) && !tank_enemy[i].type && !tank_enemy[i].stop) {
AI_attack(tank_enemy[i].x, tank_enemy[i].y, i, mid.x, mid.y, mid.dir);
tank_enemy[i].direct.a = 0;
tank_enemy[i].direct.b = 0;
tank_enemy[i].direct.c = 0;
tank_enemy[i].direct.d = 0;
}
else if (tank_enemy[i].type == 1 && !tank_enemy[i].stop) {
AI_terminator(tank_enemy[i].x, tank_enemy[i].y, tank_enemy[i].dir,i);
tank_enemy[i].direct.a = 0;
tank_enemy[i].direct.b = 0;
tank_enemy[i].direct.c = 0;
tank_enemy[i].direct.d = 0;
}
}
}
}
drawmap(map);
PrintScore(tank_enemy[0].life, 0);
put_enmtank();
putplayertank(&tank_enemy[0]);
handlekeys(&tank_enemy[0],0);
checkgrass();
checkbullet();
drawbullet();
boom_draw();
if (frame % 2 == 0)
boom_update();
if (frame == 50)
{
frame = 0;
}
EndBatchDraw();
}
else
{
load_play_audio("bk.mp3", 2, 1000);
drawmap(map);
put_enmtank();
putplayertank(&tank_enemy[0]);
getimage(&bk, 0, 0, 960, 864);
gameend_play(if_win,bk);
SaveScore(onetankscore, twotankscore, 1);
Sleep(200);
while (1)
{
if (GetAsyncKeyState(' ') < 0)
break;
}
break;
}
}
}
}
void PrintScore(int onetankHP, int twotankHP)
{
int a4 = width - 270; int b4 = height - 150; int c4 = width - 90; int d4 = height - 50;
int a3 = width - 270; int b3 = height - 280; int c3 = width - 90; int d3 = height - 180;
int a2 = width - 270; int b2 = 180; int c2 = width - 90; int d2 = 280;
int a1 = width - 270; int b1 = 50; int c1 = width - 90; int d1 = 150;
RECT R4 = { a4,b4,c4,d4 };
RECT R3 = { a3,b3,c3,d3 };
RECT R2 = { a2,b2,c2,d2 };
RECT R1 = { a1,b1,c1,d1 };
onetankscore = onetank1killNum * tank1score;
twotankscore = twotank1killNum * tank1score;
char a[4][10];
sprintf_s(a[0], "1P: %d", onetankscore);
sprintf_s(a[1], "2P: %d", twotankscore);
sprintf_s(a[2], "1P: %d", onetankHP);
sprintf_s(a[3], "2P: %d", twotankHP);
clearrectangle(960, 0, 1280, 864);
settextcolor(WHITE);
settextstyle(0, 0, _T("Fixedsys 常规"));
drawtext(a[0], &R4, DT_CENTER);
drawtext(a[1], &R3, DT_CENTER);
drawtext(a[2], &R2, DT_CENTER);
drawtext(a[3], &R1, DT_CENTER);
}
void SaveScore(int onetankscore, int twotankscore, int pattern)
{
int a1 = 250;
int a2 = 270;
RECT R1 = { 540,50,740,150 };
RECT R2 = { 440,180,540,200 };
RECT R3 = { 740,180,840,200 };
RECT R4 = { 360,a1,620,a2 };
RECT R5 = { 660,a1,920,a2 };
FILE* cScore;
int nScore[10] = { 0 };
int tail = 0;
int i = 0;
int j = 1;
int i1 = 0;
int i2 = 1;
int j1 = 2;
int j2 = 3;
int nN = 0;
if (pattern == 1)
{
cScore = fopen("Res/p1score.txt", "r");
}
else
{
cScore = fopen("Res/p2score.txt", "r");
}
do
{
fscanf(cScore, "%d", &nScore[tail]);
tail++;
} while (!feof(cScore) && tail < 9);
fclose(cScore);
if (pattern == 1)
{
while (j <= tail)
{
i = 0;
while (i < j)
{
if (nScore[i] > nScore[j])
{
nN = nScore[j];
nScore[j] = nScore[i];
nScore[i] = nN;
}
i++;
}
j++;
}
}
else
{
while (j2 <= tail)
{
i1 = 0;
i2 = 0;
while (i2 < j1)
{
if ((nScore[i1] + nScore[i2]) > (nScore[j1] + nScore[j2]))
{
nN = nScore[j1];
nScore[j1] = nScore[i1];
nScore[i1] = nN;
nN = nScore[j2];
nScore[j2] = nScore[i2];
nScore[i2] = nN;
}
i1 = i1 + 2;
i2 = i2 + 2;
}
j1 = j1 + 2;
j2 = j2 + 2;
}
}
clearrectangle(0, 0, 1280, 864);
settextcolor(WHITE);
settextstyle(0, 0, _T("Fixedsys 常规"));
char _1pscore[10], _2pscore[10];
sprintf_s(_1pscore, "1p: %d", onetankscore);
sprintf_s(_2pscore, "2p: %d", twotankscore);
char score[10][20];
j = tail + 1;
for (i = 0; i <= tail; i++, j--)
sprintf_s(score[i], " %d", nScore[i]);
drawtext(_1pscore, &R2, DT_CENTER);
drawtext(_2pscore, &R3, DT_CENTER);
i = tail;
if (pattern == 1)
{
while (i >= 1)
{
drawtext(score[i], &R4, DT_CENTER);
i = i--;
a1 = a1 + 40;
a2 = a2 + 40;
R4 = { 360,a1,620,a2 };
}
}
else
{
while (i >= 2)
{
drawtext(score[i], &R4, DT_CENTER);
i = i--;
drawtext(score[i], &R5, DT_CENTER);
i = i--;
a1 = a1 + 80;
a2 = a2 + 80;
R4 = { 360,a1,620,a2 };
R5 = { 660,a1,920,a2 };
}
}
if (pattern == 1)
{
cScore = fopen("Res/p1score.txt", "w");
}
else
{
cScore = fopen("Res/p2score.txt", "w");
}
if (pattern == 1)
{
if (onetankscore >= nScore[tail])
{
nScore[tail] = onetankscore;
}
else
{
if (tail < 9)
{
nScore[(tail + 1)] = onetankscore;
tail++;
}
else
{
nScore[1] = onetankscore;
}
}
while (tail > 1)
{
fprintf(cScore, "%d\n", nScore[tail]);
tail--;
}
}
else
{
if ((onetankscore + twotankscore) >= (nScore[tail] + nScore[(tail - 1)]))
{
nScore[tail] = onetankscore;
nScore[(tail - 1)] = twotankscore;
}
else
{
nScore[1] = onetankscore;
nScore[0] = twotankscore;
}
while (tail > 1)
{
fprintf(cScore, "%d\n", nScore[tail]);
tail--;
}
}
fclose(cScore);
}
void bonus()
{
if (bonus_item == 3 && total_enm + enm == 25)
bonus_item--, counttime = 500;
}
int gameend(int mode)
{
int player_left = 0;
for (int i = 0; i + tank_enemy.begin() != tank_enemy.end(); ++i)
{
if (tank_enemy[i].enemy_tank != 1)
player_left++;
}
if (map[34][11] == 7 || !player_left)
return 1;
if (total_enm == 0 && enm == 0)
return 2;
return 0;
}
void gameend_play(int type,IMAGE bk)
{
settextstyle(100, 80, ("Fixedsys 常规"));
setbkmode(TRANSPARENT);
settextcolor(RED);
char s[3][20] = { "Game","Over","Win"};
RECT r1 = { 0,864,960,964 };
RECT r2 = { 0,964,960,1064 };
RECT r3 = { 0,332,960,532 };
if (type == 1)
{
thread t0(load_play_audio,"gameover.mp3", 0,1000);
t0.detach();
while (1)
{
time0 = GetTickCount();
if (time0 > timetrigger)
{
timetrigger = time0 + 40;
putimage(0, 0, &bk);
drawtext(s[0], &r1, DT_CENTER);
drawtext(s[1], &r2, DT_CENTER);
if (r1.top <= 334)
{
settextcolor(RGB(rand() % 255, rand() % 255, rand() % 255));
}
else
{
r1.bottom -= 10;
r1.top -= 10;
r2.bottom -= 10;
r2.top -= 10;
}
if (GetAsyncKeyState(' ') < 0)
break;
}
}
}
else if(type == 2)
{
thread t0(load_play_audio, "win.mp3", 0, 1000);
t0.detach();
while (1)
{
time0 = GetTickCount();
if (time0 > timetrigger)
{
timetrigger = time0 + 40;
putimage(0, 0, &bk);
drawtext(s[2], &r3, DT_CENTER);
if (r3.top <= 334)
{
settextcolor(RGB(rand() % 255, rand() % 255, rand() % 255));
}
else
{
r3.bottom -= 10;
r3.top -= 10;
}
if (GetAsyncKeyState(' ') < 0)
break;
}
}
}
bullet_list.clear();
tank_enemy.clear();
boom_list.clear();
enm = 0, total_enm = 20;
onetank1killNum = 0;
twotank1killNum = 0;
}
void checkbullet()
{
int x, y;
for (int i = 0; bullet_list.begin() + i != bullet_list.end(); i++)
{
x = bullet_list[i].x / 40, y = bullet_list[i].y / 24;
Boom mid;
if (bullet_list[i].y< 0 && bullet_list[i].dir == 0)
bullet_list[i].if_delete = 1;
else if (bullet_list[i].y + 18 > 864 && bullet_list[i].dir == 1)
bullet_list[i].if_delete = 1;
else if (bullet_list[i].x < 0 && bullet_list[i].dir == 2)
bullet_list[i].if_delete = 1;
else if (bullet_list[i].x + 30> 960 && bullet_list[i].dir == 3)
bullet_list[i].if_delete = 1;
else
{
switch (bullet_list[i].dir)
{
case 0:if (map[y][x] == 1 || map[y][x] == 4)
map[y][x] == 1?map[y][x] = 0:map[y][x] = 4,bullet_list[i].if_delete = 1;
if (map[y][x + 1] == 1 || map[y][x + 1] == 4)
map[y][x + 1] == 1?map[y][x + 1] = 0:map[y][x + 1] = 4,bullet_list[i].if_delete = 1;
break;
case 1:if (map[y + 1][x] == 1 || map[y + 1][x] == 4)
map[y + 1][x] == 1 ? map[y + 1][x] = 0 : map[y + 1][x] = 4,bullet_list[i].if_delete = 1;
if (map[y + 1][x + 1] == 1 || map[y + 1][x + 1] == 4)
map[y + 1][x + 1] == 1 ? map[y + 1][x + 1] = 0 : map[y + 1][x + 1] = 4, bullet_list[i].if_delete = 1;
if (map[y + 1][x] == 6 || map[y + 1][x] == 8)
map[34][11] = 7, bullet_list[i].if_delete = 1;
if (map[y + 1][x + 1] == 6 || map[y + 1][x + 1] == 8)
map[34][11] = 7, bullet_list[i].if_delete = 1;
break;
case 2:
case 3:if (map[y][x] == 1 || map[y][x] == 4)
map[y][x] == 1 ? map[y][x] = 0 : map[y][x] = 4, bullet_list[i].if_delete = 1;
if (map[y + 1][x] == 1 || map[y + 1][x] == 4)
map[y + 1][x] == 1 ? map[y + 1][x] = 0 : map[y + 1][x] = 4, bullet_list[i].if_delete = 1;
if (map[y][x] == 6 || map[y][x] == 8)
map[34][11] = 7, bullet_list[i].if_delete = 1;
break;
}
}
for (int j = 0; j + tank_enemy.begin() != tank_enemy.end(); j++)
{
if (bullet_list[i].x + 21 > tank_enemy[j].x && bullet_list[i].x < tank_enemy[j].x + 80
&& bullet_list[i].y + 12 > tank_enemy[j].y && bullet_list[i].y < tank_enemy[j].y + 48 && bullet_list[i].enemy_tank !=
tank_enemy[j].enemy_tank && (bullet_list[i].enemy_tank == 1 || tank_enemy[j].enemy_tank == 1))
{
bullet_list[i].if_delete = 1;
mid.type = 1;
mid.x = tank_enemy[j].x;
mid.y = tank_enemy[j].y;
boom_list.push_back(mid);
tank_enemy[j].life--;
if (tank_enemy[j].life == 0)
{
if (tank_enemy[j].enemy_tank == 1)
enm--;
tank_enemy.erase(tank_enemy.begin() + j);
if (bullet_list[i].enemy_tank == 0)
onetank1killNum++;
else if(bullet_list[i].enemy_tank == 2)
twotank1killNum++;
}
if (tank_enemy[j].enemy_tank == 0)
{
tank_enemy[j].x = 280, tank_enemy[j].y = 816;
tank_enemy[j].dir = 0;
}
else if(tank_enemy[j].enemy_tank == 2)
{
tank_enemy[j].x = 600, tank_enemy[j].y = 816;
tank_enemy[j].dir = 0;
}
break;
}
}
for (int j = 0; j + bullet_list.begin() != bullet_list.end(); ++j)
{
if (bullet_list[i].enemy_tank != bullet_list[j].enemy_tank && (bullet_list[i].enemy_tank == 1 || bullet_list[j].enemy_tank == 1))
{
if (bullet_list[i].x + 21 > bullet_list[j].x && bullet_list[i].x < bullet_list[j].x + 21
&& bullet_list[i].y + 12 > bullet_list[j].y && bullet_list[i].y < bullet_list[j].y + 12)
{
bullet_list[i].if_delete = 1;
bullet_list[j].if_delete = 1;
}
}
}
if (bullet_list[i].if_delete)
{
mid.type = 0;
mid.x = (bullet_list.begin() + i)->x - 20;
mid.y = (bullet_list.begin() + i)->y - 10;
boom_list.push_back(mid);
(bullet_list.begin() + i)->host->if_bullet = 1;
bullet_list.erase(bullet_list.begin() + i);
i--;
thread t1(load_play_audio, "boom.mp3", 0, 500);
t1.detach();
}
else
{
switch (bullet_list[i].dir)
{
case 0:bullet_list[i].y -= bullet_list[i].vy; break;
case 1:bullet_list[i].y += bullet_list[i].vy; break;
case 2:bullet_list[i].x -= bullet_list[i].vy; break;
case 3:bullet_list[i].x += bullet_list[i].vy; break;
}
}
}
}
void drawbullet()
{
IMAGE img[4];
IMAGE mask[4];
loadimage(&img[0], "Res/bullet/bullet0.jpg");
loadimage(&img[1], "Res/bullet/bullet1.jpg");
loadimage(&img[2], "Res/bullet/bullet2.jpg");
loadimage(&img[3], "Res/bullet/bullet3.jpg");
loadimage(&mask[0], "Res/bullet/mask0.jpg");
loadimage(&mask[1], "Res/bullet/mask1.jpg");
loadimage(&mask[2], "Res/bullet/mask2.jpg");
loadimage(&mask[3], "Res/bullet/mask3.jpg");
for (int i = 0; bullet_list.begin() + i != bullet_list.end(); i++)
{
putimage(bullet_list[i].x, bullet_list[i].y, &mask[bullet_list[i].dir], SRCAND);
putimage(bullet_list[i].x, bullet_list[i].y, &img[bullet_list[i].dir], SRCPAINT);
}
}
void boom_draw()
{
IMAGE img[5];
IMAGE mask[5];
char s[2][50];
for (int i = 0; i < 5; i++)
{
sprintf_s(s[0], "Res/boom/boom%d.jpg", i);
sprintf_s(s[1], "Res/boom/mask%d.jpg", i);
loadimage(&img[i], s[0]);
loadimage(&mask[i], s[1]);
}
for (int i = 0; i + boom_list.begin() != boom_list.end(); ++i)
{
if (boom_list[i].seq == 3)
{
boom_list[i].x -= 16, boom_list[i].y -= 12;
}
putimage(boom_list[i].x, boom_list[i].y, &mask[boom_list[i].seq], SRCAND);
putimage(boom_list[i].x, boom_list[i].y, &img[boom_list[i].seq], SRCPAINT);
}
}
void boom_update()
{
for (int i = 0; i + boom_list.begin() != boom_list.end(); ++i)
{
boom_list[i].seq++;
if ((boom_list[i].type == 0 && boom_list[i].seq == 3) || (boom_list[i].type == 1 && boom_list[i].seq == 5))
{
boom_list.erase(boom_list.begin() + i);
--i;
continue;
}
}
}
bool checkice(tank* tank)
{
int i = tank->y / 24;
int j = tank->x / 40;
switch (tank->dir)
{
case 0: if (map[i][j] == 3)
return true;
break;
case 1:if (map[i + 1][j] == 3)
return true;
break;
case 2:if (map[i][j] == 3)
return true;
break;
case 3:if (map[i][j + 1] == 3)
return true;
}
return false;
}
void checkgrass()
{
for (int n = 0; n + tank_enemy.begin() != tank_enemy.end(); ++n)
{
int i = tank_enemy[n].y / 24;
int j = tank_enemy[n].x / 40;
switch (tank_enemy[n].dir)
{
case 0: if (map[i][j] == 2 && map[i][j + 1] == 2)
drawgrass(j * 40, i * 24, 0);
if (map[i + 1][j] == 2 && map[i + 1][j + 1] == 2)
drawgrass(j * 40, i * 24, 1);
if (map[i + 2][j] == 2 && map[i + 2][j + 1] == 2)
drawgrass(j * 40, i * 24 + 24, 1);
break;
case 1:if (map[i + 1][j] == 2 && map[i + 1][j + 1] == 2)
drawgrass(j * 40, i * 24, 1);
if (map[i][j] == 2 && map[i + 1][j + 1] == 2)
drawgrass(j * 40, i * 24, 0);
if (map[i - 1][j] == 2 && map[i - 1][j + 1] == 2)
drawgrass(j * 40, i * 24 - 24, 0);
break;
case 2:if (map[i][j] == 2 && map[i + 1][j] == 2)
drawgrass(j * 40, i * 24, 2);
if (map[i][j + 1] == 2 && map[i + 1][j + 1] == 2)
drawgrass(j * 40, i * 24, 3);
break;
case 3:if (map[i][j + 1] == 2 && map[i + 1][j + 1] == 2)
drawgrass(j * 40, i * 24, 3);
if (map[i][j] == 2 && map[i + 1][j] == 2)
drawgrass(j * 40, i * 24, 2);
if (map[i][j - 1] == 2 && map[i + 1][j - 1] == 2)
drawgrass(j * 40 - 40, i * 24, 2);
break;
}
}
}
void handlekeys(tank* tank,int player)
{
int x = (tank->x % 40 <= 20) ? tank->x / 40 * 40 : (tank->x / 40 + 1) * 40;
int y = (tank->y % 24 <= 12) ? tank->y / 24 * 24 : (tank->y / 24 + 1) * 24;
if ((GetAsyncKeyState('W') < 0 && !player) || (GetAsyncKeyState(VK_UP) < 0 && player))
{
if (tank->x % 40 != 0 && checkturn_bug(x,tank->y,tank->width,tank->height,player))
{
tank->x = x;
}
tank->dir = 0;
if (!checkhit(tank,player))
tank->y -= tank->vx;
}
else if ((GetAsyncKeyState('S') < 0 && !player) || (GetAsyncKeyState(VK_DOWN) < 0 && player))
{
if (tank->x % 40 != 0 && checkturn_bug(x, tank->y, tank->width, tank->height, player))
{
tank->x = x;
}
tank->dir = 1;
if (!checkhit(tank,player))
tank->y += tank->vx;
}
else if ((GetAsyncKeyState('A') < 0 && !player) || (GetAsyncKeyState(VK_LEFT) < 0 && player))
{
if (tank->y % 24 != 0 && checkturn_bug(tank->x,y,tank->width,tank->height, player))
{
tank->y = y;
}
tank->dir = 2;
if (!checkhit(tank,player))
tank->x -= tank->vx;
}
else if ((GetAsyncKeyState('D') < 0 && !player) || (GetAsyncKeyState(VK_RIGHT) < 0 && player))
{
if (tank->y % 24 != 0 && checkturn_bug(tank->x, y, tank->width, tank->height, player))
{
tank->y = y;
}
tank->dir = 3;
if (!checkhit(tank,player))
tank->x += tank->vx;
}
if ((((GetAsyncKeyState('J') < 0 || GetAsyncKeyState('K') < 0) && !player) ||
((GetAsyncKeyState(VK_NUMPAD4) < 0 || GetAsyncKeyState(VK_NUMPAD5) < 0) && player)) && tank->if_bullet == 1)
{
shoot(tank);
}
else if (GetAsyncKeyState('M') < 0 && !player)
{
Boom mid;
for (int i = player+1; i + tank_enemy.begin() != tank_enemy.end(); ++i)
{
mid.type = 1;
mid.x = tank_enemy[i].x;
mid.y = tank_enemy[i].y;
boom_list.push_back(mid);
tank_enemy[i].life--;
if (tank_enemy[i].life == 0)
{
if (tank_enemy[i].enemy_tank == 1)
enm--;
tank_enemy.erase(tank_enemy.begin() + i);
i--;
}
}
}
}
void shoot(tank* tank)
{
Bullet mid_bullet;
mid_bullet.dir = tank->dir;
mid_bullet.enemy_tank = tank->enemy_tank;
switch (tank->dir)
{
case 0:mid_bullet.x = tank->x + tank->width / 2 - 11, mid_bullet.y = tank->y; break;
case 1:mid_bullet.x = tank->x + tank->width / 2 - 11, mid_bullet.y = tank->y + tank->height - 18; break;
case 2:mid_bullet.x = tank->x - 15, mid_bullet.y = tank->y + tank->height / 2 - 6; break;
case 3:mid_bullet.x = tank->x + tank->width - 15, mid_bullet.y = tank->y + tank->height / 2 - 6; break;
}
mid_bullet.host = tank;
bullet_list.push_back(mid_bullet);
tank->if_bullet = 0;
thread t1(load_play_audio,("tankfire1.mp3"),0,1000);
t1.detach();
}
void drawgrass(int x, int y,int type)
{
IMAGE grass;
IMAGE mask;
loadimage(&mask, "Res/grass1.jpg", 40, 24);
loadimage(&grass, "Res/grass.jpg", 40, 24);
switch (type)
{
case 0:putimage(x, y, &mask, SRCAND);
putimage(x, y, &grass, SRCPAINT);
putimage(x + 40, y, &mask, SRCAND);
putimage(x + 40, y, &grass, SRCPAINT); break;
case 1:putimage(x, y + 24, &mask, SRCAND);
putimage(x, y + 24, &grass, SRCPAINT);
putimage(x + 40, y + 24, &mask, SRCAND);
putimage(x + 40, y + 24, &grass, SRCPAINT); break;
case 2:putimage(x, y, &mask, SRCAND);
putimage(x, y, &grass, SRCPAINT);
putimage(x, y + 24, &mask, SRCAND);
putimage(x, y + 24, &grass, SRCPAINT); break;
case 3:putimage(x + 40, y, &mask, SRCAND);
putimage(x + 40, y, &grass, SRCPAINT);
putimage(x + 40, y + 24, &mask, SRCAND);
putimage(x + 40, y + 24, &grass, SRCPAINT); break;
case 4:putimage(x, y, &mask, SRCAND);
putimage(x, y, &grass, SRCPAINT);
putimage(x + 40, y, &grass, SRCPAINT);
putimage(x, y + 24, &grass, SRCPAINT);
putimage(x + 40, y + 24, &grass, SRCPAINT);
}
}
bool checkhit(tank* tank,int enmid)
{
int j = tank->x / 40;
int i = tank->y / 24;
if (i == 0 && tank->y - tank->vx < 0 && tank->dir == 0)
return true;
else if (tank->y + tank->vx + tank->height> 864 && tank->dir == 1)
return true;
if (tank->x - tank->vx < 0 && tank->dir == 2)
return true;
else if (tank->x + tank->vx + tank->width > 960 && tank->dir == 3)
return true;
switch (tank->dir)
{
case 0: if ((tank->y - tank->vx) < i * 24 && ((map[i - 1][j] == 1 || map[i - 1][j] == 4 || map[i - 1][j] == 5)
|| (map[i - 1][j + 1] == 1 || map[i - 1][j + 1] == 4 || map[i - 1][j + 1] == 5)))
return true; break;
case 1: if (tank->y + tank->vx + tank->height >= (i + 2) * 24 && ((map[i + 2][j] == 1 ||
map[i + 2][j] == 4 || map[i + 2][j] == 5) || (map[i + 2][j + 1] == 1 ||
map[i + 2][j + 1] == 4 || map[i + 2][j + 1] == 5)))
return true; break;
case 2: if (tank->x - tank->vx < j * 40 && ((map[i][j - 1] == 1 || map[i][j - 1] == 4 || map[i][j - 1] == 5)
|| (map[i + 1][j - 1] == 1 || map[i + 1][j - 1] == 4 || map[i + 1][j - 1] == 5)))
return true; break;
case 3: if (tank->x + tank->vx + tank->width > (j + 2) * 40 && ((map[i][j + 2] == 1 || map[i][j + 2] == 4
|| map[i][j + 2] == 5) || (map[i + 1][j + 2] == 1 || map[i + 1][j + 2] == 4 || map[i + 1][j + 2] == 5)))
return true; break;
}
int xn, yn;
switch (tank->dir)
{
case 0: xn = tank->x, yn = tank->y - tank->vx; break;
case 1: xn = tank->x, yn = tank->y + tank->vx; break;
case 2: xn = tank->x - tank->vx, yn = tank->y; break;
case 3: xn = tank->x + tank->vx, yn = tank->y; break;
}
for (int i = 0; i + tank_enemy.begin() != tank_enemy.end(); i++)
{
if (enmid == i)
continue;
if (tank->x + 80 > tank_enemy[i].x && tank->x < tank_enemy[i].x + 80
&& tank->y + 48 > tank_enemy[i].y && tank->y < tank_enemy[i].y + 48)
return false;
if (xn + 80 > tank_enemy[i].x && xn < tank_enemy[i].x + 80
&& yn + 48 > tank_enemy[i].y && yn < tank_enemy[i].y + 48)
return true;
}
return false;
}
bool checkturn_bug(int x, int y,int width,int height,int id)
{
for (int i = 0; i + tank_enemy.begin() != tank_enemy.end(); ++i)
{
if (i == id)
continue;
if (tank_enemy[i].x + tank_enemy[i].width > x && tank_enemy[i].x < x + width&&
tank_enemy[i].y < y + height && tank_enemy[i].y + tank_enemy[i].height > y)
return false;
}
return true;
}
bool create_enm()
{
Tank mid;
srand(GetTickCount());
int x[4] = { 0, 160, 400, 880 };
int able[4] = { -1,-1,-1,-1 };
int count = 0;
mid.y = 0;
int i, j;
for (i = 0; i < 4; i++)
{
for (j = 0; j + tank_enemy.begin() != tank_enemy.end(); j++)
{
if (tank_enemy[j].y < 57 && tank_enemy[j].x > x[i] - 85 && tank_enemy[j].x < x[i] + 85)
break;
}
if (j + tank_enemy.begin() == tank_enemy.end())
{
able[count++] = i;
}
}
if (able[0] == -1)
return false;
else
mid.x = x[able[rand() % count]];
mid.type = (rand() % 2 == 1) ? 0 : 1;
int random = rand() % 9 ;
if (random <= 2)
loadimagetank(&mid, "tank1");
else if (random <= 5)
loadimagetank(&mid, "tank2");
else
loadimagetank(&mid, "tank3");
tank_enemy.push_back(mid);
return true;
}
void put_enmtank()
{
for (int i = 1; i + tank_enemy.begin() != tank_enemy.end(); i++)
{
if (tank_enemy[i].enemy_tank == 1)
{
putplayertank(&tank_enemy[i]);
}
}
}
void putplayertank(tank *tank)
{
putimage(tank->x, tank->y, &tank->mask[tank->dir], SRCAND);
putimage(tank->x, tank->y, &tank->img[tank->dir], SRCPAINT);
}
void AI_attack(int x, int y, int i, int tank_x, int tank_y, int tank_dir) {
int row = y / 24;
int col = x / 40;
int tank_row = tank_y / 24;
int tank_col = tank_x / 40;
int dert_x = x - tank_x;
int dert_y = y - tank_y;
int if_shoot = 1;
int if_bound = 0;
search_path(&tank_enemy[i], i);
if (abs(dert_x) < 80 ) {
if (dert_y > 0) {
for (int i = row; i > tank_row; i--) {
if (map[i][col] == 4 || map[i][col + 1] == 4) {
if_shoot = 0;
}
}
if (if_shoot) {
tank_enemy[i].dir = 0;
}
else {
for (;;) {
if (!(rand() % 5) && tank_enemy[i].direct.a) {
tank_enemy[i].dir = 0;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.c) {
tank_enemy[i].dir = 2;
break;
}
if (!(rand() % 15) && tank_enemy[i].direct.d) {
tank_enemy[i].dir = 3;
break;
}
if (!(rand() % 20) && tank_enemy[i].direct.b) {
tank_enemy[i].dir = 1;
break;
}
}
}
}
else {
for (int i = row; i < tank_row; i++) {
if (map[i][col] == 4 || map[i][col + 1] == 4) {
if_shoot = 0;
}
}
if (if_shoot) {
tank_enemy[i].dir = 1;
}
else {
for (;;) {
if (!(rand() % 5) && tank_enemy[i].direct.b) {
tank_enemy[i].dir = 1;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.c) {
tank_enemy[i].dir = 2;
break;
}
if (!(rand() % 15) && tank_enemy[i].direct.d) {
tank_enemy[i].dir = 3;
break;
}
if (!(rand() % 20) && tank_enemy[i].direct.a) {
tank_enemy[i].dir = 0;
break;
}
}
}
}
if (if_shoot && tank_enemy[i].if_bullet) {
shoot(&tank_enemy[i]);
tank_enemy[i].if_bullet = 0;
}
}
else if (abs(dert_y) < 48 ) {
if (dert_x > 0) {
for (int i = col; i > tank_col; i--) {
if (map[row][i] == 4 || map[row + 1][i] == 4) {
if_shoot = 0;
}
}
if (if_shoot) {
tank_enemy[i].dir = 2;
}
else {
for (;;) {
if (!(rand() % 5) && tank_enemy[i].direct.c) {
tank_enemy[i].dir = 2;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.a) {
tank_enemy[i].dir = 0;
break;
}
if (!(rand() % 15) && tank_enemy[i].direct.b) {
tank_enemy[i].dir = 1;
break;
}
if (!(rand() % 20) && tank_enemy[i].direct.d) {
tank_enemy[i].dir = 3;
break;
}
}
}
}
else {
for (int i = col; i < tank_col; i++) {
if (map[row][i] == 4 || map[row + 1][i] == 4) {
if_shoot = 0;
}
}
if (if_shoot) {
tank_enemy[i].dir = 3;
}
else {
for (;;) {
if (!(rand() % 5) && tank_enemy[i].direct.d) {
tank_enemy[i].dir = 3;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.a) {
tank_enemy[i].dir = 0;
break;
}
if (!(rand() % 15) && tank_enemy[i].direct.b) {
tank_enemy[i].dir = 1;
break;
}
if (!(rand() % 20) && tank_enemy[i].direct.c) {
tank_enemy[i].dir = 2;
break;
}
}
}
}
if (if_shoot && tank_enemy[i].if_bullet) {
shoot(&tank_enemy[i]);
tank_enemy[i].if_bullet = 0;
}
}
if (checkhit(&tank_enemy[i], i)) {
switch (tank_enemy[i].dir)
{
case 0: if (tank_enemy[i].y - tank_enemy[i].vx < 0) {
for (;;) {
if (!(rand() % 5) && tank_enemy[i].direct.b) {
tank_enemy[i].dir = 1;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.c) {
tank_enemy[i].dir = 2;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.d) {
tank_enemy[i].dir = 3;
break;
}
}
if_bound = 1;
} break;
case 1: if (tank_enemy[i].y + tank_enemy[i].vx + tank_enemy[i].height > 864) {
for (;;) {
if (!(rand() % 5) && tank_enemy[i].direct.a) {
tank_enemy[i].dir = 0;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.c) {
tank_enemy[i].dir = 2;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.d) {
tank_enemy[i].dir = 3;
break;
}
}
if_bound = 1;
} break;
case 2: if (tank_enemy[i].x - tank_enemy[i].vx < 0) {
for (;;) {
if (!(rand() % 5) && tank_enemy[i].direct.d) {
tank_enemy[i].dir = 3;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.a) {
tank_enemy[i].dir = 0;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.b) {
tank_enemy[i].dir = 1;
break;
}
}
if_bound = 1;
} break;
case 3: if (tank_enemy[i].x + tank_enemy[i].vx + tank_enemy[i].width > 960) {
for (;;) {
if (!(rand() % 5) && tank_enemy[i].direct.c) {
tank_enemy[i].dir = 2;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.a) {
tank_enemy[i].dir = 0;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.b) {
tank_enemy[i].dir = 1;
break;
}
}
if_bound = 1;
} break;
}
if (!if_bound) {
tank_enemy[i].direct.a = 0;
tank_enemy[i].direct.b = 0;
tank_enemy[i].direct.c = 0;
tank_enemy[i].direct.d = 0;
search_path(&tank_enemy[i], i);
if (dert_x > 0) {
for (;;) {
if (!(rand() % 5) && tank_enemy[i].direct.c) {
tank_enemy[i].dir = 2;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.a) {
tank_enemy[i].dir = 0;
break;
}
if (!(rand() % 15) && tank_enemy[i].direct.b) {
tank_enemy[i].dir = 1;
break;
}
if (!(rand() % 20) && tank_enemy[i].direct.d) {
tank_enemy[i].dir = 3;
break;
}
}
}
else {
for (;;) {
if (!(rand() % 5) && tank_enemy[i].direct.d) {
tank_enemy[i].dir = 3;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.b) {
tank_enemy[i].dir = 1;
break;
}
if (!(rand() % 18) && tank_enemy[i].direct.a) {
tank_enemy[i].dir = 0;
break;
}
if (!(rand() % 33) && tank_enemy[i].direct.c) {
tank_enemy[i].dir = 2;
break;
}
}
}
}
}
else if (!checkhit(&tank_enemy[i], i) ) {
if (abs(dert_x) > abs(dert_y)) {
for (;;) {
if (!(rand() % 5) && tank_enemy[i].direct.a) {
tank_enemy[i].dir = 0;
break;
}
if (!(rand() % 8) && tank_enemy[i].direct.b) {
tank_enemy[i].dir = 1;
break;
}
if (!(rand() % 44) && tank_enemy[i].direct.c) {
tank_enemy[i].dir = 2;
break;
}
if (!(rand() % 29) && tank_enemy[i].direct.d) {
tank_enemy[i].dir = 3;
break;
}
}
}
else {
for (;;) {
if (!(rand() % 10) && tank_enemy[i].direct.c) {
tank_enemy[i].dir = 2;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.d) {
tank_enemy[i].dir = 3;
break;
}
if (!(rand() % 30) && tank_enemy[i].direct.a) {
tank_enemy[i].dir = 0;
break;
}
if (!(rand() % 30) && tank_enemy[i].direct.b) {
tank_enemy[i].dir = 1;
break;
}
}
}
}
}
void AI_terminator(int x, int y, int dir, int i) {
void A_(int x, int y, int dir, int i);
int dert_x = x - 10 * 40;
int dert_y = y - 34 * 24;
int asd;
int if_bound = 0;
search_path(&tank_enemy[i], i);
if_boundary(i, dir, if_bound);
if (if_bound) {
tank_enemy[i].stop = 0;
return;
}
if (checkhit(&tank_enemy[i], i)) {
search_path(&tank_enemy[i], i);
for (;;) {
if ((rand() % 2) && tank_enemy[i].direct.b) {
if (tank_enemy[i].x % 40 != 0 && checkturn_bug((tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40,
tank_enemy[i].y, tank_enemy[i].width, tank_enemy[i].height, i))
{
tank_enemy[i].x = (tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40;
}
tank_enemy[i].dir = 1;
break;
}
if ((rand() % 2) && tank_enemy[i].direct.c) {
if (tank_enemy[i].y % 24 != 0 && checkturn_bug(tank_enemy[i].x, (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24, tank_enemy[i].width, tank_enemy[i].height, i))
{
tank_enemy[i].y = (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24;
}
tank_enemy[i].dir = 2;
break;
}
if ((rand() % 2) && tank_enemy[i].direct.d) {
if (tank_enemy[i].y % 24 != 0 && checkturn_bug(tank_enemy[i].x, (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24, tank_enemy[i].width, tank_enemy[i].height, i))
{
tank_enemy[i].y = (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24;
}
tank_enemy[i].dir = 3;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.a) {
if (tank_enemy[i].x % 40 != 0 && checkturn_bug((tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40,
tank_enemy[i].y, tank_enemy[i].width, tank_enemy[i].height, i))
{
tank_enemy[i].x = (tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40;
}
tank_enemy[i].dir = 0;
break;
}
}
tank_enemy[i].stop = 0;
return;
}
if (tank_enemy[i].stop) {
tank_enemy[i].stop--;
}
if (dert_y < 0 && tank_enemy[i].direct.b) {
if (tank_enemy[i].x % 40 != 0 && checkturn_bug((tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40,
tank_enemy[i].y, tank_enemy[i].width, tank_enemy[i].height, i))
{
tank_enemy[i].x = (tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40;
}
tank_enemy[i].dir = 1;
if (!rand() % 10) {
tank_enemy[i].stop = 4;
}
}
if (dert_x > 40 * 6 && !tank_enemy[i].stop) {
if (tank_enemy[i].direct.c) {
if (tank_enemy[i].y % 24 != 0 && checkturn_bug(tank_enemy[i].x, (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24, tank_enemy[i].width, tank_enemy[i].height, i))
{
tank_enemy[i].y = (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24;
}
tank_enemy[i].dir = 2;
}
else {
if (tank_enemy[i].direct.a) {
if (tank_enemy[i].x % 40 != 0 && checkturn_bug((tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40,
tank_enemy[i].y, tank_enemy[i].width, tank_enemy[i].height, i))
{
tank_enemy[i].x = (tank_enemy[i].x % 40 <= 20) ? tank_enemy[i].x / 40 * 40 : (tank_enemy[i].x / 40 + 1) * 40;
}
tank_enemy[i].dir = 0;
}
if (tank_enemy[i].direct.d) {
if (tank_enemy[i].y % 24 != 0 && checkturn_bug(tank_enemy[i].x, (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24, tank_enemy[i].width, tank_enemy[i].height, i))
{
tank_enemy[i].y = (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24;
}
tank_enemy[i].dir = 3;
}
}
if (!rand() % 10) {
tank_enemy[i].stop = 4;
}
}
if (dert_x > 40 * 4 && !tank_enemy[i].stop) {
if (tank_enemy[i].direct.d) {
if (tank_enemy[i].y % 24 != 0 && checkturn_bug(tank_enemy[i].x, (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24, tank_enemy[i].width, tank_enemy[i].height, i))
{
tank_enemy[i].y = (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24;
}
tank_enemy[i].dir = 3;
}
else {
if (tank_enemy[i].direct.a) {
tank_enemy[i].dir = 0;
}
if (tank_enemy[i].direct.c) {
if (tank_enemy[i].y % 24 != 0 && checkturn_bug(tank_enemy[i].x, (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24, tank_enemy[i].width, tank_enemy[i].height, i))
{
tank_enemy[i].y = (tank_enemy[i].y % 24 <= 12) ? tank_enemy[i].y / 24 * 24 : (tank_enemy[i].y / 24 + 1) * 24;
}
tank_enemy[i].dir = 2;
}
}
if (!rand() % 10) {
tank_enemy[i].stop = 4;
}
}
if (y <= 12 * 24) {
asd = !(rand() % 10);
}
else {
asd = !(rand() % 3);
}
if ((dert_x >= 0 && dert_x <= 40 && tank_enemy[i].dir == 1) || (dert_y >= 0 && dert_y <= 48)) {
if (tank_enemy[i].if_bullet && !asd) {
shoot(&tank_enemy[i]);
tank_enemy[i].if_bullet = 0;
}
}
}
void if_boundary(int i, int dir, int a) {
search_path(&tank_enemy[i], i);
switch (dir)
{
case 0: if (tank_enemy[i].y - tank_enemy[i].vx < 0) {
tank_enemy[i].dir = 1;
a = 1;
} break;
case 1: if (tank_enemy[i].y + tank_enemy[i].vx + tank_enemy[i].height > 864) {
if (tank_enemy[i].x > 10 * 40) {
tank_enemy[i].dir = 2;
}
else {
tank_enemy[i].dir = 3;
}
if (tank_enemy[i].if_bullet) {
shoot(&tank_enemy[i]);
tank_enemy[i].if_bullet = 0;
}
a = 1;
} break;
case 2: if (tank_enemy[i].x - tank_enemy[i].vx < 0) {
for (;;) {
if ((rand() % 2) && tank_enemy[i].direct.b) {
tank_enemy[i].dir = 1;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.d) {
tank_enemy[i].dir = 3;
break;
}
if (!(rand() % 15) && tank_enemy[i].direct.a) {
tank_enemy[i].dir = 0;
break;
}
}
a = 1;
} break;
case 3: if (tank_enemy[i].x + tank_enemy[i].vx + tank_enemy[i].width > 960) {
for (;;) {
if (!(rand() % 2) && tank_enemy[i].direct.b) {
tank_enemy[i].dir = 1;
break;
}
if (!(rand() % 10) && tank_enemy[i].direct.c) {
tank_enemy[i].dir = 2;
break;
}
if (!(rand() % 15) && tank_enemy[i].direct.a) {
tank_enemy[i].dir = 0;
break;
}
}
a = 1;
} break;
}
}
void search_path(tank* tank, int i) {
int col = tank->x / 40;
int row = tank->y / 24;
if (map[row - 1][col] == 0 || map[row - 1][col] == 1 || map[row - 1][col] == 2 || map[row - 1][col + 1] == 0 || map[row - 1][col + 1] == 1 || map[row - 1][col + 1] == 2) {
tank->direct.a = 1;
if ((map[row - 1][col] == 1 || map[row - 1][col + 1] == 1) && tank->if_bullet && tank->dir == 0) {
shoot(tank);
tank->if_bullet = 0;
}
}
if (map[row + 2][col] == 0 || map[row + 2][col] == 1 || map[row + 2][col] == 2 || map[row + 2][col + 1] == 0 || map[row + 2][col + 1] == 1 || map[row + 2][col + 1] == 2) {
tank->direct.b = 1;
if ((map[row + 2][col] == 1 || map[row + 2][col + 1] == 1) && tank->if_bullet && tank->dir == 1) {
shoot(tank);
tank->if_bullet = 0;
}
}
if (map[row][col - 1] == 0 || map[row][col - 1] == 1 || map[row][col - 1] == 2 || map[row + 1][col - 1] == 0 || map[row + 1][col - 1] == 1 || map[row + 1][col - 1] == 2) {
tank->direct.c = 1;
if ((map[row][col - 1] == 1 || map[row + 1][col - 1] == 1) && tank->if_bullet && tank->dir == 2) {
shoot(tank);
tank->if_bullet = 0;
}
}
if (map[row][col + 2] == 0 || map[row][col + 2] == 1 || map[row][col + 2] == 2 || map[row + 1][col + 2] == 0 || map[row + 1][col + 2] == 1 || map[row + 1][col + 2] == 2) {
tank->direct.d = 1;
if ((map[row][col + 2] == 1 || map[row + 1][col + 2] == 1) && tank->if_bullet && tank->dir == 3) {
shoot(tank);
tank->if_bullet = 0;
}
}
switch (tank->dir)
{
case 0: if (checkhit(tank, i) && tank->direct.a) {
tank->direct.a = 0;
} break;
case 1: if (checkhit(tank, i) && tank->direct.b) {
tank->direct.b = 0;
} break;
case 2: if (checkhit(tank, i) && tank->direct.c) {
tank->direct.c = 0;
} break;
case 3: if (checkhit(tank, i) && tank->direct.d) {
tank->direct.d = 0;
} break;
}
}
void enemy_move(tank* tank, int i) {
switch (tank->dir) {
case 0: if (!checkhit(tank, i)) {
tank->y -= tank->vx;
} break;
case 1: if (!checkhit(tank, i)) {
tank->y += tank->vx;
} break;
case 2: if (!checkhit(tank, i)) {
tank->x -= tank->vx;
} break;
case 3: if (!checkhit(tank, i)) {
tank->x += tank->vx;
} break;
}
}
void loadimagetank(tank* tank,const char s[])
{
char a[2][4][30];
for (int i = 0; i < 4; i++)
{
sprintf_s(a[0][i], "Res/%s/tank%d.jpg", s,i);
sprintf_s(a[1][i], "Res/%s/mask%d.jpg", s, i);
loadimage(&tank->img[i], a[0][i]);
loadimage(&tank->mask[i], a[1][i]);
}
tank->width = tank->img[2].getwidth();
tank->height = tank->img[0].getheight();
}
void load_map(int level)
{
FILE* fp;
char s[20] = "";
sprintf_s(s, "Res/level %d.txt",level);
fopen_s(&fp, s, "r");
for (int i = 0; i < 36; i++)
for (int j = 0; j < 24; j++)
fscanf_s(fp, "%d", &map[i][j]);
fclose(fp);
}
因为是游戏主要的部分所以代码最多,还涉及到AI知识,如果有兴趣可以自己了解一下 这里为了在播放背景音乐的同时能播放其他生效用了最简单的一种多线程如
thread t1(load_play_audio,("tankfire1.mp3"),0,1000);
t1.detach();
详情见C++ 多线程–STL库 总结版 (详细)
###2P模式 _2pmode.cpp
#include"game.h"
using namespace std;
void _2pmode(bool* if_construction)
{
int level = 1;
int if_win = 0;
load_play_audio("bk.mp3", 1, 1000);
IMAGE bk;
_1p.x = 280, _1p.y = 816, _1p.vx = 5, _1p.dir = 0, _1p.life = 5, _1p.enemy_tank = 0;
loadimagetank(&_1p, "1p");
_2p.x = 600, _2p.y = 816, _2p.vx = 5, _2p.dir = 0, _2p.life = 5, _2p.enemy_tank = 2;
loadimagetank(&_2p, "2p");
tank_enemy.push_back(_1p);
tank_enemy.push_back(_2p);
if (*if_construction)
load_map(0), * if_construction = false;
else
load_map(level);
int frame = 0;
while (1)
{
time0 = GetTickCount();
if (time0 > timetrigger)
{
frame++;
timetrigger = time0 + 40;
if_win = gameend(0);
if (if_win == 0)
{
BeginBatchDraw();
while (total_enm > 0 && enm < max_enm)
{
if (create_enm())
{
total_enm--;
enm++;
}
else
break;
}
for (int i = 2; i + tank_enemy.begin() != tank_enemy.end(); i++) {
enemy_move(&tank_enemy[i], i);
}
PrintScore(tank_enemy[0].life, tank_enemy[1].life);
drawmap(map);
put_enmtank();
putplayertank(&tank_enemy[0]);
putplayertank(&tank_enemy[1]);
if (tank_enemy[1].enemy_tank == 2)
{
thread t1(handlekeys,&tank_enemy[1],1);
t1.detach();
}
handlekeys(&tank_enemy[0],0);
checkgrass();
checkbullet();
drawbullet();
boom_draw();
if (frame % 2 == 0)
boom_update();
if (frame % 8 == 0)
{
Tank mid;
mid = rand() % 2 == 1 ? tank_enemy[0] : tank_enemy[1];
for (int i = 2; i + tank_enemy.begin() != tank_enemy.end(); i++) {
if (tank_enemy[i].stop) {
tank_enemy[i].stop--;
continue;
}
if (!tank_enemy[i].type && !tank_enemy[i].stop) {
AI_attack(tank_enemy[i].x, tank_enemy[i].y, i, mid.x, mid.y, mid.dir);
if (!(rand() % 10))
tank_enemy[i].stop = 3;
}
else if (tank_enemy[i].type == 1 && !tank_enemy[i].stop) {
AI_terminator(tank_enemy[i].x, tank_enemy[i].y, tank_enemy[i].dir, i);
}
}
}
if (frame == 50)
{
frame = 0;
}
EndBatchDraw();
}
else
{
load_play_audio("bk.mp3", 2, 1000);
drawmap(map);
put_enmtank();
putplayertank(&tank_enemy[0]);
getimage(&bk, 0, 0, 960, 864);
gameend_play(if_win, bk);
SaveScore(onetankscore, twotankscore, 2);
Sleep(200);
while (1)
{
if (GetAsyncKeyState(' ') < 0)
break;
}
break;
}
}
}
}
2p与1p相比主要是多了个对2p的操控,其他基本没变
结语
做这个小游戏前前后后花了差不多2个月,通过实际的操作是真真切切的体会到了做一个项目的辛苦,但也确实感到了乐趣,尤其是测试时各种神奇的bug虽然让人生气,但有时也让人发笑,看着编完之后10多MB的文件夹,我也是深刻感觉到了过去那些做FC游戏的大佬的厉害。这篇文章对代码也没太多讲解,也是希望大家能更多的靠自己思考解决问题(其实是因为太懒了),文章里提到的各种东西都是我们自己在网上仔细查了之后编出来的,这里我们直接给出了相应链接,省去了大家查询时间,但同时也希望大家能仔细思考,多多理解。最后,因为这是本人第一次发帖,没有经验,可能有一些遗漏,如果问题比较大,我后续会找时间更新。谢谢大家。
|