邯郸做移动网站价格,跨境电商是不是坑,免费行情的软件入口,表格制作excel下载游戏索引 游戏名称#xff1a;植物大战僵尸 游戏介绍#xff1a; 本游戏是在B站博主程序员Rock的视频指导下完成 想学的更详细的小伙伴可以移步到程序员Rock视频 语言项目#xff1a;完整版植物大战僵尸#xff01;可能是B站最好的植物大战僵尸教程了… 游戏索引 游戏名称植物大战僵尸 游戏介绍 本游戏是在B站博主程序员Rock的视频指导下完成 想学的更详细的小伙伴可以移步到程序员Rock视频 语言项目完整版植物大战僵尸可能是B站最好的植物大战僵尸教程了零基础手把手游戏开发 游戏效果展示 植物大战僵尸 游戏模块 1实现最开始的游戏场景 2实现游戏顶部的工具栏 3实现工具栏的植物卡牌 4植物卡牌的选择与拖动 5植物的种植 6植物的摇摆 7制作启动菜单 10创建随机阳光 11收集阳光显示阳光值 12创建僵尸 13子弹对僵尸的碰撞 14僵尸对植物的碰撞 15场景巡场 16状态栏下滑 17游戏输赢的判断 目录 游戏索引 游戏名称植物大战僵尸 游戏介绍 游戏效果展示 游戏模块 写代码前的准备工作 搭建项目环境easyx 导入游戏素材 修改项目属性 导入我们的辅助项目 vector2.h vector2.cpp tools.h tools.cpp 导入操作 项目所需头文件以及结构体的定义 游戏页面的实现 游戏的背景初始化 判断读取文件是否存在 将图片显示在窗口上 游戏场景动作的实现 游戏中的阳光操作 编辑 1创建阳光: 2实现阳光旋转动作: 3实现阳光收集操作: 游戏中的僵尸操作 1创建僵尸: 2实现僵尸的动作 游戏中的豌豆子弹操作 1创建豌豆子弹: 2实现豌豆子弹的动作: 游戏中植物与僵尸碰撞的实现 1豌豆子弹与僵尸的碰撞检测实现: 2僵尸与植物的碰撞检测实现: 游戏场景巡场的实现 编辑 游戏中状态栏下滑实现 游戏输赢的判断 用户的鼠标操作 main主菜单 代码的整体实现 素材已上传至百度网盘 百度网盘 请输入提取码 提取码ABCD 写代码前的准备工作 搭建项目环境easyx 要想在我们的窗口实现图片交互 应该给编译器安装 easyx 图形库 这边我用图片展示详细的安装操作 1我们先在网页找到官网 2然后点击下载 3将 easyx 安装到目标编译器 4出现安装成功就代表可以使用了 接下来我们就可以写放心写代码啦 导入游戏素材 在当前项目的目录下创建文件夹并把解压好的文件拷贝进去 修改项目属性 1点击项目找到项目属性 2将字符集改成多字符集 这里图片操作的时候需要 3将编译器对SDL的检查关掉 这里检查文件是否存在的时候需要 导入我们的辅助项目 vector2.h #pragma once//头文件要求
#include cmathstruct vector2 {vector2(int _x0, int _y0) :x(_x), y(_y) {}vector2(int* data) :x(data[0]), y(data[1]){}long long x, y;
};//加法
vector2 operator (vector2 x, vector2 y);//减法
vector2 operator -(vector2 x, vector2 y);// 乘法
vector2 operator *(vector2 x, vector2 y);
vector2 operator *(vector2, float);
vector2 operator *(float, vector2);//叉积
long long cross(vector2 x, vector2 y);//数量积 点积
long long dot(vector2 x, vector2 y);//四舍五入除法
long long dv(long long a, long long b);//模长平方
long long len(vector2 x);//模长
long long dis(vector2 x);//向量除法
vector2 operator /(vector2 x, vector2 y);//向量膜
vector2 operator %(vector2 x, vector2 y);//向量GCD
vector2 gcd(vector2 x, vector2 y);//贝塞尔曲线
vector2 calcBezierPoint(float t, vector2 p0, vector2 p1, vector2 p2, vector2 p3); vector2.cpp //头文件要求
#include cmath
#include vector2.h//加法
vector2 operator (vector2 x, vector2 y) { return vector2(x.x y.x, x.y y.y );
}//减法
vector2 operator -(vector2 x, vector2 y) {return vector2(x.x - y.x, x.y - y.y);
}// 乘法
vector2 operator *(vector2 x, vector2 y) {return vector2(x.x * y.x - x.y * y.y, x.y * y.x x.x * y.y);
}// 乘法
vector2 operator *(vector2 y, float x) {return vector2(x*y.x, x*y.y);
}vector2 operator *(float x, vector2 y) {return vector2(x * y.x, x * y.y);
}//叉积
long long cross(vector2 x, vector2 y) { return x.y * y.x - x.x * y.y; }//数量积 点积
long long dot(vector2 x, vector2 y) { return x.x * y.x x.y * y.y; }//四舍五入除法
long long dv(long long a, long long b) {//注意重名 return b 0 ? dv(-a, -b): (a 0 ? -dv(-a, b): (a b / 2) / b);
}//模长平方
long long len(vector2 x) { return x.x * x.x x.y * x.y; }//模长
long long dis(vector2 x) { return sqrt(x.x * x.x x.y * x.y); }//向量除法
vector2 operator /(vector2 x, vector2 y) {long long l len(y);return vector2(dv(dot(x, y), l), dv(cross(x, y), l));
}//向量膜
vector2 operator %(vector2 x, vector2 y) { return x - ((x / y) * y); }//向量GCD
vector2 gcd(vector2 x, vector2 y) { return len(y) ? gcd(y, x % y) : x; }//贝塞尔曲线
vector2 calcBezierPoint(float t, vector2 p0, vector2 p1, vector2 p2, vector2 p3) {float u 1 - t;float tt t * t;float uu u * u;float uuu uu * u;float ttt tt * t;vector2 p uuu * p0;p p 3 * uu * t * p1;p p 3 * u * tt * p2;p p ttt * p3;return p;
}tools.h #pragma once
#include graphics.hvoid putimagePNG(int picture_x, int picture_y, IMAGE* picture);
int getDelay(); tools.cpp #include tools.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; //在显存里像素的角标// 实现透明贴图 公式 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里的Rint sg ((src[srcX] 0xff00) 8); //Gint sb src[srcX] 0xff; //Bif (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)| ((sg * sa / 255 dg * (255 - sa) / 255) 8)| (sb * sa / 255 db * (255 - sa) / 255);}}}
}// 适用于 y 0 以及x0的任何情况
void putimagePNG(int x, int y, IMAGE* picture) {IMAGE imgTmp, imgTmp2, imgTmp3;int winWidth getwidth();int winHeight getheight();if (y 0) {SetWorkingImage(picture);getimage(imgTmp, 0, -y,picture-getwidth(), picture-getheight() y);SetWorkingImage();y 0;picture imgTmp;}else if (y getheight() || x getwidth()) {return;}else if (y picture-getheight() winHeight) {SetWorkingImage(picture);getimage(imgTmp, x, y, picture-getwidth(), winHeight - y);SetWorkingImage();picture imgTmp;}if (x 0) {SetWorkingImage(picture);getimage(imgTmp2, -x, 0, picture-getwidth() x, picture-getheight());SetWorkingImage();x 0;picture imgTmp2;}if (x winWidth - picture-getwidth()) {SetWorkingImage(picture);getimage(imgTmp3, 0, 0, winWidth - x, picture-getheight());SetWorkingImage();picture imgTmp3;}_putimagePNG(x, y, 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;}
} 导入操作 1点击项目添加现有项 2选定我们要添加的辅助项目选择添加就好啦 项目所需头文件以及结构体的定义 #includestdio.h
#includegraphics.h
#includetools.h
#includectime
#includetime.h
#includemath.h
#includevector2.h //向量工具包
#includemmsystem.h //音乐
#pragma comment(lib,winmm.lib)//导入静态库
enum { WAN_DAO, XIANG_RI_KUI, JIAN_GUO, ZHI_WU_COUNT }; //植物枚举
enum { SUNSHINE_DOWN, SUNSHINE_GROUND, SUNSHINE_COLLECT, SUNSHINE_PRODUCT }; //阳光球状态枚举
enum { GOING, WIN, FAIL };IMAGE imgBg; //游戏背景图
IMAGE imgBar; //状态栏放植物的背景板
IMAGE imgCards[ZHI_WU_COUNT]; //植物卡牌数组
IMAGE* imgZhiWu[ZHI_WU_COUNT][20]; //植物数组 int curX, curY; //当前选中植物在移动中的坐标
int curZhiWu; //当前选中的植物 int killZmCount; //杀掉的僵尸总数
int zmCount; //生成的僵尸数量
int gameStatus; //游戏的状态#define WIN_WIDTH 900 //定义背景宽度
#define WIN_HEIGHT 600 //定义背景高度
#define ZM_MAX 10 //僵尸总数//植物结构体
struct zhiWu { int type; int frameIndex; //序列帧的序号int shootTimer; //植物攻击时间间隔bool catched; //植物是否被僵尸捕获int deadTimer; //植物被吃时的死亡倒计时int x, y;int timer; //用于向日葵生成阳光的计时器
};
//阳光球结构体
struct sunShineBall { int x, y; //阳光球的x、y坐标int frameIndex; //阳光球序列帧的序号int destY; //阳光球停止的y坐标bool used; //阳光球是否在使用int timer; //计时器用来限制阳光球最后的停留时间int xoff; //阳光球归位的x坐标int yoff; //阳光球归位的y坐标float t; vector2 p1, p2, p3, p4;vector2 pCur; //当前时刻阳光球的位置float speed;int status; //阳光球的状态
};struct sunShineBall balls[10]; //阳光球池用来事先存储阳光
IMAGE imgSunShineBall[29]; //阳光序列帧总数
//僵尸结构体
struct zm { int x, y;int row;int frameIndex;bool used;int speed; //僵尸前行速度int blood; //僵尸血量bool dead; //僵尸是否死亡bool eating; //僵尸是否在吃植物
};struct zm zms[10]; //僵尸池,用来事先存储僵尸
IMAGE imgZm[22];
IMAGE imgZmDead[20];
IMAGE imgZmEat[21];
IMAGE imgZmStand[11];//豌豆子弹结构体
struct bullet { int x, y, row, speed;bool used;bool blast; //判断是否爆炸int frameIndex; //爆炸帧序号
};
//豌豆子弹池
struct bullet bullets[30];
IMAGE imgBulletNormal;
IMAGE imgBulletBlast[4];int ballMax sizeof(balls) / sizeof(balls[0]); int zmMax sizeof(zms) / sizeof(zms[0]); //僵尸池中僵尸的总数int bulletMax sizeof(bullets) / sizeof(bullets[0]); //豌豆子弹池的总数struct zhiWu map[3][9]; //地图数组方便存储植物int sunShine; //阳光值游戏页面的实现 void startUI() {mciSendString(play res/audio/bg.mp3, 0, 0, 0);IMAGE imgMenu, imgMenu1, imgMenu2;int flag 0;loadimage(imgMenu, res/menu.png); //加载开始背景图loadimage(imgMenu1, res/menu1.png);loadimage(imgMenu2, res/menu2.png);while (1) {BeginBatchDraw(); //开始绘图putimage(0, 0, imgMenu); //渲染开始背景图到窗口上putimagePNG(474, 75, flag 0 ? imgMenu1 : imgMenu2);ExMessage msg;if (peekmessage(msg)) {if (msg.message WM_LBUTTONDOWN //鼠标左键落下 msg.x 474 msg.x 774 msg.y75 msg.y 215) {flag 1;mciSendString(play res/audio/awooga.mp3, 0, 0, 0);}}else if (msg.message WM_LBUTTONUP flag 1) { //鼠标左键抬起mciSendString(close res/audio/bg.mp3, 0, 0, 0);EndBatchDraw();return;}EndBatchDraw(); //结束绘图}
}双缓冲绘图 BeginBatchDraw() - 开始双缓冲 EndBatchDraw() - 结束双缓冲 双缓冲区打印一个的同时显示另一个不断重复这个过程避免了屏幕闪耀问题 游戏的背景初始化 void gameInit() {//设置随机种子srand(time(NULL));//加载游戏背景图片loadimage(imgBg, res/bg.jpg);//加载状态栏loadimage(imgBar, res/bar5.png);killZmCount 0;zmCount 0;gameStatus GOING;memset(imgZhiWu, 0, sizeof(imgZhiWu)); //给指针赋空值memset(map, 0, sizeof(map)); //初始化地图数组memset(balls, 0, sizeof(balls)); //初始化阳光池memset(zms, 0, sizeof(zms)); //初始化僵尸池memset(bullets, 0, sizeof(bullets)); //初始化豌豆子弹池//加载植物卡牌char name[64];for (int i 0; i ZHI_WU_COUNT; i) {//生成植物卡牌的文件名sprintf_s(name, sizeof(name), res/Cards/card_%d.png, i 1);loadimage(imgCards[i], name);for (int j 0; j 20; j) { sprintf_s(name, sizeof(name), res/zhiwu/%d/%d.png, i, j 1);//判断文件读取是否存在if (fileExist(name)) {imgZhiWu[i][j] new IMAGE;loadimage(imgZhiWu[i][j], name);}else {break;}}}//初始化选中植物curZhiWu 0;//初始化阳光值sunShine 50;//加载阳光for (int i 0; i 29; i) { sprintf_s(name, sizeof(name), res/sunshine/%d.png, i 1);loadimage(imgSunShineBall[i], name);}//加载僵尸图片for (int i 0; i 22; i) {sprintf_s(name, sizeof(name), res/zm/%d.png, i 1);loadimage(imgZm[i], name);}//加载僵尸死亡图片for (int i 0; i 20; i) {sprintf_s(name, sizeof(name), res/zm_dead/%d.png, i 1);loadimage(imgZmDead[i], name);}//加载僵尸吃植物图片for (int i 0; i 21; i) {sprintf_s(name, sizeof(name), res/zm_eat/%d.png, i 1);loadimage(imgZmEat[i], name);}//加载巡场僵尸图片for (int i 0; i 11; i) {sprintf_s(name, sizeof(name), res/zm_stand/%d.png, i 1);loadimage(imgZmStand[i], name);}//加载豌豆子弹图片loadimage(imgBulletNormal, res/bullets/bullet_normal.png);//加载豌豆子弹爆炸图片loadimage(imgBulletBlast[3], res/bullets/bullet_blast.png);for (int i 0; i 3; i) {float k (i 2) * 0.2;loadimage(imgBulletBlast[i], res/bullets/bullet_blast.png,imgBulletBlast[3].getwidth() * k, imgBulletBlast[3].getheight() * k, true);}//创建游戏窗口initgraph(WIN_WIDTH, WIN_HEIGHT); //设置字体LOGFONT f;gettextstyle(f);f.lfHeight 30;f.lfWeight 15;strcpy(f.lfFaceName, Segoe UI Black); //设置字体效果f.lfQuality ANTIALIASED_QUALITY; //抗锯齿settextstyle(f);setbkmode(TRANSPARENT); //字体模式背景透明setcolor(BLACK); //字体颜色黑色} 判断读取文件是否存在 bool fileExist(const char* name) {FILE* fp fopen(name, r);if (fp NULL) {return false;}else {fclose(fp);return true;}
} 将图片显示在窗口上 void updateWindow() {BeginBatchDraw();putimage(-112, 0, imgBg); //加载背景板putimagePNG(255, 0, imgBar); //加载状态栏for (int i 0; i ZHI_WU_COUNT; i) { //加载植物卡牌int x 343 i * 65;int y 6;putimagePNG(x, y, imgCards[i]);}//在地图上加载植物for (int i 0; i 3; i) {for (int j 0; j 9; j) {if (map[i][j].type 0) {int zhiWuType map[i][j].type - 1;int index map[i][j].frameIndex;putimagePNG(map[i][j].x, map[i][j].y, imgZhiWu[zhiWuType][index]);}}}//加载拖动的植物if (curZhiWu 0) {IMAGE* img imgZhiWu[curZhiWu - 1][0];putimagePNG(curX - img-getwidth() / 2, curY - img-getheight() / 2, img);}//加载阳光值char scoreText[8];sprintf_s(scoreText, sizeof(scoreText), %d, sunShine); //把阳光值转换成字符类型outtextxy(283, 67, scoreText); //加载僵尸for (int i 0; i zmMax; i) {if (zms[i].used) {IMAGE* img NULL;if (zms[i].eating) {img imgZmEat;}else if (zms[i].dead) {img imgZmDead;}else {img imgZm;}img zms[i].frameIndex;putimagePNG(zms[i].x, zms[i].y - img-getheight(), img);}}//加载豌豆子弹for (int i 0; i bulletMax; i) {if (bullets[i].used) {if (bullets[i].blast) { //豌豆子弹碰撞渲染IMAGE* img imgBulletBlast[bullets[i].frameIndex];putimagePNG(bullets[i].x, bullets[i].y, img);FlushBatchDraw();}else { putimagePNG(bullets[i].x, bullets[i].y, imgBulletNormal);}}}//加载阳光for (int i 0; i ballMax; i) {if (balls[i].used ) {IMAGE* img imgSunShineBall[balls[i].frameIndex];putimagePNG(balls[i].pCur.x, balls[i].pCur.y, img);}}EndBatchDraw();
}游戏场景动作的实现 void updateGame() {//更新植物动作for (int i 0; i 3; i) {for (int j 0; j 9; j) {if (map[i][j].type 0) {map[i][j].frameIndex;int zhiWuType map[i][j].type - 1;int index map[i][j].frameIndex;if (imgZhiWu[zhiWuType][index] NULL) {map[i][j].frameIndex 0;}}}}//创建僵尸createZm();//更新僵尸动作updateZm();//创建阳光createSunShine();//更新阳光动作updateSunShine();//创建豌豆子弹createBullets(); //更新豌豆子弹动作updateBullets();//豌豆子弹与僵尸碰撞collisionCheck();
}游戏中的阳光操作 1创建阳光: void createSunShine() {static int count 0;static int fre 200;count;if (count fre) { //限制阳光生成的速度fre 100 rand() % 150; //第二次生成阳光的时间随机count 0;int i;//从阳光池中取出可用的阳光for (i 0; i ballMax balls[i].used; i); if (i ballMax)return;balls[i].used true;balls[i].frameIndex 0;balls[i].timer 0;balls[i].status SUNSHINE_DOWN;balls[i].t 0;balls[i].p1 vector2(260 - 112 rand() % (900 - 320 112), 60);balls[i].p4 vector2(balls[i].p1.x, 200 (rand() % 4) * 90);int off 2;float distance balls[i].p4.y - balls[i].p1.y;balls[i].speed 1.0 / (distance / off);}//向日葵生产阳光for (int i 0; i 3; i) {for (int j 0; j 9; j) {if (map[i][j].type XIANG_RI_KUI 1) {map[i][j].timer;if (map[i][j].timer 200) {map[i][j].timer 0;int k;for (k 0; k ballMax balls[k].used; k);if (k ballMax)return;balls[k].used true;balls[k].p1 vector2(map[i][j].x, map[i][j].y); //设置贝塞尔曲线的参数int w (50 rand() % 51) * (rand() % 2 ? 1 : -1);balls[k].p4 vector2(map[i][j].x w, map[i][j].y imgZhiWu[XIANG_RI_KUI][0]-getheight()- imgSunShineBall-getheight());balls[k].p2 vector2(balls[k].p1.x w * 0.3, balls[k].p1.y - 100);balls[k].p3 vector2(balls[k].p1.x w * 0.7, balls[k].p1.y - 150);balls[k].status SUNSHINE_PRODUCT;balls[k].speed 0.05;balls[k].t 0;}}}}
} 2实现阳光旋转动作: void updateSunShine() {for (int i 0; i ballMax; i) {if (balls[i].used) {balls[i].frameIndex (balls[i].frameIndex 1) % 29; //更新序列帧if (balls[i].status SUNSHINE_DOWN) {struct sunShineBall* sun balls[i];sun-t sun-speed;sun-pCur sun-p1 sun-t * (sun-p4 - sun-p1);if (sun-t 1) {sun-status SUNSHINE_GROUND;sun-t 0;sun-timer 0;}}else if (balls[i].status SUNSHINE_GROUND) {balls[i].timer;if (balls[i].timer 100) {balls[i].used false;balls[i].timer 0;}}else if (balls[i].status SUNSHINE_COLLECT) {struct sunShineBall* sun balls[i];sun-t sun-speed;sun-pCur sun-p1 sun-t * (sun-p4 - sun-p1);if (sun-t 1) {sunShine 25;sun-used false;sun-t 0;}}else if (balls[i].status SUNSHINE_PRODUCT) {struct sunShineBall* sun balls[i];sun-t sun-speed;sun-pCur calcBezierPoint(sun-t, sun-p1, sun-p2, sun-p3, sun-p4);if (sun-t 1) {sun-status SUNSHINE_GROUND;sun-t 0;sun-timer 0;}}}}
}3实现阳光收集操作: void collectSunshine(ExMessage* msg) {int w imgSunShineBall[0].getwidth(); //单个阳光球的宽度int h imgSunShineBall[0].getheight(); //单个阳光球的高度for (int i 0; i ballMax; i) {if (balls[i].used) { //阳光球被使用了才进行操作int x balls[i].pCur.x;int y balls[i].pCur.y;if (msg-x x msg-xx w //只有当光标在阳光范围内才进行操作msg-yy msg-y y h) {balls[i].status SUNSHINE_COLLECT;mciSendString(play res/sunshine.mp3, 0, 0, 0);balls[i].p1 balls[i].pCur;balls[i].p4 vector2(262, 0);balls[i].t 0;float distance dis(balls[i].p1 - balls[i].p4);float off 8;balls[i].speed 1.0 / (distance / off);break;}}}
}游戏中的僵尸操作 1创建僵尸: void createZm()
{if (zmCount ZM_MAX) {return;}static int count 0;static int zmFre 500;count;if (count zmFre) { //限制僵尸生成的速度zmFre 300 rand() % 200; //第二次生成僵尸的时间随机count 0;int i;//从僵尸池中取出可用的僵尸for (i 0; i zmMax zms[i].used; i); //别问问就是一种新定义方式跟{}一个样就是!xxif (i zmMax)return;zms[i].used true;zms[i].x WIN_WIDTH;zms[i].row rand() % 3;zms[i].y 172 (zms[i].row 1) * 100;zms[i].speed 1;zms[i].blood 200;zms[i].dead false;zms[i].eating false;zmCount;}
} 2实现僵尸的动作 void updateZm() {//更新僵尸位置static int count 0;count;if (count 2) { //限制僵尸前进速度count 0;for (int i 0; i zmMax; i) {if (zms[i].used) {zms[i].x - zms[i].speed;if (zms[i].x 48) {//结束游戏gameStatus FAIL;}}}}//更新僵尸动作static int count2 0;count2;if (count2 4) { count2 0;for (int i 0; i zmMax; i) {if (zms[i].used) {if (zms[i].dead) {zms[i].frameIndex;if (zms[i].frameIndex 20) {zms[i].used false;killZmCount;if (killZmCount ZM_MAX) {gameStatus WIN;}}}else if (zms[i].eating) {zms[i].frameIndex (zms[i].frameIndex 1) % 20;}else{zms[i].frameIndex (zms[i].frameIndex 1) % 21; }}}}
} 游戏中的豌豆子弹操作 1创建豌豆子弹: void createBullets() {int lines[3] { 0 };int dangerX WIN_WIDTH - imgZm[0].getwidth() 50; //定义开始射击距离for (int i 0; i zmMax; i) {if (zms[i].used zms[i].x dangerX) {lines[zms[i].row] 1; }}for (int i 0; i 3; i) { for (int j 0; j 9; j) {if (lines[i] map[i][j].type 1) { //有豌豆且僵尸走到打击范围map[i][j].shootTimer;if (map[i][j].shootTimer 20) {map[i][j].shootTimer 0;int k;PlaySound(res/audio/shootpea1.wav, NULL, SND_FILENAME | SND_ASYNC);for (k 0; k bulletMax bullets[k].used; k);if (k bulletMax) return;bullets[k].used true; bullets[k].row i;bullets[k].speed 5;bullets[k].blast false;bullets[k].frameIndex 0;int zwX 256 - 112 j * 81;int zwY 179 i * 102 14;bullets[k].x zwX imgZhiWu[0][0]-getwidth() - 10;bullets[k].y zwY 5;lines[i] 0;}}}}
}2实现豌豆子弹的动作: void updateBullets() {for (int i 0; i bulletMax; i) {if (bullets[i].used) {bullets[i].x bullets[i].speed;if (bullets[i].x WIN_WIDTH) {bullets[i].used false;}//碰撞播放完就消失if (bullets[i].blast) {bullets[i].frameIndex;if (bullets[i].frameIndex 3) {bullets[i].used false;}}}}
} 游戏中植物与僵尸碰撞的实现 1豌豆子弹与僵尸的碰撞检测实现: void checkBullettoZm() {for (int i 0; i bulletMax; i) {if (bullets[i].used false || bullets[i].blast)continue; //如果豌豆子弹没使用或者已经开始碰撞就跳过for (int j 0; j zmMax; j) {if (zms[j].used false)continue;int x1 zms[j].x 80;int x2 zms[j].x 110;int x bullets[i].x;if (zms[j].dead false bullets[i].row zms[j].row x x1 x x2) { //豌豆子弹与僵尸碰撞后PlaySound(res/audio/peacrush1.wav, NULL, SND_FILENAME | SND_ASYNC);zms[j].blood - 10;bullets[i].blast true;bullets[i].speed 0;if (zms[j].blood 0) {zms[j].dead true;zms[j].speed 0;zms[j].frameIndex 0;}break;}}}
} 2僵尸与植物的碰撞检测实现: void checkZmtoZhiWu() {for (int i 0; i zmMax; i) {if (zms[i].dead)continue;int row zms[i].row;for (int k 0; k 9; k) {if (map[row][k].type 0)continue;int zhiWuX 256 - 112 k * 81; //定义僵尸开吃范围int x1 zhiWuX 10;int x2 zhiWuX 60;int x3 zms[i].x 80;if (x3 x1 x3 x2) {if (map[row][k].catched true) { //僵尸吃的过程中的一些配置map[row][k].deadTimer;mciSendString(play res/audio/zmeat.mp3, 0, 0, 0);if (map[row][k].deadTimer 100) {mciSendString(play res/audio/plantDead.mp3, 0, 0, 0);map[row][k].deadTimer 0;map[row][k].type 0;zms[i].eating false;zms[i].frameIndex 0;zms[i].speed 1;}}else {map[row][k].catched true;map[row][k].deadTimer 0;zms[i].eating true;zms[i].speed 0;zms[i].frameIndex 0;}}}}
} 游戏场景巡场的实现 void viewScence() {int xMin WIN_WIDTH - imgBg.getwidth();vector2 points[9] { {550,80},{530,160},{630,170},{530,200},{525,270}, {565,370},{605,340},{705,280},{690,340} };int index[9];for (int i 0; i 9; i) {index[i] rand() % 11;}int count 0;for (int x 0; x xMin; x - 4) {BeginBatchDraw();putimage(x, 0, imgBg);count;for (int k 0; k 9; k) {putimagePNG(points[k].x - xMin x, points[k].y, imgZmStand[index[k]]);if (count 10) {index[k] (index[k] 1) % 11;}}if (count 10)count 0;EndBatchDraw();Sleep(5);}for (int i 0; i 100; i) {BeginBatchDraw();putimage(xMin, 0, imgBg);for (int j 0; j 9; j) {putimagePNG(points[j].x, points[j].y, imgZmStand[index[j]]);index[j] (index[j] 1) % 11;}EndBatchDraw();Sleep(20);}for (int x xMin; x -112; x 4) { BeginBatchDraw();putimage(x, 0, imgBg);count;for (int k 0; k 9; k) {putimagePNG(points[k].x - xMin x, points[k].y, imgZmStand[index[k]]);if (count 10) {index[k] (index[k] 1) % 11;}if (count 10)count 0;}EndBatchDraw();Sleep(5);}
}游戏中状态栏下滑实现 void barsDown() {IMAGE imgMenu, imgDaiFu1;int height imgBar.getheight();for (int y -height; y 0; y) {BeginBatchDraw();putimage(-112, 0, imgBg);putimagePNG(250, y, imgBar);for (int i 0; i ZHI_WU_COUNT; i) {int x 338 i * 65;putimagePNG(x, 6 y, imgCards[i]);}EndBatchDraw();Sleep(9);}loadimage(imgMenu, res/Maculk.png);loadimage(imgDaiFu1, res/a.png);putimagePNG(180, 117, imgMenu);putimagePNG(0, 100, imgDaiFu1);mciSendString(play res/audio/crazydaveshort2.mp3, 0, 0, 0);Sleep(2000);mciSendString(play res/audio/crazydavelong1.mp3, 0, 0, 0);Sleep(3000);
}游戏输赢的判断 bool checkOver() {BeginBatchDraw();bool ret false;if (gameStatus WIN) {Sleep(100);mciSendString(close res/audio/Mountains.mp3 , 0, 0, 0);loadimage(0, res/gameWin.png);mciSendString(play res/win.mp3, 0, 0, 0);ret true;}else if (gameStatus FAIL) {Sleep(100);mciSendString(close res/audio/Mountains.mp3 , 0, 0, 0);loadimage(0, res/gameFail.png);mciSendString(play res/lose.mp3, 0, 0, 0);ret true;}EndBatchDraw();return ret;
} 用户的鼠标操作 左键点击移动目标植物到指定位置 点击右键进行种植 void userClick() {static int status 0;ExMessage msg;if (peekmessage(msg)) { //判断用户是否有操作if (msg.message WM_LBUTTONDOWN) { //鼠标左键按下if (msg.x 343 msg.x 343 65 * ZHI_WU_COUNT msg.y 96) { int index (msg.x - 343) / 65;//判断阳光值是否足够购买植物if (index XIANG_RI_KUI) {if (sunShine 50) {status 1;curZhiWu index 1;curX msg.x;curY msg.y;sunShine - 50;}}else if (index WAN_DAO) {if (sunShine 100) {status 1;curZhiWu index 1;curX msg.x;curY msg.y;sunShine - 100;}}else if (index JIAN_GUO) {if (sunShine 50) {status 1;curZhiWu index 1;curX msg.x;curY msg.y;sunShine - 50;}}}else { //收集阳光事件collectSunshine(msg);}}else if (msg.message WM_MOUSEMOVE status 1) { //鼠标移动curX msg.x;curY msg.y;}else if (msg.message WM_RBUTTONDOWN status 1) { //鼠标右键按下种植if (msg.x 256 - 112 msg.x 900 - 30 msg.y 179 msg.y 489) {mciSendString(play res/audio/plantdown.mp3, 0, 0, 0);int row (msg.y - 179) / 102; //获取行int col (msg.x - 256 112) / 81; //获取列if (map[row][col].type 0) {map[row][col].type curZhiWu; //给鼠标当前行种下植物map[row][col].frameIndex 0; //渲染植物第一帧map[row][col].shootTimer 0; //初始化发射时间map[row][col].x 256 - 112 col * 81; //植物坐标map[row][col].y 179 row * 102 14;}}//使植物释放消失curZhiWu 0;status 0;}}
} main主菜单 int main(void) {gameInit(); //游戏初始化startUI(); //加载游戏开始界面viewScence(); //场景巡场mciSendString(play res/audio/Mountains.mp3, 0, 0, 0);barsDown(); //状态栏下滑int timer 0;bool flag true;while (1){userClick(); //获取用户点击事件timer getDelay(); //获取间隔时间if (timer 20) { //用来限制植物渲染时间timer 0;flag true;}if (flag) {flag false;updateWindow(); //更新游戏窗口updateGame(); //更新动作if (checkOver())break; //检查游戏是否结束}}system(pause);
} 代码的整体实现 #includestdio.h
#includegraphics.h
#includetools.h
#includectime
#includetime.h
#includemath.h
#includevector2.h
#includemmsystem.h
#pragma comment(lib,winmm.lib)
enum { WAN_DAO, XIANG_RI_KUI, JIAN_GUO, ZHI_WU_COUNT };
enum { SUNSHINE_DOWN, SUNSHINE_GROUND, SUNSHINE_COLLECT, SUNSHINE_PRODUCT };
enum { GOING, WIN, FAIL };IMAGE imgBg;
IMAGE imgBar;
IMAGE imgCards[ZHI_WU_COUNT];
IMAGE* imgZhiWu[ZHI_WU_COUNT][20]; int curX, curY;
int curZhiWu; int killZmCount;
int zmCount;
int gameStatus; #define WIN_WIDTH 900
#define WIN_HEIGHT 600
#define ZM_MAX 10 struct zhiWu { int type; int frameIndex;int shootTimer; bool catched; int deadTimer; int x, y;int timer;
};struct sunShineBall { int x, y; int frameIndex; int destY; bool used; int timer; int xoff; int yoff; float t; vector2 p1, p2, p3, p4;vector2 pCur; float speed;int status;
};struct sunShineBall balls[10];
IMAGE imgSunShineBall[29]; struct zm { int x, y;int row;int frameIndex;bool used;int speed; int blood; bool dead; bool eating;
};struct zm zms[10];
IMAGE imgZm[22];
IMAGE imgZmDead[20];
IMAGE imgZmEat[21];
IMAGE imgZmStand[11];struct bullet { int x, y, row, speed;bool used;bool blast; int frameIndex;
};struct bullet bullets[30];
IMAGE imgBulletNormal;
IMAGE imgBulletBlast[4];int ballMax sizeof(balls) / sizeof(balls[0]); int zmMax sizeof(zms) / sizeof(zms[0]); int bulletMax sizeof(bullets) / sizeof(bullets[0]); struct zhiWu map[3][9];
int sunShine; void gameInit();void startUI();void viewScence();void barsDown();void updateWindow();void userClick();bool fileExist(const char* name);void updateGame();bool checkOver();void createSunShine();void updateSunShine();void collectSunshine(ExMessage* msg);void createZm();void updateZm();void createBullets();void updateBullets();void collisionCheck();void checkBullettoZm();void checkZmtoZhiWu();int main(void) {gameInit(); startUI(); viewScence(); mciSendString(play res/audio/Mountains.mp3, 0, 0, 0);barsDown(); int timer 0;bool flag true;while (1){userClick(); timer getDelay(); if (timer 20) { timer 0;flag true;}if (flag) {flag false;updateWindow(); updateGame(); if (checkOver())break; }}system(pause);
}void gameInit() {srand(time(NULL));loadimage(imgBg, res/bg.jpg);loadimage(imgBar, res/bar5.png);killZmCount 0;zmCount 0;gameStatus GOING;memset(imgZhiWu, 0, sizeof(imgZhiWu));memset(map, 0, sizeof(map)); memset(balls, 0, sizeof(balls)); memset(zms, 0, sizeof(zms)); memset(bullets, 0, sizeof(bullets)); char name[64];for (int i 0; i ZHI_WU_COUNT; i) {sprintf_s(name, sizeof(name), res/Cards/card_%d.png, i 1);loadimage(imgCards[i], name);for (int j 0; j 20; j) { sprintf_s(name, sizeof(name), res/zhiwu/%d/%d.png, i, j 1);if (fileExist(name)) {imgZhiWu[i][j] new IMAGE;loadimage(imgZhiWu[i][j], name);}else {break;}}}curZhiWu 0;sunShine 50;for (int i 0; i 29; i) { sprintf_s(name, sizeof(name), res/sunshine/%d.png, i 1);loadimage(imgSunShineBall[i], name);}for (int i 0; i 22; i) {sprintf_s(name, sizeof(name), res/zm/%d.png, i 1);loadimage(imgZm[i], name);}for (int i 0; i 20; i) {sprintf_s(name, sizeof(name), res/zm_dead/%d.png, i 1);loadimage(imgZmDead[i], name);}for (int i 0; i 21; i) {sprintf_s(name, sizeof(name), res/zm_eat/%d.png, i 1);loadimage(imgZmEat[i], name);}for (int i 0; i 11; i) {sprintf_s(name, sizeof(name), res/zm_stand/%d.png, i 1);loadimage(imgZmStand[i], name);}loadimage(imgBulletNormal, res/bullets/bullet_normal.png);loadimage(imgBulletBlast[3], res/bullets/bullet_blast.png);for (int i 0; i 3; i) {float k (i 2) * 0.2;loadimage(imgBulletBlast[i], res/bullets/bullet_blast.png,imgBulletBlast[3].getwidth() * k, imgBulletBlast[3].getheight() * k, true);}initgraph(WIN_WIDTH, WIN_HEIGHT); LOGFONT f;gettextstyle(f);f.lfHeight 30;f.lfWeight 15;strcpy(f.lfFaceName, Segoe UI Black);f.lfQuality ANTIALIASED_QUALITY; settextstyle(f);setbkmode(TRANSPARENT); setcolor(BLACK); }void startUI() {mciSendString(play res/audio/bg.mp3, 0, 0, 0);IMAGE imgMenu, imgMenu1, imgMenu2;int flag 0;loadimage(imgMenu, res/menu.png); loadimage(imgMenu1, res/menu1.png);loadimage(imgMenu2, res/menu2.png);while (1) {BeginBatchDraw();putimage(0, 0, imgMenu); putimagePNG(474, 75, flag 0 ? imgMenu1 : imgMenu2);ExMessage msg;if (peekmessage(msg)) {if (msg.message WM_LBUTTONDOWN msg.x 474 msg.x 774 msg.y75 msg.y 215) {flag 1;mciSendString(play res/audio/awooga.mp3, 0, 0, 0);}}else if (msg.message WM_LBUTTONUP flag 1) { mciSendString(close res/audio/bg.mp3, 0, 0, 0);EndBatchDraw();return;}EndBatchDraw();}
}void viewScence() {int xMin WIN_WIDTH - imgBg.getwidth();vector2 points[9] { {550,80},{530,160},{630,170},{530,200},{525,270}, {565,370},{605,340},{705,280},{690,340} };int index[9];for (int i 0; i 9; i) {index[i] rand() % 11;}int count 0;for (int x 0; x xMin; x - 4) {BeginBatchDraw();putimage(x, 0, imgBg);count;for (int k 0; k 9; k) {putimagePNG(points[k].x - xMin x, points[k].y, imgZmStand[index[k]]);if (count 10) {index[k] (index[k] 1) % 11;}}if (count 10)count 0;EndBatchDraw();Sleep(5);}for (int i 0; i 100; i) {BeginBatchDraw();putimage(xMin, 0, imgBg);for (int j 0; j 9; j) {putimagePNG(points[j].x, points[j].y, imgZmStand[index[j]]);index[j] (index[j] 1) % 11;}EndBatchDraw();Sleep(20);}for (int x xMin; x -112; x 4) { BeginBatchDraw();putimage(x, 0, imgBg);count;for (int k 0; k 9; k) {putimagePNG(points[k].x - xMin x, points[k].y, imgZmStand[index[k]]);if (count 10) {index[k] (index[k] 1) % 11;}if (count 10)count 0;}EndBatchDraw();Sleep(5);}
}void barsDown() {IMAGE imgMenu, imgDaiFu1;int height imgBar.getheight();for (int y -height; y 0; y) {BeginBatchDraw();putimage(-112, 0, imgBg);putimagePNG(250, y, imgBar);for (int i 0; i ZHI_WU_COUNT; i) {int x 338 i * 65;putimagePNG(x, 6 y, imgCards[i]);}EndBatchDraw();Sleep(9);}loadimage(imgMenu, res/Maculk.png);loadimage(imgDaiFu1, res/a.png);putimagePNG(180, 117, imgMenu);putimagePNG(0, 100, imgDaiFu1);mciSendString(play res/audio/crazydaveshort2.mp3, 0, 0, 0);Sleep(2000);mciSendString(play res/audio/crazydavelong1.mp3, 0, 0, 0);Sleep(3000);
}void updateWindow() {BeginBatchDraw();putimage(-112, 0, imgBg); putimagePNG(255, 0, imgBar); for (int i 0; i ZHI_WU_COUNT; i) { int x 343 i * 65;int y 6;putimagePNG(x, y, imgCards[i]);}for (int i 0; i 3; i) {for (int j 0; j 9; j) {if (map[i][j].type 0) {int zhiWuType map[i][j].type - 1;int index map[i][j].frameIndex;putimagePNG(map[i][j].x, map[i][j].y, imgZhiWu[zhiWuType][index]);}}}if (curZhiWu 0) {IMAGE* img imgZhiWu[curZhiWu - 1][0];putimagePNG(curX - img-getwidth() / 2, curY - img-getheight() / 2, img);}char scoreText[8];sprintf_s(scoreText, sizeof(scoreText), %d, sunShine); outtextxy(283, 67, scoreText); for (int i 0; i zmMax; i) {if (zms[i].used) {IMAGE* img NULL;if (zms[i].eating) {img imgZmEat;}else if (zms[i].dead) {img imgZmDead;}else {img imgZm;}img zms[i].frameIndex;putimagePNG(zms[i].x, zms[i].y - img-getheight(), img);}}for (int i 0; i bulletMax; i) {if (bullets[i].used) {if (bullets[i].blast) { IMAGE* img imgBulletBlast[bullets[i].frameIndex];putimagePNG(bullets[i].x, bullets[i].y, img);FlushBatchDraw();}else { putimagePNG(bullets[i].x, bullets[i].y, imgBulletNormal);}}}for (int i 0; i ballMax; i) {if (balls[i].used ) {IMAGE* img imgSunShineBall[balls[i].frameIndex];putimagePNG(balls[i].pCur.x, balls[i].pCur.y, img);}}EndBatchDraw();
}void userClick() {static int status 0;ExMessage msg;if (peekmessage(msg)) { if (msg.message WM_LBUTTONDOWN) { if (msg.x 343 msg.x 343 65 * ZHI_WU_COUNT msg.y 96) { int index (msg.x - 343) / 65;if (index XIANG_RI_KUI) {if (sunShine 50) {status 1;curZhiWu index 1;curX msg.x;curY msg.y;sunShine - 50;}}else if (index WAN_DAO) {if (sunShine 100) {status 1;curZhiWu index 1;curX msg.x;curY msg.y;sunShine - 100;}}else if (index JIAN_GUO) {if (sunShine 50) {status 1;curZhiWu index 1;curX msg.x;curY msg.y;sunShine - 50;}}}else { collectSunshine(msg);}}else if (msg.message WM_MOUSEMOVE status 1) { curX msg.x;curY msg.y;}else if (msg.message WM_RBUTTONDOWN status 1) { if (msg.x 256 - 112 msg.x 900 - 30 msg.y 179 msg.y 489) {mciSendString(play res/audio/plantdown.mp3, 0, 0, 0);int row (msg.y - 179) / 102; int col (msg.x - 256 112) / 81; if (map[row][col].type 0) {map[row][col].type curZhiWu; map[row][col].frameIndex 0; map[row][col].shootTimer 0; map[row][col].x 256 - 112 col * 81; map[row][col].y 179 row * 102 14;}}curZhiWu 0;status 0;}}
}bool fileExist(const char* name) {FILE* fp fopen(name, r);if (fp NULL) {return false;}else {fclose(fp);return true;}
}void updateGame() {for (int i 0; i 3; i) {for (int j 0; j 9; j) {if (map[i][j].type 0) {map[i][j].frameIndex;int zhiWuType map[i][j].type - 1;int index map[i][j].frameIndex;if (imgZhiWu[zhiWuType][index] NULL) {map[i][j].frameIndex 0;}}}}createZm();updateZm();createSunShine();updateSunShine();createBullets(); updateBullets();collisionCheck();
}bool checkOver() {BeginBatchDraw();bool ret false;if (gameStatus WIN) {Sleep(100);mciSendString(close res/audio/Mountains.mp3 , 0, 0, 0);loadimage(0, res/gameWin.png);mciSendString(play res/win.mp3, 0, 0, 0);ret true;}else if (gameStatus FAIL) {Sleep(100);mciSendString(close res/audio/Mountains.mp3 , 0, 0, 0);loadimage(0, res/gameFail.png);mciSendString(play res/lose.mp3, 0, 0, 0);ret true;}EndBatchDraw();return ret;
}void createSunShine() {static int count 0;static int fre 200;count;if (count fre) { fre 100 rand() % 150;count 0;int i;for (i 0; i ballMax balls[i].used; i); if (i ballMax)return;balls[i].used true;balls[i].frameIndex 0;balls[i].timer 0;balls[i].status SUNSHINE_DOWN;balls[i].t 0;balls[i].p1 vector2(260 - 112 rand() % (900 - 320 112), 60);balls[i].p4 vector2(balls[i].p1.x, 200 (rand() % 4) * 90);int off 2;float distance balls[i].p4.y - balls[i].p1.y;balls[i].speed 1.0 / (distance / off);}for (int i 0; i 3; i) {for (int j 0; j 9; j) {if (map[i][j].type XIANG_RI_KUI 1) {map[i][j].timer;if (map[i][j].timer 200) {map[i][j].timer 0;int k;for (k 0; k ballMax balls[k].used; k);if (k ballMax)return;balls[k].used true;balls[k].p1 vector2(map[i][j].x, map[i][j].y); int w (50 rand() % 51) * (rand() % 2 ? 1 : -1);balls[k].p4 vector2(map[i][j].x w, map[i][j].y imgZhiWu[XIANG_RI_KUI][0]-getheight()- imgSunShineBall-getheight());balls[k].p2 vector2(balls[k].p1.x w * 0.3, balls[k].p1.y - 100);balls[k].p3 vector2(balls[k].p1.x w * 0.7, balls[k].p1.y - 150);balls[k].status SUNSHINE_PRODUCT;balls[k].speed 0.05;balls[k].t 0;}}}}
}void updateSunShine() {for (int i 0; i ballMax; i) {if (balls[i].used) {balls[i].frameIndex (balls[i].frameIndex 1) % 29; if (balls[i].status SUNSHINE_DOWN) {struct sunShineBall* sun balls[i];sun-t sun-speed;sun-pCur sun-p1 sun-t * (sun-p4 - sun-p1);if (sun-t 1) {sun-status SUNSHINE_GROUND;sun-t 0;sun-timer 0;}}else if (balls[i].status SUNSHINE_GROUND) {balls[i].timer;if (balls[i].timer 100) {balls[i].used false;balls[i].timer 0;}}else if (balls[i].status SUNSHINE_COLLECT) {struct sunShineBall* sun balls[i];sun-t sun-speed;sun-pCur sun-p1 sun-t * (sun-p4 - sun-p1);if (sun-t 1) {sunShine 25;sun-used false;sun-t 0;}}else if (balls[i].status SUNSHINE_PRODUCT) {struct sunShineBall* sun balls[i];sun-t sun-speed;sun-pCur calcBezierPoint(sun-t, sun-p1, sun-p2, sun-p3, sun-p4);if (sun-t 1) {sun-status SUNSHINE_GROUND;sun-t 0;sun-timer 0;}}}}
}void collectSunshine(ExMessage* msg) {int w imgSunShineBall[0].getwidth(); int h imgSunShineBall[0].getheight(); for (int i 0; i ballMax; i) {if (balls[i].used) { int x balls[i].pCur.x;int y balls[i].pCur.y;if (msg-x x msg-xx w msg-yy msg-y y h) {balls[i].status SUNSHINE_COLLECT;mciSendString(play res/sunshine.mp3, 0, 0, 0);balls[i].p1 balls[i].pCur;balls[i].p4 vector2(262, 0);balls[i].t 0;float distance dis(balls[i].p1 - balls[i].p4);float off 8;balls[i].speed 1.0 / (distance / off);break;}}}
}void createZm()
{if (zmCount ZM_MAX) {return;}static int count 0;static int zmFre 500;count;if (count zmFre) { zmFre 300 rand() % 200; count 0;int i;for (i 0; i zmMax zms[i].used; i); if (i zmMax)return;zms[i].used true;zms[i].x WIN_WIDTH;zms[i].row rand() % 3;zms[i].y 172 (zms[i].row 1) * 100;zms[i].speed 1;zms[i].blood 200;zms[i].dead false;zms[i].eating false;zmCount;}
}void updateZm() {static int count 0;count;if (count 2) { count 0;for (int i 0; i zmMax; i) {if (zms[i].used) {zms[i].x - zms[i].speed;if (zms[i].x 48) {gameStatus FAIL;}}}}static int count2 0;count2;if (count2 4) { count2 0;for (int i 0; i zmMax; i) {if (zms[i].used) {if (zms[i].dead) {zms[i].frameIndex;if (zms[i].frameIndex 20) {zms[i].used false;killZmCount;if (killZmCount ZM_MAX) {gameStatus WIN;}}}else if (zms[i].eating) {zms[i].frameIndex (zms[i].frameIndex 1) % 20;}else{zms[i].frameIndex (zms[i].frameIndex 1) % 21; }}}}
}void createBullets() {int lines[3] { 0 };int dangerX WIN_WIDTH - imgZm[0].getwidth() 50; for (int i 0; i zmMax; i) {if (zms[i].used zms[i].x dangerX) {lines[zms[i].row] 1; }}for (int i 0; i 3; i) { for (int j 0; j 9; j) {if (lines[i] map[i][j].type 1) { map[i][j].shootTimer;if (map[i][j].shootTimer 20) {map[i][j].shootTimer 0;int k;PlaySound(res/audio/shootpea1.wav, NULL, SND_FILENAME | SND_ASYNC);for (k 0; k bulletMax bullets[k].used; k);if (k bulletMax) return;bullets[k].used true; bullets[k].row i;bullets[k].speed 5;bullets[k].blast false;bullets[k].frameIndex 0;int zwX 256 - 112 j * 81;int zwY 179 i * 102 14;bullets[k].x zwX imgZhiWu[0][0]-getwidth() - 10;bullets[k].y zwY 5;lines[i] 0;}}}}
}void updateBullets() {for (int i 0; i bulletMax; i) {if (bullets[i].used) {bullets[i].x bullets[i].speed;if (bullets[i].x WIN_WIDTH) {bullets[i].used false;}if (bullets[i].blast) {bullets[i].frameIndex;if (bullets[i].frameIndex 3) {bullets[i].used false;}}}}
}void collisionCheck() {checkBullettoZm();checkZmtoZhiWu();
}
void checkBullettoZm() {for (int i 0; i bulletMax; i) {if (bullets[i].used false || bullets[i].blast)continue; for (int j 0; j zmMax; j) {if (zms[j].used false)continue;int x1 zms[j].x 80;int x2 zms[j].x 110;int x bullets[i].x;if (zms[j].dead false bullets[i].row zms[j].row x x1 x x2) { PlaySound(res/audio/peacrush1.wav, NULL, SND_FILENAME | SND_ASYNC);zms[j].blood - 10;bullets[i].blast true;bullets[i].speed 0;if (zms[j].blood 0) {zms[j].dead true;zms[j].speed 0;zms[j].frameIndex 0;}break;}}}
}void checkZmtoZhiWu() {for (int i 0; i zmMax; i) {if (zms[i].dead)continue;int row zms[i].row;for (int k 0; k 9; k) {if (map[row][k].type 0)continue;int zhiWuX 256 - 112 k * 81; int x1 zhiWuX 10;int x2 zhiWuX 60;int x3 zms[i].x 80;if (x3 x1 x3 x2) {if (map[row][k].catched true) {map[row][k].deadTimer;mciSendString(play res/audio/zmeat.mp3, 0, 0, 0);if (map[row][k].deadTimer 100) {mciSendString(play res/audio/plantDead.mp3, 0, 0, 0);map[row][k].deadTimer 0;map[row][k].type 0;zms[i].eating false;zms[i].frameIndex 0;zms[i].speed 1;}}else {map[row][k].catched true;map[row][k].deadTimer 0;zms[i].eating true;zms[i].speed 0;zms[i].frameIndex 0;}}}}
}