#include <stdio.h>
#include <graphics.h>
#include <mmsystem.h>
#include <windows.h>
#include <time.h>
#include <vector>
#include <utility>
#include"tools.h"
#pragma comment(lib, "winmm.lib")
#define WIDTH 1000
#define HEIGHT 600
#define KEY_DELAY 70
#define VOLUME_STEP 10
#define TOTAL_ROWS 5 // 总行数
#define PEA_SPEED 8 // 豌豆移动速度(像素/帧)
#define PEA_DAMAGE 1 // 豌豆伤害
#define BASE_ZOMBIE_HP 100 // 基础僵尸血量
#define MIN_SHOOT_INTERVAL 1000 // 最小发射间隔(毫秒)
#define MAX_SHOOT_INTERVAL 2500 // 最大发射间隔(毫秒)
#define ZOMBIE_DEAD_FRAME_DELAY 80 // 僵尸死亡帧间隔
#define ZOMBIE_EAT_FRAME_DELAY 100 // 僵尸吃植物帧间隔
#define ZOMBIE_DETECTION_RANGE 800 // 僵尸检测范围
#define PLANT_HP 5 // 植物血量
// 僵尸相关参数
#define ZOMBIE_EAT_OFFSET 30 // 僵尸碰撞判定右移
#define ZOMBIE_MOVE_SPEED 1 // 僵尸移动速度
#define ZOMBIE_EAT_DISTANCE 10 // 僵尸进入吃植物状态的距离
#define ZOMBIE_HOME_BREACH -100 // 僵尸闯入家中的X坐标
// 食人花相关参数
#define MANEATER_ATTACK_RANGE 90 // 攻击范围
#define MANEATER_COOLDOWN 4000 // 攻击冷却时间
#define MANEATER_EAT_FRAMES 15 // 吃僵尸动画帧数
#define MANEATER_EAT_FRAME_DELAY 80 // 吃僵尸动画帧间隔
// 胜利条件参数
#define WIN_ZOMBIE_COUNT 30 // 消灭多少僵尸获胜
// 难度提升参数
#define ZOMBIES_PER_LEVEL 5 // 每消灭这些僵尸提升一次难度
#define HP_INCREASE_PER_LEVEL 1 // 每级增加的僵尸血量
// 游戏状态枚举
enum GameState {
GAME_PLAYING,
GAME_WIN,
GAME_OVER
};
// 植物类型枚举
enum { PLANT_PEA, PLANT_SUN, PLANT_MANEATER, TOTAL_PLANTS };
// 豌豆结构体
struct Pea {
int x; // X坐标
int y; // Y坐标
int row; // 所在行
bool used; // 是否活跃
};
// 爆炸特效结构体
struct Explosion {
int x; // X坐标
int y; // Y坐标
int frame; // 当前帧
bool used; // 是否活跃
ULONGLONG frameTimer; // 帧计时器
};
// 僵尸结构体
struct Zombie {
int x; // X坐标
int y; // Y坐标
int row; // 所在行
// 行走动画
int walkFrame; // 行走帧(0~21)
// 吃植物动画
bool isEating; // 是否在吃植物
int eatFrame; // 吃植物帧(0~20)
ULONGLONG eatTimer; // 吃植物帧计时器
// 死亡动画
bool isDying; // 是否处于死亡动画中
bool isBeingEaten; // 是否被食人花吃
int deadFrame; // 死亡帧(0~19)
ULONGLONG deadFrameTimer; // 死亡帧计时器
// 基础状态
int hp; // 僵尸血量
bool used; // 是否存活
// 目标植物信息
int targetPlantRow;
int targetPlantCol;
int targetPlantX;
};
// 植物结构体
struct PlantStatus
{
int type;
int frame;
int sunTimer; // 太阳花生成阳光计时器
ULONGLONG bulletTimer; // 豌豆射手发射计时器
ULONGLONG attackCooldown; // 食人花攻击冷却计时器
ULONGLONG eatFrameTimer; // 食人花吃僵尸帧计时器
bool isEatingZombie; // 食人花是否正在吃僵尸
int eatZombieFrame; // 食人花吃僵尸动画帧
int hp; // 植物血量
} map[TOTAL_ROWS][9] = { 0 };
// 阳光结构体
struct SunShine
{
int x;
int y;
int frameindex;
int DSTY;
bool USED;
int TIMER;
};
// 全局资源与变量
IMAGE imgBg, imgBr, imgCards[TOTAL_PLANTS];
IMAGE imgWinBg, imgGameOverBg; // 胜利和失败背景
IMAGE* imgPlants[TOTAL_PLANTS][20];
IMAGE imgSun[29];
IMAGE* imgZombies[22] = { nullptr }; // 僵尸行走图片
IMAGE* imgZombieDead[20] = { nullptr }; // 僵尸死亡图片
IMAGE* imgZombieEat[21] = { nullptr }; // 僵尸吃植物图片
IMAGE imgPea; // 豌豆图片
IMAGE imgExplosion; // 爆炸特效图片
Zombie zombies[20] = { 0 }; // 僵尸数组
Pea peas[30] = { 0 }; // 豌豆数组
Explosion explosions[15] = { 0 }; // 爆炸特效数组
SunShine balls[10]; // 阳光池
char pathBuffer[64], debugText[256];
int curX, curY, Select_Index = 0;
int sunlight = 100;
bool isPlantSoundPlaying = false;
ULONGLONG plantSoundStartTime = 0;
const int PLANT_SOUND_DURATION = 1000;
ULONGLONG lastKeyPressTime = 0;
int currentVolume = 500;
GameState gameState = GAME_PLAYING; // 当前游戏状态
// 难度系统变量
int zombieKillCount = 0; // 已消灭僵尸数量
int difficultyLevel = 1; // 当前难度等级
// 检查文件是否存在
bool FileExists(const char* path) {
FILE* fp;
if (fopen_s(&fp, path, "r") == 0) {
fclose(fp);
return true;
}
return false;
}
// 播放音效
void PlaySoundEffect(const char* soundPath, const char* alias) {
if (!FileExists(soundPath)) return;
char cmd[128];
sprintf_s(cmd, "close %s", alias);
mciSendString(cmd, NULL, 0, NULL);
sprintf_s(cmd, "open "%s" type mpegvideo alias %s", soundPath, alias);
mciSendString(cmd, NULL, 0, NULL);
sprintf_s(cmd, "setaudio %s volume to %d", alias, currentVolume);
mciSendString(cmd, NULL, 0, NULL);
sprintf_s(cmd, "play %s", alias);
mciSendString(cmd, NULL, 0, NULL);
}
// 播放背景音乐
void PlayBGM() {
if (FileExists("res/bg.MP3")) {
mciSendString("open res/bg.MP3 type mpegvideo alias bgm", NULL, 0, NULL);
mciSendString("play bgm repeat", NULL, 0, NULL);
}
}
// 获取当前难度下的僵尸血量
int GetZombieHP() {
return BASE_ZOMBIE_HP + (difficultyLevel - 1) * HP_INCREASE_PER_LEVEL;
}
// 检查指定行是否有僵尸
bool hasZombieInRow(int row) {
for (int i = 0; i < 20; i++) {
if (zombies[i].used && !zombies[i].isDying && !zombies[i].isBeingEaten && zombies[i].row == row) {
return zombies[i].x < WIDTH&& zombies[i].x > -ZOMBIE_DETECTION_RANGE;
}
}
return false;
}
// 获取指定行最近僵尸的距离
int getNearestZombieDistance(int row, int plantCol) {
int plantX = 252 + plantCol * 78;
int minDistance = ZOMBIE_DETECTION_RANGE;
bool found = false;
}
// 检查植物与僵尸之间是否有其他僵尸遮挡
bool isZombieBlocked(int row, int zombieX, int plantX) {
for (int i = 0; i < 20; i++) {
if (!zombies[i].used || zombies[i].isDying || zombies[i].isBeingEaten || zombies[i].row != row) continue;
}
// 检测僵尸是否碰到可吃的植物
bool checkZombiePlantCollision(Zombie& zombie, int& targetRow, int& targetCol, int& targetX) {
int zombieEffectiveX = zombie.x + ZOMBIE_EAT_OFFSET;
int zombieW, zombieH;
if (zombie.isEating && imgZombieEat[zombie.eatFrame]) {
zombieW = imgZombieEat[zombie.eatFrame]->getwidth();
zombieH = imgZombieEat[zombie.eatFrame]->getheight();
}
else if (imgZombies[zombie.walkFrame]) {
zombieW = imgZombies[zombie.walkFrame]->getwidth();
zombieH = imgZombies[zombie.walkFrame]->getheight();
}
else return false;
int zombieEffectiveW = zombieW - ZOMBIE_EAT_OFFSET;
}
// 食人花检测范围内的僵尸
int checkManeaterTarget(int row, int col) {
int plantX = 252 + col * 78;
int plantY = 87 + row * 97 - 5;
int plantW = imgPlants[PLANT_MANEATER][0]->getwidth();
}
// 生成僵尸
void createZombie() {
static int count = 0;
static int spawnInterval = 50;
static int currentRow = 0;
static int offsetTimer = 0;
count++;
}
// 生成豌豆
void createPea(int x, int y, int row) {
for (int i = 0; i < 30; i++) {
if (!peas[i].used) {
peas[i].used = true;
peas[i].x = x;
peas[i].y = y;
peas[i].row = row;
PlaySoundEffect("res/audio/pea_shoot.mp3", "peaShoot");
return;
}
}
}
// 生成爆炸特效
void createExplosion(int zombieX, int zombieY, int zombieWidth, int zombieHeight) {
for (int i = 0; i < 15; i++) {
if (!explosions[i].used) {
explosions[i].used = true;
explosions[i].x = zombieX - 17 + zombieWidth / 2 - imgExplosion.getwidth() / 2;
explosions[i].y = zombieY + zombieHeight / 2 - imgExplosion.getheight() / 2;
explosions[i].frame = 0;
explosions[i].frameTimer = GetTickCount();
PlaySoundEffect("res/audio/explode.mp3", "explode");
return;
}
}
}
// 更新豌豆
void UpdatePeas() {
ULONGLONG currentTime = GetTickCount();
for (int i = 0; i < 30; i++) {
if (!peas[i].used) continue;
}
// 更新爆炸特效
void UpdateExplosions() {
ULONGLONG currentTime = GetTickCount();
for (int i = 0; i < 15; i++) {
if (!explosions[i].used) continue;
}
// 更新僵尸
void UpdateZombies() {
if (gameState != GAME_PLAYING) return;
}
// 处理食人花逻辑
void handleManeaterPlant(int row, int col) {
PlantStatus& plant = map[row][col];
ULONGLONG currentTime = GetTickCount();
}
// 更新植物
void UpdatePlants() {
if (gameState != GAME_PLAYING) return;
}
// 初始化游戏资源
void GameInit() {
// 加载背景和工具栏
loadimage(&imgBg, "res/Map/map0.jpg");
loadimage(&imgBr, "res/bar5.png");
}
// 获取卡片阳光消耗
int GetSunCost(int index) {
switch (index) {
case PLANT_PEA: return 100;
case PLANT_SUN: return 50;
case PLANT_MANEATER: return 150; // 食人花消耗更高
default: return 0;
}
}
// 绘制调试信息
void DrawDebugInfo() {
settextcolor(WHITE);
settextstyle(18, 0, "Consolas");
}
// 绘制游戏元素
void DrawScene() {
BeginBatchDraw();
}
// 收集阳光
void collectSunshine(ExMessage* msg) {
if (gameState != GAME_PLAYING) return;
}
// 处理鼠标操作
void HandleMouse() {
if (gameState != GAME_PLAYING) return;
}
// 检查植物放置声音
void CheckPlantSound() {
if (isPlantSoundPlaying) {
ULONGLONG currentTime = GetTickCount();
if (currentTime - plantSoundStartTime >= PLANT_SOUND_DURATION) {
mciSendString("close plant1", NULL, 0, NULL);
isPlantSoundPlaying = false;
}
}
}
// 处理音量控制
void HandleVolumeKeys() {
ULONGLONG currentTime = GetTickCount();
if ((GetAsyncKeyState(VK_LEFT) & 0x8000) && (currentTime - lastKeyPressTime > KEY_DELAY)) {
currentVolume = max(0, currentVolume - VOLUME_STEP);
char cmd[32];
sprintf_s(cmd, "setaudio bgm volume to %d", currentVolume);
mciSendString(cmd, NULL, 0, NULL);
lastKeyPressTime = currentTime;
}
if ((GetAsyncKeyState(VK_RIGHT) & 0x8000) && (currentTime - lastKeyPressTime > KEY_DELAY)) {
currentVolume = min(1000, currentVolume + VOLUME_STEP);
char cmd[32];
sprintf_s(cmd, "setaudio bgm volume to %d", currentVolume);
mciSendString(cmd, NULL, 0, NULL);
lastKeyPressTime = currentTime;
}
}
// 释放资源
void Cleanup() {
mciSendString("stop bgm", NULL, 0, NULL);
mciSendString("close bgm", NULL, 0, NULL);
mciSendString("close plant1", NULL, 0, NULL);
mciSendString("close peaShoot", NULL, 0, NULL);
mciSendString("close explode", NULL, 0, NULL);
mciSendString("close zombieDead", NULL, 0, NULL);
mciSendString("close zombieEat", NULL, 0, NULL);
mciSendString("close maneaterEat", NULL, 0, NULL);
mciSendString("close difficultyUp", NULL, 0, NULL);
mciSendString("close zombieHit", NULL, 0, NULL);
mciSendString("close winSound", NULL, 0, NULL);
mciSendString("close loseSound", NULL, 0, NULL);
}
// 处理输入
void HandleInput() {
HandleMouse();
HandleVolumeKeys();
}
int main() {
GameInit();
int timer = 0;
}
#pragma once
#include <graphics.h>
void putimagePNG(int picture_x, int picture_y, IMAGE* picture);
int getDelay();
#include "tools.h"
#include <graphics.h>
// 载入PNG图并去透明部分
void _putimagePNG(int picture_x, int picture_y, IMAGE* picture) //x为载入图片的X坐标,y为Y坐标
{
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; //在显存里像素的角标
}
// 适用于 y <0 以及x<0的任何情况
void putimagePNG(int x, int y, IMAGE* picture) {
}
int getDelay() {
static unsigned long long lastTime = 0;
unsigned long long currentTime = GetTickCount();
if (lastTime == 0) {
lastTime = currentTime;
return 0;
}
else {
int ret = currentTime - lastTime;
lastTime = currentTime;
return ret;
}
}
DWORD* GetImageBuffer(IMAGE* pImg)
{
return GetImageBuffer(pImg);
}
我学废了自己写的!!!!!植物大战僵尸看得懂的自己找素材