就是练C++而已的。
工具类
lag.h
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include
#pragma comment(lib,"winmm.lib") // 播放音频
using namespace std;
/*
功能:窗口居中
参数:hWnd-窗口句柄
*/
void myCenterWindow(HWND hWnd);
/*
功能:得到某范围内的随机整数
参数:min - 最小值
max - 最大值
返回:某范围内的随机整数
*/
int myRandom(int min, int max);
/*
功能:定时器
参数:interval - 延时间隔(毫秒)
id - 编号 (0-max)
返回:true-已到时,false-未到时
*/
bool myTimer(int interval, int id);
/*
功能:播放音频
参数:fileName - 音频文件
repeat - 是否循环播放(true-循环,false-不循环)
返回:无
*/
void myPlayAudio(const string& fileName, bool repeat = false);
/*
功能:判断某键是否被按下
参数:keyCode - 键值
返回:true-按下,false-未按下
*/
bool myKeyDown(int keyCode);
/*
功能:判断两个矩形是否相交
参数:x1 - 第一个矩形的左上角X坐标
y1 - 第一个矩形的左上角Y坐标
w1 - 第一个矩形的宽度
h1 - 第一个矩形的高度
x2 - 第二个矩形的左上角X坐标
y2 - 第二个矩形的左上角Y坐标
w2 - 第二个矩形的宽度
h2 - 第二个矩形的高度
返回:true-相交,false-不相交
*/
bool myRectIntersectRect(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2);
/*
功能:绘制透明图片
参数:dstX - 目的X坐标
dstY - 目的Y坐标
pSrcImg - 源图像指针
winWidth - 窗口宽度(判断图片位置是否超出窗口范围,不录则默认为0,表示该参数不用)
winHeight - 窗口高度(判断图片位置是否超出窗口范围,不录则默认为0,表示该参数不用)
返回:无
*/
void myDrawImage(int dstX, int dstY, IMAGE* pSrcImg, int winWidth = 0, int winHeight = 0);
/*
功能:绘制字符串
参数:text - 字符串内容
x - X坐标
y - Y坐标
返回:无
*/
void myDrawString(int x, int y, const string& text);
lag.cpp
#include "lag.h"
/*
功能:窗口居中
参数:hWnd-窗口句柄
*/
void myCenterWindow(HWND hWnd)
{
int screenWidth; // 屏幕宽度
int screenHeight; // 屏幕高度
RECT rect; // 矩形
// 得到屏幕尺寸
screenWidth = GetSystemMetrics(SM_CXSCREEN);
screenHeight = GetSystemMetrics(SM_CYSCREEN);
// 得到窗口尺寸
GetWindowRect(hWnd, &rect);
// 重新设置窗口尺寸
rect.left = (screenWidth - (rect.right - rect.left)) / 2;
rect.top = (screenHeight - (rect.bottom - rect.top)) / 3;
// 移动窗口到屏幕中间
SetWindowPos(hWnd, HWND_TOP, rect.left, rect.top, rect.right, rect.bottom, SWP_NOSIZE);
}
/*
功能:得到某范围内的随机整数
参数:min - 最小值
max - 最大值
返回:某范围内的随机整数
备注:公式:min + rand() % (max - min + 1)
原理:rand() % m => 返回[0-m)的随机数
*/
int myRandom(int min, int max)
{
// 生成随机种子(必须在原有毫秒时间的基础上再加随机值,否则在类似for循环中会出现同一种子值的现象)
srand((unsigned int)time(NULL) + (unsigned)rand());
return (int)(min + rand() % (max - min + 1));
}
/*
功能:定时器
参数:interval - 延时间隔(毫秒)
id - 编号 (0-max)
返回:true-已到时,false-未到时
*/
bool myTimer(int interval, int id)
{
// 静态vector数组(默认数组元素为5,值为0)
static vector vectorLastTimeForMyTimer(5, 0);
// 根据编号自动扩容
if (id < 0) { id = 0; }
if ((int)vectorLastTimeForMyTimer.size() <= id) { vectorLastTimeForMyTimer.resize(id + 1, 0); }
// 得到当前毫秒并判断是否到时
unsigned long long currentTime = GetTickCount64();
if (vectorLastTimeForMyTimer[id] == 0) // 未初始化呢
{
vectorLastTimeForMyTimer[id] = currentTime;
return false;
}
else
{
int addTime = (int)(currentTime - vectorLastTimeForMyTimer[id]);
if (addTime >= interval)
{
vectorLastTimeForMyTimer[id] = currentTime;
return true;
}
}
return false;
}
/*
功能:播放音频
参数:fileName - 音频文件
repeat - 是否循环播放(true-循环,false-不循环)
返回:无
*/
void myPlayAudio(const string& fileName, bool repeat)
{
string command = "play " + fileName;
if (repeat) { command += " repeat"; }
mciSendString(command.c_str(), 0, 0, 0);
}
/*
功能:判断某键是否被按下
参数:keyCode - 键值
返回:true-按下,false-未按下
*/
bool myKeyDown(int keyCode)
{
return (GetAsyncKeyState(keyCode) & 0x8000);
}
/*
功能:判断两个矩形是否相交
参数:x1 - 第一个矩形的左上角X坐标
y1 - 第一个矩形的左上角Y坐标
w1 - 第一个矩形的宽度
h1 - 第一个矩形的高度
x2 - 第二个矩形的左上角X坐标
y2 - 第二个矩形的左上角Y坐标
w2 - 第二个矩形的宽度
h2 - 第二个矩形的高度
返回:true-相交,false-不相交
*/
bool myRectIntersectRect(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2)
{
if (x1 > x2 + w2) { return false; }
if (x2 > x1 + w1) { return false; }
if (y1 > y2 + h2) { return false; }
if (y2 > y1 + h1) { return false; }
return true;
}
/*
功能:载入图片并过滤透明部分(做位运算)
参数:picture_x - 载入图片X坐标
picture_y - 载入图片Y坐标
picture - 载入图片
返回:无
*/
void myDrawImageAlpha(int picture_x, int picture_y, IMAGE* picture)
{
DWORD* dst = GetImageBuffer(); // GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带
DWORD* draw = GetImageBuffer();
DWORD* src = GetImageBuffer(picture); // 获取picture的显存指针
int picture_width = picture->getwidth(); // 获取picture的宽度,EASYX自带
int picture_height = picture->getheight(); // 获取picture的高度,EASYX自带
int graphWidth = getwidth(); // 获取绘图区的宽度,EASYX自带
int graphHeight = getheight(); // 获取绘图区的高度,EASYX自带
int dstX = 0; // 在显存里像素的角标
// 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算
for (int iy = 0; iy < picture_height; iy++)
{
for (int ix = 0; ix < picture_width; ix++)
{
int srcX = ix + iy * picture_width; // 在显存里像素的角标
int sa = ((src[srcX] & 0xff000000) >> 24); // 0xAArrggbb;AA是透明度
int sr = ((src[srcX] & 0xff0000) >> 16); // 获取RGB里的R
int sg = ((src[srcX] & 0xff00) >> 8); // G
int sb = src[srcX] & 0xff; // B
if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight)
{
dstX = (ix + picture_x) + (iy + picture_y) * graphWidth; // 在显存里像素的角标
int dr = ((dst[dstX] & 0xff0000) >> 16);
int dg = ((dst[dstX] & 0xff00) >> 8);
int db = dst[dstX] & 0xff;
draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16) // 公式: Cp=αp*FP+(1-αp)*BP ; αp=sa/255 , FP=sr , BP=dr
| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8) // αp=sa/255 , FP=sg , BP=dg
| (sb * sa / 255 + db * (255 - sa) / 255); // αp=sa/255 , FP=sb , BP=db
}
}
}
}
/*
功能:绘制透明图片
参数:dstX - 目的X坐标
dstY - 目的Y坐标
pSrcImg - 源图像指针
winWidth - 窗口宽度(判断图片位置是否超出窗口范围,不录则默认为0,表示该参数不用)
winHeight - 窗口高度(判断图片位置是否超出窗口范围,不录则默认为0,表示该参数不用)
返回:无
*/
void myDrawImage(int dstX, int dstY, IMAGE* pSrcImg, int winWidth, int winHeight)
{
IMAGE imgTmp;
int newImgX = 0;
int newImgY = 0;
int newImgWidth = pSrcImg->getwidth();
int newImgHeight = pSrcImg->getheight();
int flag = 0;
// 图片完全不在窗口中
if (dstX <= -pSrcImg->getwidth()) { return; }
if (winWidth > 0 && dstX >= winWidth) { return; }
if (dstY <= -pSrcImg->getheight()) { return; }
if (winHeight > 0 && dstY >= winHeight) { return; }
// 处理X坐标
if (dstX < 0) // 左边界
{
newImgX = -dstX;
newImgWidth = pSrcImg->getwidth() + dstX;
dstX = 0;
flag = 1;
}
else if (winWidth > 0 && dstX > winWidth - pSrcImg->getwidth()) // 右边界
{
newImgWidth = winWidth - dstX;
flag = 1;
}
// 处理Y坐标
if (dstY < 0) // 上边界
{
newImgY = -dstY;
newImgHeight = pSrcImg->getheight() + dstY;
dstY = 0;
flag = 1;
}
else if (winHeight > 0 && dstY > winHeight - pSrcImg->getheight()) // 下边界
{
newImgHeight = winHeight - dstY;
flag = 1;
}
// 处理图片变动
if (flag == 1)
{
SetWorkingImage(pSrcImg); // 设定pSrcImg为当前的绘图设备
getimage(&imgTmp, newImgX, newImgY, newImgWidth, newImgHeight); // 从当前绘图设备获取图像(即截取pSrcImg的要显示部分内容放到imgTmp中)
SetWorkingImage(); // 恢复默认绘图设备
pSrcImg = &imgTmp;
}
// 开始输出透明位图
myDrawImageAlpha(dstX, dstY, pSrcImg);
}
/*
功能:绘制字符串
参数:text - 字符串内容
x - X坐标
y - Y坐标
返回:无
*/
void myDrawString(int x, int y, const string& text)
{
outtextxy(x, y, text.c_str());
}
/*
功能:绘制血条
参数:x - 血条X坐标
y - 血条Y坐标
width - 血条宽度
height - 血条高度
percent - 血条比例
返回:无
*/
void myDrawBloodBar(int x, int y, int width, int height, float percent);
/*
功能:绘制血条
参数:x - 血条X坐标
y - 血条Y坐标
width - 血条宽度
height - 血条高度
percent - 血条比例
返回:无
*/
void myDrawBloodBar(int x, int y, int width, int height, float percent)
{
// 记录原来的状态,以便后面恢复
COLORREF fillColor = getfillcolor();
COLORREF getColor = getcolor();
if (percent < 0) { percent = 0.0; }
setfillcolor(YELLOW);
solidrectangle(x, y, x + width, y + height);
setfillcolor(RED);
solidrectangle(x, y, (int)(x + width * percent), y + height);
setcolor(WHITE);
rectangle(x, y, x + width, y + height);
// 恢复原来的状态
setfillcolor(fillColor);
setcolor(getColor);
}
方块类
Block.h
#pragma once
#include "lag.h"
// 方块类
class Block
{
private:
IMAGE imgWall; // 墙块图片
IMAGE imgIron; // 铁块图片
IMAGE imgHome; // 老巢图片
int(*map)[26]; // 当前地图
public:
// 构造函数
Block();
// 绘制方块
void draw();
};
Block.cpp
#include "Block.h"
#include "GameMap.h"
#include "define.h"
// 构造函数
Block::Block()
{
// 加载图片
loadimage(&imgWall, "./resources/image/wall.gif");
loadimage(&imgIron, "./resources/image/iron.gif");
loadimage(&imgHome, "./resources/image/home.jpg");
// 得到当前地图
map = GameMap::getMap();
}
// 绘制方块
void Block::draw()
{
// 绘制墙块与铁块
for (int i = 0; i < 26; i++)
{
for (int j = 0; j < 26; j++)
{
int value = map[i][j];
if (value > 0)
{
if (value == WALL) // 墙块
{
putimage(j * BLOCK_SIZE, i * BLOCK_SIZE, &imgWall);
}
else if (value == IRON) // 铁块
{
putimage(j * BLOCK_SIZE, i * BLOCK_SIZE, &imgIron);
}
}
}
}
// 绘制老巢
myDrawImage(12 * BLOCK_SIZE, 24 * BLOCK_SIZE, &imgHome);
}
爆炸类
Bomb.h
#pragma once
#include "define.h"
#include "lag.h"
// 爆炸类
class Bomb
{
private:
static IMAGE* imgBombs[5]; // 爆炸图片
public:
int x = 0; // 爆炸中心点X坐标
int y = 0; // 爆炸中心点Y坐标
int frameIndex = -1; // 爆炸图片帧数
int maxFrame = 5; // 最大图片帧数
int size = BLOCK_SIZE * 2; // 爆炸尺寸
int status = BOMB_STATUS_FREE; // 爆炸状态
public:
// 构造函数
Bomb();
// 绘制爆炸
void draw();
};
Bomb.cpp
#include "Bomb.h"
IMAGE* Bomb::imgBombs[5] = {NULL}; // 初始化爆炸图片
// 构造函数
Bomb::Bomb()
{
// 加载图片
if (imgBombs[0] == NULL)
{
IMAGE imgTmp;
loadimage(&imgTmp, "./resources/image/bomb.png", size * 5, size);
SetWorkingImage(&imgTmp); // 设定当前绘图目标为imgTmp
for (int i = 0; i < 5; i++)
{
imgBombs[i] = new IMAGE;
getimage(imgBombs[i], i * size, 0, size, size);
}
SetWorkingImage(); // 设置绘图目标为绘图窗口
}
}
// 绘制爆炸
void Bomb::draw()
{
myDrawImage(x - size / 2 + 6, y - size / 2 + 6, imgBombs[frameIndex],GAME_WIDTH,GAME_HEIGHT); // 得考虑子弹的尺寸
}
子弹类
Bullet.h
#pragma once
#include "lag.h"
#include "define.h"
// 子弹类
class Bullet
{
private:
static IMAGE* imgBullets[4]; // 子弹图片
public:
int x = 0; // X坐标
int y = 0; // Y坐标
int direction = 0; // 方向
int speed = 6; // 速度
int owner = 0; // 拥有者
int status = BULLET_STATUS_FREE; // 状态
public:
// 构造函数
Bullet();
// 子弹绘制
void draw();
// 子弹运行
void run();
};
Bullet.cpp
#include "Bullet.h"
IMAGE* Bullet::imgBullets[4] = {NULL}; // 初始化子弹图片
// 构造函数
Bullet::Bullet()
{
// 加载子弹图片
if (imgBullets[0] == NULL)
{
IMAGE imgTmp;
loadimage(&imgTmp, "./resources/image/bullet.png", BULLET_SIZE * 4, BULLET_SIZE);
SetWorkingImage(&imgTmp); // 设定当前绘图目标为imgTmp
for (int i = 0; i < 4; i++)
{
imgBullets[i] = new IMAGE;
getimage(imgBullets[i], i * BULLET_SIZE, 0, BULLET_SIZE, BULLET_SIZE);
}
SetWorkingImage(); // 设置绘图目标为绘图窗口
}
}
// 子弹绘制
void Bullet::draw()
{
myDrawImage(this->x, this->y, imgBullets[this->direction], GAME_WIDTH, GAME_HEIGHT);
}
// 子弹运行
void Bullet::run()
{
switch (this->direction)
{
case TANK_DIRECTION_UP:
if (this->y - this->speed >= 0)
{
this->y -= this->speed;
}
else
{
this->status = BULLET_STATUS_FREE;
}
break;
case TANK_DIRECTION_DOWN:
if (this->y + BULLET_SIZE + this->speed <= GAME_HEIGHT)
{
this->y += this->speed;
}
else
{
this->status = BULLET_STATUS_FREE;
}
break;
case TANK_DIRECTION_LEFT:
if (this->x >= this->speed)
{
this->x -= this->speed;
}
else
{
this->status = BULLET_STATUS_FREE;
}
break;
case TANK_DIRECTION_RIGHT:
if (this->x + BLOCK_SIZE + this->speed <= GAME_WIDTH)
{
this->x += this->speed;
}
else
{
this->status = BULLET_STATUS_FREE;
}
break;
}
}
宏定义
define.h
#pragma once
// 主窗口宏定义
#define TITLE "坦克大战" // 窗口标题
#define WIN_WIDTH 570 // 窗口宽度
#define WIN_HEIGHT 468 // 窗口高度
#define GAME_WIDTH 468 // 游戏宽度
#define GAME_HEIGHT 468 // 游戏高度
#define INTERVAL_REFRESH 10 // 界面刷新间隔
#define TIMERID_REFRESH 0 // 界面刷新ID
#define GAME_STATUS_RUN 0 // 游戏状态(运行)
#define GAME_STATUS_WIN 1 // 游戏状态(胜利)
#define GAME_STATUS_OVER 2 // 游戏状态(失败)
#define INTERVAL_SCORE 500 // 分数刷新间隔
#define TIMERID_SCORE 8 // 分数刷新ID
// 块宏定义
#define BLANK 0 // 空地
#define WALL 1 // 墙块
#define IRON 2 // 铁块
#define HOME 9 // 老巢
#define BLOCK_SIZE 18 // 方块尺寸
// 坦克宏定义
#define TANK_OWNER_HERO 8 // 我方坦克
#define TANK_OWNER_ENEMY 7 // 敌方坦克
#define TANK_DIRECTION_UP 0 // 坦克方向(向上)
#define TANK_DIRECTION_LEFT 1 // 坦克方向(向左)
#define TANK_DIRECTION_DOWN 2 // 坦克方向(向下)
#define TANK_DIRECTION_RIGHT 3 // 坦克方向(向右)
#define TANK_STATUS_FREE 0 // 坦克状态(空闲)
#define TANK_STATUS_RUN 1 // 坦克状态(运行)
#define INTERVAL_TANKMOVE 10 // 坦克移动进程刷新间隔
#define TIMERID_TANKMOVE 4 // 坦克移动进程刷新ID
#define INTERVAL_CREATEENEMY 5000 // 敌方坦克投放刷新间隔
#define TIMERID_CREATEENEMY 5 // 敌方坦克投放刷新ID
#define INTERVAL_MOVEENEMY 300 // 敌方坦克移动刷新间隔
#define TIMERID_MOVEENEMY 6 // 敌方坦克移动刷新ID
// 子弹宏定义
#define INTERVAL_BULLET_SHOOT 500 // 子弹射击间隔
#define TIMERID_BULLET_SHOOT 1 // 子弹射击ID
#define INTERVAL_BULLET_RUN 10 // 子弹运行间隔
#define TIMERID_BULLET_RUN 2 // 子弹运行ID
#define BULLET_STATUS_FREE 0 // 子弹状态(空闲)
#define BULLET_STATUS_RUN 1 // 子弹状态(运行)
#define BULLET_SIZE 9 // 子弹尺寸
// 爆炸宏定义
#define INTERVAL_BOMB 50 // 爆炸刷新间隔
#define TIMERID_BOMB 3 // 爆炸刷新ID
#define BOMB_STATUS_FREE 0 // 爆炸状态(空闲)
#define BOMB_STATUS_RUN 1 // 爆炸状态(运行)
// 星星宏定义
#define INTERVAL_STAR 100 // 星星刷新间隔
#define TIMERID_STAR 7 // 星星刷新ID
#define STAR_STATUS_FREE 0 // 星星状态(空闲)
#define STAR_STATUS_RUN 1 // 星星状态(运行)
游戏地图类
GameMap.h
#pragma once
#define LEVEL_TOTAL 2 // 总关卡数
// 游戏地图
class GameMap
{
private:
static int maps[LEVEL_TOTAL][26][26]; // 各关地图
static int level; // 当前关数
static int enemyTankNum[LEVEL_TOTAL]; // 当前关敌方坦克数
public:
// 设置关数
static void setLevel(int level);
// 得到最大关数
static int getMaxLevel();
// 得到当前关敌方坦克数
static int getEnemyTankNum(int level);
// 得到当前关地图
static int(*getMap())[26];
};
GameMap.cpp
#include "GameMap.h"
// 各关地图初始化
int GameMap::maps[LEVEL_TOTAL][26][26] =
{
// 第1关地图
{
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,2,2,1,1,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,2,2,1,1,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
{1,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,1},
{2,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,2,2},
{0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0},
{0,0,0,0,0,0,0,0,0,0,0,1,9,9,1,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,1,9,9,1,0,0,0,0,0,0,0,0,0,0,0}
},
// 第2关地图
{
{0,0,0,0,0,0,2,2,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,2,2,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0},
{0,0,1,1,0,0,2,2,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,2,2,0,0,0,0,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,1,2,2,1,1,0,0},
{0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,1,0,0,1,1,2,2,1,1,0,0},
{0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0},
{0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0},
{0,0,0,0,0,0,1,1,0,0,0,0,2,2,0,0,0,0,1,1,0,0,1,1,2,2},
{0,0,0,0,0,0,1,1,0,0,0,0,2,2,0,0,0,0,1,1,0,0,1,1,2,2},
{0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,2,2,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,2,2,0,0,0,0,0,0,0,0},
{0,0,1,1,1,1,1,1,0,0,0,0,0,0,2,2,0,0,0,0,0,0,1,1,0,0},
{0,0,1,1,1,1,1,1,0,0,0,0,0,0,2,2,0,0,0,0,0,0,1,1,0,0},
{0,0,0,0,0,0,2,2,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
{0,0,0,0,0,0,2,2,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0},
{2,2,1,1,0,0,2,2,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0},
{2,2,1,1,0,0,2,2,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,2,2,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,1,1,2,2,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},
{0,0,1,1,0,0,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},
{0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,1,1,0,0,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,0,1,9,9,1,0,0,0,1,1,1,1,1,1,0,0},
{0,0,1,1,0,0,1,1,0,0,0,1,9,9,1,0,0,0,1,1,1,1,1,1,0,0}
}
// 其他关地图...
};
// 当前关卡初始化
int GameMap::level = 0;
// 当前关敌方坦克数初始化
int GameMap::enemyTankNum[LEVEL_TOTAL] = { 16,20 };
// 设置关数
void GameMap::setLevel(int level)
{
GameMap::level = level;
}
// 得到最大关数
int GameMap::getMaxLevel()
{
return LEVEL_TOTAL;
}
// 得到当前关敌方坦克数
int GameMap::getEnemyTankNum(int level)
{
return GameMap::enemyTankNum[level];
}
// 得到当前关地图
int(*GameMap::getMap())[26]
{
return GameMap::maps[GameMap::level];
}
星星类
Star.h
#pragma once
#include "define.h"
#include "lag.h"
// 星星类
class Star
{
private:
static IMAGE* imgStars[4]; // 星星图片
unsigned long long lastTime; // 上次时间
public:
int row = 0; // 行坐标
int column = 0; // 列坐标
int status = STAR_STATUS_FREE; // 星星状态
int frameIndex = -1; // 星星图片帧数
int maxFrame = 4; // 星星图片帧数
int size = BLOCK_SIZE * 2; // 星星尺寸
public:
// 构造函数
Star();
// 绘制星星
void draw();
};
Star.cpp
#include "Star.h"
IMAGE* Star::imgStars[4] = {NULL};
// 构造函数
Star::Star()
{
// 加载图片
if (imgStars[0] == NULL)
{
IMAGE imgTmp;
loadimage(&imgTmp, "./resources/image/star.png", size * 4, size);
SetWorkingImage(&imgTmp); // 设定当前绘图目标为imgTmp
for (int i = 0; i < 4; i++)
{
imgStars[i] = new IMAGE;
getimage(imgStars[i], i * size, 0, size, size);
}
SetWorkingImage(); // 设置绘图目标为绘图窗口
}
// 计时开始
this->lastTime = GetTickCount64();
}
// 绘制星星
void Star::draw()
{
myDrawImage(column * BLOCK_SIZE,row * BLOCK_SIZE, imgStars[frameIndex]);
}
坦克类
Tank.h
#pragma once
#include "lag.h"
#include "Bullet.h"
// 坦克类
class Tank
{
private:
int owner; // 坦克拥有者
int(*map)[26]; // 关卡地图
static IMAGE* imgHero[4][4][2]; // 我方坦克图片([装甲][方向][履带])
static IMAGE* imgEnemy[4][4][2]; // 敌方坦克图片([装甲][方向][履带])
vector bulletPool; // 子弹池
unsigned long long lastTime; // 上次时间
public:
int x; // 坦克左上角X坐标
int y; // 坦克左上角Y坐标
int row; // 坦克所在行
int column; // 坦克所在列
int oldRow; // 坦克上次所在行
int oldColumn; // 坦克上次所在列
int direction; // 坦克方向
int speed = 2; // 坦克速度
int originalArmor = 0; // 原始装甲
int armor = 0; // 当前装甲(共4层)
int status = TANK_STATUS_FREE; // 坦克状态
bool track = false; // 履带切换
private:
// 坦克是否可以移动
bool moveValid(int direction);
public:
// 有参构造函数
Tank(int tankOwner, int tankRow, int tankColumn, int tankDirection);
// 坦克绘制
void draw();
// 坦克移动
bool move(int direction);
// 坦克射击
void shoot();
// 坦克坐标映射到地图
void toMap();
// 坦克重置
void reset();
// 得到子弹池
vector& getBulletPool();
};
Tank.cpp
#include "Tank.h"
#include "GameMap.h"
#include "define.h"
IMAGE* Tank::imgHero[4][4][2] = {NULL}; // 初始化我方坦克图片
IMAGE* Tank::imgEnemy[4][4][2] = {NULL}; // 初始化敌方坦克图片
// 有参构造函数
Tank::Tank(int owner, int row, int column, int direction)
{
// 参数初始化
this->owner = owner;
this->row = row;
this->column = column;
this->oldRow = this->row;
this->oldColumn = this->column;
this->x = this->column * BLOCK_SIZE;
this->y = this->row * BLOCK_SIZE;
this->direction = direction;
this->map = GameMap::getMap();
// 加载敌我双方坦克图片(图片每一行装甲不同,这里没用装甲)
if (imgHero[0][0][0] == NULL)
{
// 加载敌我坦克图片
IMAGE imgTmp;
loadimage(&imgTmp, "./resources/image/tank.png", BLOCK_SIZE * 16, BLOCK_SIZE * 16); // 加载时扩大到合适尺寸,剪裁时就正好大小了
SetWorkingImage(&imgTmp); // 切换到绘图工作区
for (int ar = 0; ar < 4; ar++)
{
for (int dir = 0; dir < 4; dir++)
{
for (int tr = 0; tr < 2; tr++)
{
// 我方坦克
imgHero[ar][dir][tr] = new IMAGE;
getimage(imgHero[ar][dir][tr], dir * BLOCK_SIZE * 4 + tr * BLOCK_SIZE * 2 - 1, ar * BLOCK_SIZE * 2, BLOCK_SIZE * 2, BLOCK_SIZE * 2);
// 敌方坦克
imgEnemy[ar][dir][tr] = new IMAGE;
getimage(imgEnemy[ar][dir][tr], dir * BLOCK_SIZE * 4 + tr * BLOCK_SIZE * 2 - 1, BLOCK_SIZE * 8 + ar * BLOCK_SIZE * 2, BLOCK_SIZE * 2, BLOCK_SIZE * 2);
}
}
}
SetWorkingImage(); // 切换回窗口工作区
}
// 计时开始
this->lastTime = GetTickCount64();
}
// 坦克绘制
void Tank::draw()
{
// 绘制我方坦克
if (this->owner == TANK_OWNER_HERO && this->status == TANK_STATUS_RUN)
{
myDrawImage(this->x, this->y, imgHero[this->armor][this->direction][this->track]);
}
// 绘制敌方坦克
if (this->owner == TANK_OWNER_ENEMY && this->status == TANK_STATUS_RUN)
{
myDrawImage(this->x, this->y, imgEnemy[this->armor][this->direction][this->track]);
}
}
// 坦克是否可以移动
bool Tank::moveValid(int direction)
{
switch (direction)
{
case TANK_DIRECTION_UP:
if (row == 0) { return false; }
if (map[row - 1][column] > 0) { return false; }
if (map[row - 1][column + 1] > 0) { return false; }
break;
case TANK_DIRECTION_DOWN:
if (row == 24) { return false; }
if (map[row + 2][column] > 0) { return false; }
if (map[row + 2][column + 1] > 0) { return false; }
break;
case TANK_DIRECTION_LEFT:
if (column == 0) { return false; }
if (map[row][column - 1] > 0) { return false; }
if (map[row + 1][column - 1] > 0) { return false; }
break;
case TANK_DIRECTION_RIGHT:
if (column == 24) { return false; }
if (map[row][column + 2] > 0) { return false; }
if (map[row + 1][column + 2] > 0) { return false; }
break;
}
return true;
}
// 坦克移动
bool Tank::move(int direction)
{
// 如果坦克移动进程未完成则禁止再次移动
if (this->oldRow != this->row) { return false; }
if (this->oldColumn != this->column) { return false; }
if (this->direction == direction) // 方向相同则前进
{
// 判断是否可以移动
if (!moveValid(direction)) { return false; }
// 开始移动
switch (direction)
{
case TANK_DIRECTION_UP:
map[row + 1][column] = 0;
map[row + 1][column + 1] = 0;
map[row - 1][column] = owner;
map[row - 1][column + 1] = owner;
oldRow = row;
row--;
break;
case TANK_DIRECTION_DOWN:
map[row][column] = 0;
map[row][column + 1] = 0;
map[row + 2][column] = owner;
map[row + 2][column + 1] = owner;
oldRow = row;
row++;
break;
case TANK_DIRECTION_LEFT:
map[row][column + 1] = 0;
map[row + 1][column + 1] = 0;
map[row][column - 1] = owner;
map[row + 1][column - 1] = owner;
oldColumn = column;
column--;
break;
case TANK_DIRECTION_RIGHT:
map[row][column] = 0;
map[row + 1][column] = 0;
map[row][column + 2] = owner;
map[row + 1][column + 2] = owner;
oldColumn = column;
column++;
break;
}
}
else // 方向不同,仅调整方向不前进
{
this->direction = direction;
}
return true;
}
// 坦克射击
void Tank::shoot()
{
// 射击冷却未到时间禁止发射
unsigned long long currentTime = GetTickCount64();
int addTime = (int)(currentTime - this->lastTime);
if (addTime >= INTERVAL_BULLET_SHOOT)
{
this->lastTime = currentTime;
}
else
{
return;
}
// 在子弹池中寻找空闲的子弹
Bullet *bullet = nullptr;
int len = this->bulletPool.size();
for (int i = 0; i < len; i++)
{
if (this->bulletPool[i].status == BULLET_STATUS_FREE)
{
bullet = &this->bulletPool[i];
break;
}
}
if (bullet == nullptr) // 没有就增加一个
{
Bullet newBullet;
newBullet.owner = this->owner;
this->bulletPool.push_back(newBullet); // 浅拷贝
bullet = &bulletPool[len];
}
// 设置子弹位置
bullet->direction = this->direction;
switch (this->direction)
{
case TANK_DIRECTION_UP:
bullet->x = this->column * BLOCK_SIZE + BLOCK_SIZE - BULLET_SIZE / 2;
bullet->y = this->row * BLOCK_SIZE - BULLET_SIZE - 4;
break;
case TANK_DIRECTION_DOWN:
bullet->x = this->column * BLOCK_SIZE + BLOCK_SIZE - BULLET_SIZE / 2;
bullet->y = this->row * BLOCK_SIZE + 2 * BLOCK_SIZE + 4;
break;
case TANK_DIRECTION_LEFT:
bullet->x = this->column * BLOCK_SIZE - BULLET_SIZE - 4;
bullet->y = this->row * BLOCK_SIZE + BLOCK_SIZE - BULLET_SIZE / 2;
break;
case TANK_DIRECTION_RIGHT:
bullet->x = this->column * BLOCK_SIZE + 2 * BLOCK_SIZE + 4;
bullet->y = this->row * BLOCK_SIZE + BLOCK_SIZE - BULLET_SIZE / 2;
break;
}
// 设置子弹状态
bullet->status = BULLET_STATUS_RUN;
// 我方坦克发出射击声音
if (owner == TANK_OWNER_HERO){myPlayAudio("./resources/audio/shoot.mp3");}
}
// 坦克坐标映射到地图
void Tank::toMap()
{
map[row][column] = owner;
map[row][column + 1] = owner;
map[row + 1][column] = owner;
map[row + 1][column + 1] = owner;
}
// 坦克重置
void Tank::reset()
{
map[row][column] = 0;
map[row][column + 1] = 0;
map[row + 1][column] = 0;
map[row + 1][column + 1] = 0;
if (owner == TANK_OWNER_HERO)
{
this->row = 24;
this->column = 8;
this->oldRow = this->row;
this->oldColumn = this->column;
this->x = this->column * BLOCK_SIZE;
this->y = this->row * BLOCK_SIZE;
this->direction = TANK_DIRECTION_UP;
this->armor = 3;
}
else
{
this->row = 0;
this->oldRow = 0;
this->column = 0;
this->oldColumn = 0;
this->x = 0;
this->y = 0;
}
this->status = TANK_STATUS_FREE;
}
// 得到子弹池
vector& Tank::getBulletPool()
{
return this->bulletPool;
}
我方坦克类
Hero.h
#pragma once
#include "Tank.h"
// 我方坦克类
class Hero : public Tank
{
public:
// 构造函数
Hero(int tankRow, int tankColumn, int tankDirection);
};
Hero.cpp
#include "Hero.h"
#include "define.h"
// 构造函数
Hero::Hero(int tankRow, int tankColumn, int tankDirection) : Tank(TANK_OWNER_HERO, tankRow, tankColumn, tankDirection) {}
敌方坦克类
Enemy.h
#pragma once
#include "Tank.h"
// 敌方坦克类
class Enemy : public Tank
{
public:
int target = HOME; // 坦克射击的目标(我方坦克,老巢)
public:
// 构造函数
Enemy(int tankRow, int tankColumn, int tankDirection);
};
Enemy.cpp
#include "Enemy.h"
// 构造函数
Enemy::Enemy(int tankRow, int tankColumn, int tankDirection) : Tank::Tank(TANK_OWNER_ENEMY, tankRow, tankColumn, tankDirection){}
main.cpp
#include "lag.h"
#include "define.h"
#include "GameMap.h"
#include "Block.h"
#include "Hero.h"
#include "Enemy.h"
#include "Bullet.h"
#include "Bomb.h"
#include "Star.h"
// 项目结构
struct _stu_project
{
int gameStatus = GAME_STATUS_RUN; // 游戏状态
bool refreshFlag = false; // 刷新标识
int level = 0; // 游戏关卡
int enemyMaxNum = 0; // 敌方坦克最大数量
int enemyCreateNum = 0; // 敌方坦克投放数量
int enemyDeadNum = 0; // 敌方坦克死亡数量
int enemyArmorDeadNum[4] = {0,0,0,0}; // 敌方不同装甲坦克死亡数量
IMAGE imgLogo; // Logo图片
IMAGE imgLevel; // 关卡图片
IMAGE imgScore; // 分数图片
IMAGE imgSuccess; // 游戏成功图片
IMAGE imgFailure; // 游戏失败图片
int(*map)[26] = nullptr; // 关卡地图
} stu_project;
// 子弹所在行列结构
struct _stu_bullet_pos
{
int row1;
int col1;
int row2;
int col2;
};
// 方块类
Block block;
// 我方坦克类
Hero hero(24, 8, TANK_DIRECTION_UP);
// 我方子弹池
vector& heroBulletPool = hero.getBulletPool();
// 敌方坦克类
vector enemyPool;
// 爆炸池
vector bombPool;
// 星星池
vector starPool;
// 函数声明
void createWindow();
void welcome();
void loadResources();
void initGame();
void paint();
void run();
void keyEvent();
void mouseEvent();
void starCreate();
void starAdd(int row, int column);
void enemyTankCreate(int row, int column);
void enemyTankMove();
void enemyTankShoot();
int enemyTankAI(Enemy& enemy);
void bombAdd(int x, int y);
void collide();
void doGame();
void newGame();
void showScore();
void getBulletPos(struct _stu_bullet_pos* pos, int x, int y, int direction);
// 坦克大战
int main()
{
// 创建窗口
createWindow();
// 显示封面
welcome();
// 开始游戏
newGame();
// 暂停一下
system("pause");
// 关闭窗口
closegraph();
return 0;
}
// 创建窗口
void createWindow()
{
// 创建并得到窗口句柄
HWND hWnd = initgraph(WIN_WIDTH, WIN_HEIGHT);
// 修改标题
SetWindowText(hWnd, TITLE);
// 居中显示
myCenterWindow(hWnd);
}
// 加载资源
void loadResources()
{
// 加载游戏成功图片
loadimage(&stu_project.imgSuccess, "./resources/image/success.png");
// 加载游戏失败图片
loadimage(&stu_project.imgFailure, "./resources/image/failure.png");
// 加载关卡图片
loadimage(&stu_project.imgLevel, "./resources/image/level.png");
// 加载Logo图片
loadimage(&stu_project.imgLogo, "./resources/image/logo.png");
// 加载分数图片
loadimage(&stu_project.imgScore, "./resources/image/score.jpg");
}
// 显示封面
void welcome()
{
// 显示封面
IMAGE imgWelcome;
loadimage(&imgWelcome, "./resources/image/welcome.gif");
putimage(0, 0, &imgWelcome);
// 加载资源
loadResources();
// 暂停一下
system("pause");
}
// 初始化游戏
void initGame()
{
// 项目参数初始化
stu_project.gameStatus = GAME_STATUS_RUN;
stu_project.refreshFlag = false;
stu_project.enemyMaxNum = GameMap::getEnemyTankNum(stu_project.level);
stu_project.enemyCreateNum = 0;
stu_project.enemyDeadNum = 0;
stu_project.map = GameMap::getMap();
for (int i = 0; i < 4; i++){stu_project.enemyArmorDeadNum[i] = 0;}
// 设置游戏关卡
GameMap::setLevel(stu_project.level);
// 我方坦克初始化
hero.reset();
hero.status = TANK_STATUS_RUN;
hero.toMap();
// 敌方坦克池初始化10辆坦克
int lenEnemyPool = enemyPool.size();
if (lenEnemyPool == 0)
{
for (int i = 0; i < 10; i++)
{
Enemy enemy(0,0,TANK_DIRECTION_DOWN);
enemyPool.push_back(enemy);
}
}
else
{
for (int i = 0; i < lenEnemyPool; i++)
{
enemyPool[i].reset();
vector& enemyBulletPool = enemyPool[i].getBulletPool();
int lenEnemyBulletPool = enemyBulletPool.size();
for (int j = 0; j < lenEnemyBulletPool; j++) { enemyBulletPool[j].status = BULLET_STATUS_FREE; }
}
}
// 星星初始化
int lenStarPool = starPool.size();
if (lenStarPool == 0)
{
for (int i = 0; i < 3; i++)
{
Star star;
starPool.push_back(star);
}
}
else
{
for (int i = 0; i < lenStarPool; i++) { starPool[i].status = STAR_STATUS_FREE; }
}
// 爆炸初始化
int lenBombPool = bombPool.size();
for (int i = 0; i < lenBombPool; i++) { bombPool[i].status = BOMB_STATUS_FREE;}
}
// 绘制窗口
void paint()
{
// 开启双缓冲机制,防止闪烁
BeginBatchDraw();
// 绘制游戏区域
setcolor(BLACK);
cleardevice();
setfillcolor(LIGHTGRAY);
fillrectangle(GAME_WIDTH, -2, WIN_WIDTH, WIN_HEIGHT + 2);
// 绘制分数
settextstyle(20, 0, "微软雅黑");
settextcolor(YELLOW);
setbkmode(TRANSPARENT);
myDrawString(GAME_WIDTH + 20, 6, "总数:" + to_string(stu_project.enemyMaxNum));
myDrawString(GAME_WIDTH + 20, 26, "死亡:" + to_string(stu_project.enemyDeadNum));
myDrawString(GAME_WIDTH + 20, 46, "剩余:" + to_string(stu_project.enemyMaxNum - stu_project.enemyDeadNum));
int notCreateNum = stu_project.enemyMaxNum - stu_project.enemyCreateNum;
if (notCreateNum > 0)
{
int logoRow = notCreateNum / 2;
if (notCreateNum % 2 != 0) { logoRow++; }
int logoCount = 0;
for (int i = 0; i < logoRow; i++)
{
for (int j = 0; j < 2; j++)
{
if (logoCount >= notCreateNum) { break; }
myDrawImage(GAME_WIDTH + 22 + j * (20 + 14), 80 + i * (16 + 4), &stu_project.imgLogo,WIN_WIDTH,WIN_HEIGHT);
logoCount++;
}
}
}
myDrawImage(GAME_WIDTH + 20, 330, &stu_project.imgLevel);
settextcolor(RED);
myDrawString(GAME_WIDTH + 20, 380, "关数:" + to_string(stu_project.level + 1));
settextcolor(WHITE);
myDrawString(GAME_WIDTH + 20, 420, "作者:Lag");
// 绘制地图
block.draw();
// 绘制我方坦克
hero.draw();
// 绘制我方子弹
int lenHeroBulletPool = heroBulletPool.size();
for (int i = 0; i < lenHeroBulletPool; i++)
{
if (heroBulletPool[i].status == BULLET_STATUS_RUN)
{
heroBulletPool[i].draw();
}
}
// 绘制敌方坦克、子弹
int lenEnemyPool = enemyPool.size();
for (int i = 0; i < lenEnemyPool; i++)
{
if (enemyPool[i].status == TANK_STATUS_RUN) { enemyPool[i].draw(); }
vector& enemyBulletPool = enemyPool[i].getBulletPool();
int lenEnemyBulletPool = enemyBulletPool.size();
for (int j = 0; j < lenEnemyBulletPool; j++)
{
if (enemyBulletPool[j].status == BULLET_STATUS_RUN){enemyBulletPool[j].draw();}
}
}
// 绘制爆炸
int lenBombPool = bombPool.size();
for (int i = 0; i < lenBombPool; i++)
{
if (bombPool[i].status == BOMB_STATUS_RUN)
{
bombPool[i].draw();
}
}
// 绘制星星
int lenStarPool = starPool.size();
for (int i = 0; i < lenStarPool; i++)
{
if (starPool[i].status == STAR_STATUS_RUN)
{
starPool[i].draw();
}
}
// 结束双缓冲机制
EndBatchDraw();
}
// 向星星池增加
void starAdd(int row, int column)
{
// 流星雨
myPlayAudio("./resources/audio/star.mp3");
// 查找空闲的星星
int len = starPool.size();
for (int i = 0; i < len; i++)
{
if (starPool[i].status == STAR_STATUS_FREE)
{
starPool[i].row = row;
starPool[i].column = column;
starPool[i].frameIndex = 0;
starPool[i].status = STAR_STATUS_RUN;
break;
}
}
}
// 星星创建(在坦克创建前先创建星星)
void starCreate()
{
// 创建坦克标识
bool createFlag = false;
if (stu_project.enemyCreateNum == 0 || myTimer(INTERVAL_CREATEENEMY, TIMERID_CREATEENEMY)) { createFlag = true; }
if (createFlag)
{
// 判断投放地点是否为空
int createPos[3] = { -1,-1,-1 };
int createPosNum = 0;
if (stu_project.map[0][0] == BLANK && stu_project.map[0][1] == BLANK && stu_project.map[1][0] == BLANK && stu_project.map[1][1] == BLANK) // 判断左上角位置是否可以投放
{
createPos[createPosNum] = 0;
createPosNum++;
}
if (stu_project.map[0][12] == BLANK && stu_project.map[0][13] == BLANK && stu_project.map[1][12] == BLANK && stu_project.map[1][13] == BLANK) // 判断中间位置是否可以投放
{
createPos[createPosNum] = 12;
createPosNum++;
}
if (stu_project.map[0][24] == BLANK && stu_project.map[0][25] == BLANK && stu_project.map[1][24] == BLANK && stu_project.map[1][25] == BLANK) // 判断右上角位置是否可以投放
{
createPos[createPosNum] = 24;
createPosNum++;
}
if (createPosNum < 1) { return; } // 无投放位置,退出
// 首次一次性投放3辆坦克
if (stu_project.enemyCreateNum == 0)
{
for (int i = 0; i < createPosNum; i++)
{
// 先把茅坑占上
stu_project.map[0][createPos[i]] = 999;
stu_project.map[0][createPos[i] + 1] = 999;
stu_project.map[1][createPos[i]] = 999;
stu_project.map[1][createPos[i] + 1] = 999;
// 增加星星
starAdd(0, createPos[i]);
}
}
else // 每隔一段时间投放一辆坦克
{
// 判断是否达到最大投放数量
if (stu_project.enemyCreateNum >= stu_project.enemyMaxNum) { return; }
// 得到随机投放位置
int pos = createPos[myRandom(0, createPosNum - 1)];
// 先把茅坑占上
stu_project.map[0][pos] = 999;
stu_project.map[0][pos + 1] = 999;
stu_project.map[1][pos] = 999;
stu_project.map[1][pos + 1] = 999;
// 增加星星
starAdd(0, pos);
}
}
}
// 敌方坦克创建(在星星创建的位置)
void enemyTankCreate(int row,int column)
{
// 在坦克池中寻找空闲的坦克
Enemy* enemy = nullptr;
int lenEnemyPool = enemyPool.size();
for (int i = 0; i < lenEnemyPool; i++)
{
if (enemyPool[i].status == TANK_STATUS_FREE)
{
enemy = &enemyPool[i];
break;
}
}
if (enemy == nullptr) // 没有就增加一个
{
Enemy newEnemy(0, 0, TANK_DIRECTION_DOWN);
enemyPool.push_back(newEnemy);
enemy = &enemyPool[lenEnemyPool];
}
// 开始投放
enemy->row = row;
enemy->oldRow = enemy->row;
enemy->column = column;
enemy->oldColumn = enemy->column;
enemy->x = enemy->column * BLOCK_SIZE;
enemy->y = 0;
enemy->direction = TANK_DIRECTION_DOWN;
if (stu_project.enemyCreateNum >= 3)
{
enemy->armor = myRandom(0, 3);
}
else
{
enemy->armor = 0;
}
enemy->originalArmor = enemy->armor;
enemy->target = myRandom(TANK_OWNER_HERO, HOME);
enemy->status = TANK_STATUS_RUN;
enemy->toMap();
stu_project.enemyCreateNum++;
}
// 敌方坦克AI(返回方向)
// 原理:判断目标与敌方坦克的相应位置,找出哪个方向最可能靠近目标。
int enemyTankAI(Enemy &enemy)
{
// 先剔除墙与铁块那个方向(铁块暂时打不动)
int validDirectory[4][2] = { -1,-1,-1,-1,-1,-1,-1,-1 }; // 可用方向数组[方向][空地/墙]
int validDirectoryNum = 0;
for (int i = 0; i < 4; i++)
{
bool blankFlag = false; // 空地标识(true-是空地,false-非空地)
if (i == TANK_DIRECTION_UP)
{
if (enemy.row == 0){continue;}
if (stu_project.map[enemy.row - 1][enemy.column] == IRON || stu_project.map[enemy.row - 1][enemy.column + 1] == IRON) { continue; }
if (stu_project.map[enemy.row - 1][enemy.column] == BLANK && stu_project.map[enemy.row - 1][enemy.column + 1] == BLANK) { blankFlag = true; }
}
else if (i == TANK_DIRECTION_DOWN)
{
if (enemy.row == 24) { continue; }
if (stu_project.map[enemy.row + 2][enemy.column] == IRON || stu_project.map[enemy.row + 2][enemy.column + 1] == IRON) { continue; }
if (stu_project.map[enemy.row + 2][enemy.column] == BLANK && stu_project.map[enemy.row + 2][enemy.column + 1] == BLANK) { blankFlag = true; }
}
else if (i == TANK_DIRECTION_LEFT)
{
if (enemy.column == 0) { continue; }
if (stu_project.map[enemy.row][enemy.column - 1] == IRON || stu_project.map[enemy.row + 1][enemy.column - 1] == IRON) { continue; }
if (stu_project.map[enemy.row][enemy.column - 1] == BLANK && stu_project.map[enemy.row + 1][enemy.column - 1] == BLANK) { blankFlag = true; }
}
else if (i == TANK_DIRECTION_RIGHT)
{
if (enemy.column == 24) { continue; }
if (stu_project.map[enemy.row][enemy.column + 2] == IRON || stu_project.map[enemy.row + 1][enemy.column + 2] == IRON) { continue; }
if (stu_project.map[enemy.row][enemy.column + 2] == BLANK && stu_project.map[enemy.row + 1][enemy.column + 2] == BLANK) { blankFlag = true; }
}
validDirectory[validDirectoryNum][0] = i;
if (blankFlag)
{
validDirectory[validDirectoryNum][1] = BLANK;
}
else
{
validDirectory[validDirectoryNum][1] = WALL;
}
validDirectoryNum++;
}
// 判断目标与敌方坦克位置关系
int directory[4] = { -1,-1,-1,-1 };
int targetRow;
int targetColumn;
if (enemy.target == TANK_OWNER_HERO) // 目标是我方坦克
{
targetRow = hero.row;
targetColumn = hero.column;
}
else // 目标是老巢
{
targetRow = 24;
targetColumn = 12;
}
if (targetColumn > enemy.column) // 目标在敌方坦克右边
{
if (targetRow < enemy.row) // 右上角(上或右)
{
for (int i = 0; i < validDirectoryNum; i++)
{
if (validDirectory[i][0] == TANK_DIRECTION_UP || validDirectory[i][0] == TANK_DIRECTION_RIGHT)
{
// 空地优先级别高
if (validDirectory[i][1] == BLANK)
{
if (directory[0] != -1){directory[1] = directory[0];}
directory[0] = validDirectory[i][0];
continue;
}
// 从左向右填充
for (int j = 0; j < 4; j++)
{
if (directory[j] == -1)
{
directory[j] = validDirectory[i][0];
break;
}
}
}
else
{
// 从右向左填充
for (int j = 3; j >= 0; j--)
{
if (directory[j] == -1)
{
directory[j] = validDirectory[i][0];
break;
}
}
}
}
}
else // 右下角(下或右)
{
for (int i = 0; i < validDirectoryNum; i++)
{
if (validDirectory[i][0] == TANK_DIRECTION_DOWN || validDirectory[i][0] == TANK_DIRECTION_RIGHT)
{
// 空地优先级别高
if (validDirectory[i][1] == BLANK)
{
if (directory[0] != -1) { directory[1] = directory[0]; }
directory[0] = validDirectory[i][0];
continue;
}
// 从左向右填充
for (int j = 0; j < 4; j++)
{
if (directory[j] == -1)
{
directory[j] = validDirectory[i][0];
break;
}
}
}
else
{
// 从右向左填充
for (int j = 3; j >= 0; j--)
{
if (directory[j] == -1)
{
directory[j] = validDirectory[i][0];
break;
}
}
}
}
}
// 特殊情况(同一条线上)
if (targetRow == enemy.row)
{
for (int i = 0; i < validDirectoryNum; i++)
{
if (validDirectory[i][0] == TANK_DIRECTION_RIGHT)
{
if (validDirectory[i][1] == BLANK){return validDirectory[i][0];} // 是空地就必须勇敢的冲过去
}
}
}
}
else // 目标在敌方坦克左边
{
if (targetRow < enemy.row) // 左上角(上或左)
{
for (int i = 0; i < validDirectoryNum; i++)
{
if (validDirectory[i][0] == TANK_DIRECTION_UP || validDirectory[i][0] == TANK_DIRECTION_LEFT)
{
// 空地优先级别高
if (validDirectory[i][1] == BLANK)
{
if (directory[0] != -1) { directory[1] = directory[0]; }
directory[0] = validDirectory[i][0];
continue;
}
// 从左向右填充
for (int j = 0; j < 4; j++)
{
if (directory[j] == -1)
{
directory[j] = validDirectory[i][0];
break;
}
}
}
else
{
// 从右向左填充
for (int j = 3; j >= 0; j--)
{
if (directory[j] == -1)
{
directory[j] = validDirectory[i][0];
break;
}
}
}
}
}
else // 左下角(下或左)
{
for (int i = 0; i < validDirectoryNum; i++)
{
if (validDirectory[i][0] == TANK_DIRECTION_DOWN || validDirectory[i][0] == TANK_DIRECTION_LEFT)
{
// 空地优先级别高
if (validDirectory[i][1] == BLANK)
{
if (directory[0] != -1) { directory[1] = directory[0]; }
directory[0] = validDirectory[i][0];
continue;
}
// 从左向右填充
for (int j = 0; j < 4; j++)
{
if (directory[j] == -1)
{
directory[j] = validDirectory[i][0];
break;
}
}
}
else
{
// 从右向左填充
for (int j = 3; j >= 0; j--)
{
if (directory[j] == -1)
{
directory[j] = validDirectory[i][0];
break;
}
}
}
}
}
// 特殊情况(同一条线上)
if (targetRow == enemy.row)
{
for (int i = 0; i < validDirectoryNum; i++)
{
if (validDirectory[i][0] == TANK_DIRECTION_LEFT)
{
if (validDirectory[i][1] == BLANK) { return validDirectory[i][0]; } // 是空地就必须勇敢的冲过去
}
}
}
}
if (targetColumn == enemy.column) // 目标在敌方坦克正上或下方
{
// 特殊情况(同一条线上)
if (targetRow < enemy.row) // 正上方
{
for (int i = 0; i < validDirectoryNum; i++)
{
if (validDirectory[i][0] == TANK_DIRECTION_UP)
{
if (validDirectory[i][1] == BLANK) { return validDirectory[i][0]; } // 是空地就必须勇敢的冲过去
}
}
}
else
{
for (int i = 0; i < validDirectoryNum; i++)
{
if (validDirectory[i][0] == TANK_DIRECTION_DOWN)
{
if (validDirectory[i][1] == BLANK) {return validDirectory[i][0]; } // 是空地就必须勇敢的冲过去
}
}
}
}
// 方向补全
for (int i = 0; i < 4; i++)
{
if (directory[i] == -1) { directory[i] = enemy.direction; }
}
// 随机抽取4:3:2:1
int random = myRandom(1,10);
if (random <= 4)
{
return directory[0];
}
else if (random <= 7)
{
return directory[1];
}
else if (random <= 9)
{
return directory[2];
}
else
{
return directory[3];
}
}
// 敌方坦克移动
void enemyTankMove()
{
if (myTimer(INTERVAL_MOVEENEMY, TIMERID_MOVEENEMY))
{
int lenEnemyPool = enemyPool.size();
for (int i = 0; i < lenEnemyPool; i++)
{
if (enemyPool[i].status == TANK_STATUS_RUN)
{
// 得到移动方向
enemyPool[i].direction = enemyTankAI(enemyPool[i]);
enemyPool[i].move(enemyPool[i].direction);
stu_project.refreshFlag = true;
}
}
}
}
// 敌方坦克射击
void enemyTankShoot()
{
if (myTimer(INTERVAL_BULLET_SHOOT, TIMERID_BULLET_SHOOT))
{
int lenEnemyPool = enemyPool.size();
for (int i = 0; i < lenEnemyPool; i++)
{
if (enemyPool[i].status == TANK_STATUS_RUN)
{
// 敌方坦克比较傻,不爱射击
if (myRandom(1, 10) < 4){enemyPool[i].shoot();} // 30%几率开枪
stu_project.refreshFlag = true;
}
}
}
}
// 向爆炸池增加
void bombAdd(int x, int y)
{
// 查找空闲的爆炸
Bomb* bomb = nullptr;
int len = bombPool.size();
for (int i = 0; i < len; i++)
{
if (bombPool[i].status == BOMB_STATUS_FREE)
{
bomb = &bombPool[i];
break;
}
}
if (bomb == nullptr) // 没有就增加一个
{
Bomb newBomb;
bombPool.push_back(newBomb);
bomb = &bombPool[len];
}
bomb->x = x;
bomb->y = y;
bomb->frameIndex = 0;
bomb->status = BOMB_STATUS_RUN;
}
// 得到子弹所在行列位置(子弹位于坦克中间位置,所以正对着2个格子的中间位置,所以计算时2个格子都在其射击范围内)
void getBulletPos(struct _stu_bullet_pos* pBulletPos, int x, int y, int direction)
{
int x1, y1, x2, y2;
// 重算子弹图片中心点坐标(因为此时的x与y是子弹图片左上角的坐标)
x = x + BULLET_SIZE / 2;
y = y + BULLET_SIZE / 2;
// 根据方向判断2个格子位置
if (direction == TANK_DIRECTION_UP || direction == TANK_DIRECTION_DOWN)
{
x1 = x - BLOCK_SIZE / 2;
y1 = y;
x2 = x + BLOCK_SIZE / 2;
y2 = y;
}
else
{
x1 = x;
y1 = y - BLOCK_SIZE / 2;
x2 = x;
y2 = y + BLOCK_SIZE / 2;
}
pBulletPos->row1 = y1 / BLOCK_SIZE;
pBulletPos->col1 = x1 / BLOCK_SIZE;
pBulletPos->row2 = y2 / BLOCK_SIZE;
pBulletPos->col2 = x2 / BLOCK_SIZE;
}
// 碰撞处理
void collide()
{
// 子弹所在位置结构体
struct _stu_bullet_pos stu_bullet_pos;
// 判断我方子弹是否与敌方坦克或块或老巢碰撞
int lenHeroBulletPool = heroBulletPool.size();
for (int i = 0; i < lenHeroBulletPool; i++)
{
if (heroBulletPool[i].status == BULLET_STATUS_RUN)
{
// 得到子弹所在行与列
getBulletPos(&stu_bullet_pos, heroBulletPool[i].x, heroBulletPool[i].y, heroBulletPool[i].direction);
// 得到子弹2个点的值
int v1 = stu_project.map[stu_bullet_pos.row1][stu_bullet_pos.col1];
int v2 = stu_project.map[stu_bullet_pos.row2][stu_bullet_pos.col2];
if (v1 == 0 && v2 == 0) { continue; }
if (v1 == TANK_OWNER_HERO && v2 == TANK_OWNER_HERO) { continue; }
// 判断是否与墙块碰撞
if (v1 == WALL) { stu_project.map[stu_bullet_pos.row1][stu_bullet_pos.col1] = 0; }
if (v2 == WALL) { stu_project.map[stu_bullet_pos.row2][stu_bullet_pos.col2] = 0; }
// 判断是否与老巢碰撞
if (v1 == HOME || v2 == HOME) { stu_project.gameStatus = GAME_STATUS_OVER; }
// 判断是否与敌方坦克碰撞
int lenEnemyPool = enemyPool.size();
for (int i = 0; i < lenEnemyPool; i++)
{
if (enemyPool[i].status == TANK_STATUS_RUN)
{
if (
(enemyPool[i].row == stu_bullet_pos.row1 && enemyPool[i].column == stu_bullet_pos.col1) ||
(enemyPool[i].row == stu_bullet_pos.row1 && enemyPool[i].column + 1 == stu_bullet_pos.col1) ||
(enemyPool[i].row + 1 == stu_bullet_pos.row1 && enemyPool[i].column == stu_bullet_pos.col1) ||
(enemyPool[i].row + 1 == stu_bullet_pos.row1 && enemyPool[i].column + 1 == stu_bullet_pos.col1) ||
(enemyPool[i].row == stu_bullet_pos.row2 && enemyPool[i].column == stu_bullet_pos.col2) ||
(enemyPool[i].row == stu_bullet_pos.row2 && enemyPool[i].column + 1 == stu_bullet_pos.col2) ||
(enemyPool[i].row + 1 == stu_bullet_pos.row2 && enemyPool[i].column == stu_bullet_pos.col2) ||
(enemyPool[i].row + 1 == stu_bullet_pos.row2 && enemyPool[i].column + 1 == stu_bullet_pos.col2)
)
{
myPlayAudio("./resources/audio/boom.wav");
if (enemyPool[i].armor == 0)
{
enemyPool[i].reset();
stu_project.enemyDeadNum++;
stu_project.enemyArmorDeadNum[enemyPool[i].originalArmor]++;
if (stu_project.enemyDeadNum >= stu_project.enemyMaxNum){stu_project.gameStatus = GAME_STATUS_WIN;}
break;
}
else
{
enemyPool[i].armor--;
}
}
}
}
// 子弹销毁
heroBulletPool[i].status = BULLET_STATUS_FREE;
// 子弹爆炸
bombAdd(heroBulletPool[i].x, heroBulletPool[i].y);
}
}
// 判断敌方子弹是否与我方坦克或块或老巢碰撞(不需要判断敌方坦克状态,因为即使坦克销毁子弹可能仍然在飞)
int lenEnemyPool = enemyPool.size();
for (int m = 0; m < lenEnemyPool; m++)
{
vector& enemyBulletPool = enemyPool[m].getBulletPool();
int lenEnemyBulletPool = enemyBulletPool.size();
for (int i = 0; i < lenEnemyBulletPool; i++)
{
if (enemyBulletPool[i].status == BULLET_STATUS_RUN)
{
// 得到子弹所在行与列
getBulletPos(&stu_bullet_pos, enemyBulletPool[i].x, enemyBulletPool[i].y, enemyBulletPool[i].direction);
// 得到子弹2个点的值
int v1 = stu_project.map[stu_bullet_pos.row1][stu_bullet_pos.col1];
int v2 = stu_project.map[stu_bullet_pos.row2][stu_bullet_pos.col2];
if (v1 == 0 && v2 == 0) { continue; }
if (v1 == TANK_OWNER_ENEMY && v2 == TANK_OWNER_ENEMY) { continue; }
// 判断是否与墙块碰撞
if (v1 == WALL) { stu_project.map[stu_bullet_pos.row1][stu_bullet_pos.col1] = 0; }
if (v2 == WALL) { stu_project.map[stu_bullet_pos.row2][stu_bullet_pos.col2] = 0; }
// 判断是否与老巢碰撞
if (v1 == HOME || v2 == HOME) { stu_project.gameStatus = GAME_STATUS_OVER; }
// 判断是否与我方坦克碰撞
if (hero.status == TANK_STATUS_RUN)
{
if (
(hero.row == stu_bullet_pos.row1 && hero.column == stu_bullet_pos.col1) ||
(hero.row == stu_bullet_pos.row1 && hero.column + 1 == stu_bullet_pos.col1) ||
(hero.row + 1 == stu_bullet_pos.row1 && hero.column == stu_bullet_pos.col1) ||
(hero.row + 1 == stu_bullet_pos.row1 && hero.column + 1 == stu_bullet_pos.col1) ||
(hero.row == stu_bullet_pos.row2 && hero.column == stu_bullet_pos.col2) ||
(hero.row == stu_bullet_pos.row2 && hero.column + 1 == stu_bullet_pos.col2) ||
(hero.row + 1 == stu_bullet_pos.row2 && hero.column == stu_bullet_pos.col2) ||
(hero.row + 1 == stu_bullet_pos.row2 && hero.column + 1 == stu_bullet_pos.col2)
)
{
if (hero.armor == 0)
{
hero.reset();
stu_project.gameStatus = GAME_STATUS_OVER;
}
else
{
hero.armor--;
}
}
}
// 子弹销毁
enemyBulletPool[i].status = BULLET_STATUS_FREE;
// 子弹爆炸
bombAdd(enemyBulletPool[i].x, enemyBulletPool[i].y);
}
}
}
}
// 游戏进程
void run()
{
// 重置刷新标识
stu_project.refreshFlag = false;
// 星星创建
starCreate();
// 星星进程
if (myTimer(INTERVAL_STAR, TIMERID_STAR))
{
int len = starPool.size();
for (int i = 0; i < len; i++)
{
if (starPool[i].status == STAR_STATUS_RUN)
{
int index = starPool[i].frameIndex;
if (index >= starPool[i].maxFrame - 1)
{
starPool[i].status = STAR_STATUS_FREE;
enemyTankCreate(starPool[i].row, starPool[i].column); // 创建敌方坦克
continue;
}
starPool[i].frameIndex = ++index;
}
}
}
// 敌方坦克移动
enemyTankMove();
// 敌方坦克射击
enemyTankShoot();
// 坦克移动进程
if (myTimer(INTERVAL_TANKMOVE, TIMERID_TANKMOVE))
{
// 我方坦克移动
if (hero.oldRow != hero.row)
{
int destY = hero.row * BLOCK_SIZE;
if (hero.direction == TANK_DIRECTION_UP)
{
if (hero.y > destY)
{
hero.y = hero.y - hero.speed;
hero.track = !hero.track; // 切换履带
}
else
{
hero.oldRow = hero.row;
hero.y = destY; // 坐标微调
}
}
else if (hero.direction == TANK_DIRECTION_DOWN)
{
if (hero.y < destY)
{
hero.y = hero.y + hero.speed;
hero.track = !hero.track;
}
else
{
hero.oldRow = hero.row;
hero.y = destY;
}
}
stu_project.refreshFlag = true;
}
else if (hero.column != hero.oldColumn)
{
int destX = hero.column * BLOCK_SIZE;
if (hero.direction == TANK_DIRECTION_LEFT)
{
if (hero.x > destX)
{
hero.x = hero.x - hero.speed;
hero.track = !hero.track;
}
else
{
hero.oldColumn = hero.column;
hero.x = destX;
}
}
else if (hero.direction == TANK_DIRECTION_RIGHT)
{
if (hero.x < destX)
{
hero.x = hero.x + hero.speed;
hero.track = !hero.track;
}
else
{
hero.oldColumn = hero.column;
hero.x = destX;
}
}
stu_project.refreshFlag = true;
}
// 敌方坦克移动
int lenEnemyPool = enemyPool.size();
for (int i = 0; i < lenEnemyPool; i++)
{
if (enemyPool[i].status == TANK_STATUS_RUN)
{
if (enemyPool[i].oldRow != enemyPool[i].row)
{
int destY = enemyPool[i].row * BLOCK_SIZE;
if (enemyPool[i].direction == TANK_DIRECTION_UP)
{
if (enemyPool[i].y > destY)
{
enemyPool[i].y = enemyPool[i].y - enemyPool[i].speed;
enemyPool[i].track = !enemyPool[i].track; // 切换履带
}
else
{
enemyPool[i].oldRow = enemyPool[i].row;
enemyPool[i].y = destY; // 坐标微调
}
}
else if (enemyPool[i].direction == TANK_DIRECTION_DOWN)
{
if (enemyPool[i].y < destY)
{
enemyPool[i].y = enemyPool[i].y + enemyPool[i].speed;
enemyPool[i].track = !enemyPool[i].track;
}
else
{
enemyPool[i].oldRow = enemyPool[i].row;
enemyPool[i].y = destY;
}
}
stu_project.refreshFlag = true;
}
else if (enemyPool[i].column != enemyPool[i].oldColumn)
{
int destX = enemyPool[i].column * BLOCK_SIZE;
if (enemyPool[i].direction == TANK_DIRECTION_LEFT)
{
if (enemyPool[i].x > destX)
{
enemyPool[i].x = enemyPool[i].x - enemyPool[i].speed;
enemyPool[i].track = !enemyPool[i].track;
}
else
{
enemyPool[i].oldColumn = enemyPool[i].column;
enemyPool[i].x = destX;
}
}
else if (enemyPool[i].direction == TANK_DIRECTION_RIGHT)
{
if (enemyPool[i].x < destX)
{
enemyPool[i].x = enemyPool[i].x + enemyPool[i].speed;
enemyPool[i].track = !enemyPool[i].track;
}
else
{
enemyPool[i].oldColumn = enemyPool[i].column;
enemyPool[i].x = destX;
}
}
stu_project.refreshFlag = true;
}
}
}
}
// 子弹进程
if (myTimer(INTERVAL_BULLET_RUN, TIMERID_BULLET_RUN))
{
// 我方子弹运行
int lenHeroBulletPool = heroBulletPool.size();
for (int i = 0; i < lenHeroBulletPool; i++)
{
if (heroBulletPool[i].status == BULLET_STATUS_RUN)
{
heroBulletPool[i].run();
}
}
// 敌方子弹运行
int lenEnemyPool = enemyPool.size();
for (int i = 0; i < lenEnemyPool; i++)
{
vector& enemyBulletPool = enemyPool[i].getBulletPool();
int lenEnemyBulletPool = enemyBulletPool.size();
for (int j = 0; j < lenEnemyBulletPool; j++)
{
if (enemyBulletPool[j].status == BULLET_STATUS_RUN)
{
enemyBulletPool[j].run();
}
}
}
}
// 碰撞处理
collide();
// 爆炸进程
if (myTimer(INTERVAL_BOMB, TIMERID_BOMB))
{
int len = bombPool.size();
for (int i = 0; i < len; i++)
{
if (bombPool[i].status == BOMB_STATUS_RUN)
{
int index = bombPool[i].frameIndex;
if (index >= bombPool[i].maxFrame - 1)
{
bombPool[i].status = BOMB_STATUS_FREE;
break;
}
bombPool[i].frameIndex = ++index;
}
}
}
// 刷新界面
if (stu_project.refreshFlag) { paint(); }
}
// 键盘监控
void keyEvent()
{
// 重置刷新标识
stu_project.refreshFlag = false;
// 方向键只运行同时按一个,用else if判断
if (myKeyDown(VK_UP)) // 上键
{
if (hero.move(TANK_DIRECTION_UP)) { stu_project.refreshFlag = true; }
}
else if (myKeyDown(VK_DOWN)) // 下键
{
if (hero.move(TANK_DIRECTION_DOWN)) { stu_project.refreshFlag = true; }
}
else if (myKeyDown(VK_LEFT)) // 左键
{
if (hero.move(TANK_DIRECTION_LEFT)) { stu_project.refreshFlag = true; }
}
else if (myKeyDown(VK_RIGHT)) // 右键
{
if (hero.move(TANK_DIRECTION_RIGHT)) { stu_project.refreshFlag = true; }
}
// 其他键不受限制
if (myKeyDown(VK_SPACE)) // 空格
{
hero.shoot();
stu_project.refreshFlag = true;
}
// 刷新界面
if (stu_project.refreshFlag) { paint(); }
}
// 鼠标监控
void mouseEvent()
{
ExMessage msg; // 鼠标消息结构体
if (peekmessage(&msg, EM_MOUSE)) // 只监听鼠标消息
{
switch (msg.message)
{
case WM_LBUTTONUP: // 鼠标左键释放(用msg.x与msg.y来判断点击位置)
break;
case WM_MOUSEMOVE: // 鼠标移动
break;
case WM_RBUTTONUP: // 鼠标右键释放
break;
}
}
}
// 显示本关分数
void showScore()
{
putimage(0, 0, &stu_project.imgScore);
settextstyle(24, 0, "微软雅黑");
settextcolor(YELLOW);
setbkmode(TRANSPARENT);
myDrawString(330, 58, to_string(stu_project.level + 1));
settextcolor(WHITE);
int score = 0;
for (int i = 0; i < 4; i++)
{
score = score + stu_project.enemyArmorDeadNum[i] * 100 * (i + 1);
myDrawString(176, 183 + i * 42 , to_string(stu_project.enemyArmorDeadNum[i]));
myDrawString(220, 183 + i * 42, "×");
myDrawString(260, 183 + i * 42, to_string(100 * (i + 1)));
myDrawString(320, 183 + i * 42, "=");
myDrawString(350, 183 + i * 42, to_string(stu_project.enemyArmorDeadNum[i] * 100 * (i + 1)));
Sleep(500);
}
settextcolor(RED);
myDrawString(350, 350, to_string(score));
Sleep(500);
system("pause");
}
// 处理游戏状态(下一关或失败)
void doGame()
{
// 游戏结束
if (stu_project.gameStatus == GAME_STATUS_OVER)
{
myPlayAudio("./resources/audio/over.mp3");
myDrawImage((GAME_WIDTH - stu_project.imgFailure.getwidth()) / 2, (GAME_HEIGHT - stu_project.imgFailure.getheight()) / 2, &stu_project.imgFailure);
Sleep(1000);
showScore();
}
else if (stu_project.gameStatus == GAME_STATUS_WIN)
{
myDrawImage((GAME_WIDTH - stu_project.imgSuccess.getwidth()) / 2, (GAME_HEIGHT - stu_project.imgSuccess.getheight()) / 2, &stu_project.imgSuccess);
Sleep(1000);
showScore();
stu_project.level++;
if (stu_project.level < GameMap::getMaxLevel())
{
newGame();
}
}
}
// 开始游戏
void newGame()
{
myPlayAudio("./resources/audio/begin.mp3");
// 初始化游戏
initGame();
// 开始游戏
while (stu_project.gameStatus == GAME_STATUS_RUN)
{
// 开始刷新
if (myTimer(INTERVAL_REFRESH, TIMERID_REFRESH))
{
// 绘制窗口
paint();
// 游戏进程
run();
}
// 键盘监控
keyEvent();
// 鼠标监控(必须随时监控,否则不湿滑)
//mouseEvent();
}
// 处理游戏状态(下一关或失败)
doGame();
}
链接:https://pan.baidu.com/s/1Mk-yTrfrXnb-FmYO82YA4A?pwd=g67n
提取码:g67n