一.项目介绍
目前只完成了
/*
* 开发日志
* 1.创建新项目(空白项目模板)使用VS2019
* 2.导入素材
* 3.实现最开始的游戏场景
* 4.实现游戏顶部的工具栏
* 5.实现工具栏中的植物卡牌
* 6.植物卡牌的选择与拖动
* 7.植物的种植
* 8.植物的摇摆
* 9.制作启动菜单
* 10.创建随机阳光
* 11.收集阳光,显示阳光值
* 12.创建僵尸
*/
在创建僵尸这里出现了bug,僵尸每走到草坪中间就会消失,目前bug
还没解决,等以后有时间了再完成后续工作。
二.创建主场景
新建项目--植物大战僵尸
导入素材(素材会新发一个文件)
新建res文件,将解压后的素材移入res中
把解压后的素材中的两个工具文件放到外面
安装EasyX图形库
1.打开官网EasyX Graphics Library for C++
2.点击“下载 EasyX”
3.直接打开安装包,跟随指令安装即可
4.判断是否安装成功
打开VS
新建一个“空项目”或者“控制台项目”
输入:
#include
#include
int main()
{
initgraph(640, 480); // 创建绘图窗口,大小为 640x480 像素
circle(200, 200, 100); // 画圆,圆心(200, 200),半径 100
_getch(); // 按任意键继续
closegraph(); // 关闭绘图窗口
}
黑窗口上出现了一个圆,代表安装成功
实现最开始的游戏场景:
#include
#include
#define WIN_WIDTH 900 //窗口宽度
#define WIN_HEIGHT 600 //窗口高度
IMAGE imgBg; //表示背景图片
//游戏初始化
void gameInit() {
/*加载游戏背景图片
* 背景图片有两种加载方式
* 1.直接把背景图片打印到窗口里,这种方式会比较慢
* 2.把背景图片先放到内存变量里面去,再从变量里面显示就很快
* 使用第二种方式
*/
//把字符集修改为”多字节字符集“
loadimage(&imgBg, "res/bg.jpg"); //背景图片加载到变量 ""里是素材的路径
//创建游戏的图形窗口
initgraph(WIN_WIDTH, WIN_HEIGHT);
}
//更新窗口
void updateWindow() {
putimage(0,0,&imgBg); //把图片渲染出来
}
int main()
{
gameInit();
updateWindow();
system("pause");
return 0;
}
三.实现植物卡牌
将两个工具导入项目中,使用其接口
#include
#include
#include"tools.h"
#define WIN_WIDTH 900 //窗口宽度
#define WIN_HEIGHT 600 //窗口高度
enum {WAN_DOU , XIANG_RI_KUI , ZHI_WU_COUNT};
IMAGE imgBg; //表示背景图片
IMAGE imgBar; //植物卡牌工具栏
IMAGE imgCards[ZHI_WU_COUNT]; //植物卡牌
//游戏初始化
void gameInit() {
/*加载游戏背景图片
* 背景图片有两种加载方式
* 1.直接把背景图片打印到窗口里,这种方式会比较慢
* 2.把背景图片先放到内存变量里面去,再从变量里面显示就很快
* 使用第二种方式
*/
//把字符集修改为”多字节字符集“
loadimage(&imgBg, "res/bg.jpg"); //背景图片加载到变量 ""里是素材的路径
loadimage(&imgBar, "res/bar.png");
//初始化植物卡牌
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);
}
//创建游戏的图形窗口
initgraph(WIN_WIDTH, WIN_HEIGHT);
}
//更新窗口
void updateWindow() {
putimage(0,0,&imgBg); //把图片渲染出来
//putimage(250,0,&imgBar);
putimagePNG(250, 0, &imgBar); //背景透明化
for (int i = 0; i < ZHI_WU_COUNT; i++) {
int x = 338 + i * 65;
int y = 6;
putimage(x, y, &imgCards[i]);
}
}
四.实现植物的选择与拖动
关掉SDL检查
IMAGE imgCards[ZHI_WU_COUNT]; //植物卡牌
IMAGE* imgZhiWu[ZHI_WU_COUNT][20];
int curX, curY; //当前选中的植物,在移动过程中的位置
int curZhiWu; // 0 : 没有选中, 1 :选中了第一种植物
bool fileExist(const char* name) {
FILE* fp = fopen(name, "r");
if (fp == NULL) {
return false;
}
else {
fclose(fp);
return true;
}
}
//游戏初始化
void gameInit() {
/*加载游戏背景图片
* 背景图片有两种加载方式
* 1.直接把背景图片打印到窗口里,这种方式会比较慢
* 2.把背景图片先放到内存变量里面去,再从变量里面显示就很快
* 使用第二种方式
*/
//把字符集修改为”多字节字符集“
loadimage(&imgBg, "res/bg.jpg"); //背景图片加载到变量 ""里是素材的路径
loadimage(&imgBar, "res/bar.png");
memset(imgZhiWu, 0, sizeof(imgZhiWu));//初始化
//初始化植物卡牌
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; //初始化
//创建游戏的图形窗口
initgraph(WIN_WIDTH, WIN_HEIGHT,1);
}
//更新窗口
void updateWindow() {
BeginBatchDraw(); //开始缓冲
putimage(0,0,&imgBg); //把图片渲染出来
//putimage(250,0,&imgBar);
putimagePNG(250, 0, &imgBar); //背景透明化
for (int i = 0; i < ZHI_WU_COUNT; i++) {
int x = 338 + i * 65;
int y = 6;
putimage(x, y, &imgCards[i]);
}
//渲染 拖动过程中的植物
if (curZhiWu > 0) {
putimage(curX, curY, imgZhiWu[curZhiWu - 1][0]);
}
EndBatchDraw(); //结束缓冲
}
//点击
void userClick() {
ExMessage msg;
static int status = 0; //判断拖动状态还是选择状态
if (peekmessage(&msg)) {//判断有没有消息
if (msg.message == WM_LBUTTONDOWN) {//如果是左键按下
//判断单击位置对不对,只有点击卡牌区域才响应
if (msg.x > 338 && msg.x < 338 + 65 * ZHI_WU_COUNT && msg.y < 96) {
int index = (msg.x - 338) / 65;//判断点击的是哪张卡牌
status = 1; //选择状态
curZhiWu = index + 1;
}
}
else if (msg.message == WM_MOUSEMOVE && status == 1) { //如果是鼠标移动
curX = msg.x;
curY = msg.y;
}
else if (msg.message == WM_LBUTTONUP) { //如果左键抬起来
}
}
}
可以拖动,但是有两个问题
1.拖动的植物是黑色背景,太丑陋
渲染改成PNG版本的:
//渲染 拖动过程中的植物
if (curZhiWu > 0) {
putimage(curX, curY, imgZhiWu[curZhiWu - 1][0]);
}
改成
//渲染 拖动过程中的植物
if (curZhiWu > 0) {
putimagePNG(curX, curY, imgZhiWu[curZhiWu - 1][0]);
}
2.光标显示在植物的左上角,应该让它显示在植物的正中央
渲染的位置作下改动
if (curZhiWu > 0) {
putimagePNG(curX, curY, imgZhiWu[curZhiWu - 1][0]);
}
改成:
//渲染 拖动过程中的植物
if (curZhiWu > 0) {
IMAGE* img = imgZhiWu[curZhiWu - 1][0];
putimagePNG(curX - img->getwidth() / 2, curY - img->getheight() / 2, img);
}
五.实现植物的种植
int curX, curY; //当前选中的植物,在移动过程中的位置
int curZhiWu; // 0 : 没有选中, 1 :选中了第一种植物
struct zhiwu {
int type; //0:没有植物; 1: 第一种植物
int frameIndex; //序列帧的序号
};
struct zhiwu map[3][9]; //地图
bool fileExist(const char* name) {
FILE* fp = fopen(name, "r");
if (fp == NULL) {
return false;
}
else {
fclose(fp);
return true;
}
}
//游戏初始化
void gameInit() {
/*加载游戏背景图片
* 背景图片有两种加载方式
* 1.直接把背景图片打印到窗口里,这种方式会比较慢
* 2.把背景图片先放到内存变量里面去,再从变量里面显示就很快
* 使用第二种方式
*/
//把字符集修改为”多字节字符集“
loadimage(&imgBg, "res/bg.jpg"); //背景图片加载到变量 ""里是素材的路径
loadimage(&imgBar, "res/bar.png");
memset(imgZhiWu, 0, sizeof(imgZhiWu));//初始化
memset(map, 0, sizeof(map));
//初始化植物卡牌
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; //初始化
//创建游戏的图形窗口
initgraph(WIN_WIDTH, WIN_HEIGHT,1);
}
//更新窗口
void updateWindow() {
BeginBatchDraw(); //开始缓冲
putimage(0,0,&imgBg); //把图片渲染出来
//putimage(250,0,&imgBar);
putimagePNG(250, 0, &imgBar); //背景透明化
for (int i = 0; i < ZHI_WU_COUNT; i++) {
int x = 338 + i * 65;
int y = 6;
putimage(x, y, &imgCards[i]);
}
//渲染 拖动过程中的植物
if (curZhiWu > 0) {
IMAGE* img = imgZhiWu[curZhiWu - 1][0];
putimagePNG(curX - img->getwidth() / 2, curY - img->getheight() / 2, img);
}
//种下植物
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 9; j++) {
if (map[i][j].type > 0) {
int x = 256 + j * 81;
int y = 179 + i * 102 + 14;
int zhiWuType = map[i][j].type - 1;
int index = map[i][j].frameIndex;
putimagePNG(x, y, imgZhiWu[zhiWuType][index]);
}
}
}
EndBatchDraw(); //结束缓冲
}
//点击
void userClick() {
ExMessage msg;
static int status = 0; //判断拖动状态还是选择状态
if (peekmessage(&msg)) {//判断有没有消息
if (msg.message == WM_LBUTTONDOWN) {//如果是左键按下
//判断单击位置对不对,只有点击卡牌区域才响应
if (msg.x > 338 && msg.x < 338 + 65 * ZHI_WU_COUNT && msg.y < 96) {
int index = (msg.x - 338) / 65;//判断点击的是哪张卡牌
status = 1; //选择状态
curZhiWu = index + 1;
}
}
else if (msg.message == WM_MOUSEMOVE && status == 1) { //如果是鼠标移动
curX = msg.x;
curY = msg.y;
}
else if (msg.message == WM_LBUTTONUP) { //如果左键抬起来
if (msg.x > 256 && msg.y > 179 && msg.y < 489) {
int row = (msg.y - 179) / 102;
int col = (msg.x - 256) / 81;
//printf("%d,%d\n", row, col);
if (map[row][col].type == 0) {
map[row][col].type = curZhiWu;
map[row][col].frameIndex = 0;
}
}
curZhiWu = 0;
status = 0;
}
}
}
六.实现植物的摇摆
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;
}
}
}
}
}
七.优化游戏循环和游戏渲染顺序
不使用sleep(),使游戏循环衔接的很好。
int timer = 0;
bool flag = true;
while (1) {
userClick();
timer += getDelay();
if (timer > 20) {
flag = true;
timer = 0;
}
if (flag) {
flag = false;
updateWindow();
updateGame();
}
八.制作启动菜单
//启动菜单
void startUI() {
IMAGE imgBg, imgMenu1, imgMenu2;
loadimage(&imgBg, "res/menu.png");
loadimage(&imgMenu1, "res/menu1.png");
loadimage(&imgMenu2, "res/menu2.png");
int flag = 0;
while (1) {
BeginBatchDraw();
putimage(0, 0, &imgBg);
putimagePNG(474, 75, flag ? &imgMenu2 : &imgMenu2);
ExMessage msg;
if (peekmessage(&msg)) {
if (msg.message == WM_LBUTTONDOWN &&
msg.x > 474 && msg.x < 474 + 300 && msg.y>75 && msg.y < 75 + 140) {
flag = 1;
}
else if (msg.message == WM_LBUTTONUP && flag ) {
return;
}
}
EndBatchDraw();
}
}
九.创建随机阳光
//阳光
/*
* 阳光旋转着落下
其动画通过播放很多张旋转的图片来实现,图片循环着播放,显示
阳光是垂直飘下的,只需确定y轴坐标即可,x轴坐标不变
*/
struct sunshineBall {
int x, y; //阳光球在飘落过程中的位置变化
int frameIndex; //当前显示的图片帧的序号
int destY; //飘落的目标位置的y坐标
int used; //是否在使用
};
/*
* 预先准备一个阳光池,需要生产阳光时,从里面取出一个阳光,用完之后,再归还进池子
*/
//阳光池
struct sunshineBall balls[10];
//存储阳光球照片的数组
IMAGE imgSunshineBall[29];
//创建阳光
void createSunshine() {
static int count = 0; //函数的调用次数
static int fre = 400;
count++;
if (count >= fre) { //调用xx次才生成阳光
fre = 200 + rand() % 200;
count = 0;
//从阳光池中取一个可以使用的
int ballMax = sizeof(balls) / sizeof(balls[0]);
int i;
for (int i = 0; i < ballMax && balls[i].used; i++);
if (i >= ballMax) {
return;
}
balls[i].used = true;
balls[i].frameIndex = 0;
balls[i].x = rand() % (900 - 260); //260..900 阳光飘落的区域
balls[i].y = 60;
balls[i].destY = 200 + (rand() % 4) * 90;
}
十.显示随机阳光
//更新阳光状态
void updateSunshine() {
int ballMax = sizeof(balls) / sizeof(balls[0]);
for (int i = 0; i < ballMax; i++) {
if (balls[i].used) {
balls[i].frameIndex = (balls[i].frameIndex + 1) % 29;
if (balls[i].timer == 0) {
balls[i].y += 2;
}
if (balls[i].y >= balls[i].destY) {
//balls[i].used = false;
balls[i].timer++;
if (balls[i].timer > 100) {//定时器加到100时,才让阳光球消失,模拟阳光在草坪上停留的时间
balls[i].used = false;
}
}
}
}
}
十一.收集阳光,显示阳光值
//设置阳光初始值
int sunshine;
//设置字体
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 collectSunshine(ExMessage* msg) {
int count = sizeof(balls) / sizeof(balls[0]);
int w = imgSunshineBall[0].getwidth();
int h = imgSunshineBall[0].getheight();
for (int i = 0; i < count; i++) {
if (balls[i].used) {
int x = balls[i].x;
int y = balls[i].y;
if (msg->x > x && msg->x
balls[i].used = false;
sunshine += 25;
//播放音效
mciSendString("play res/bg.MP3", 0, 0, 0);
}
}
}
}
十二.创建僵尸
//定义僵尸
struct zm {
int x, y;
int frameIndex;
bool used;
int speed;
};
struct zm zms[10]; //定义10个僵尸
//僵尸图片数组
IMAGE imgZM[22];
//创建僵尸
void createZM() {
static int zmFre = 500;
static int count = 0;
count++;
if (count > zmFre) {
count = 0;
zmFre = rand() % 200 + 300;
int i = 0;
int zmMax = sizeof(zms) / sizeof(zms[0]);
for (int i = 0; i < zmMax && zms[i].used; i++);
if (i < zmMax) {
zms[i].used = true;
zms[i].x = WIN_WIDTH;
zms[i].y = 172 + (1 + rand() % 3) * 100;
zms[i].speed = 1;
}
}
}
//更新僵尸的状态
void updateZM() {
int zmMax = sizeof(zms) / sizeof(zms[0]);
//更新僵尸的位置
for (int i = 0; i < zmMax; i++) {
if (zms[i].used) {
zms[i].x -= zms[i].speed;
if (zms[i].x < 170) {
printf("GAME OVER\n");
MessageBox(NULL, "over", "over", 0); //待优化
exit(0); //待优化
}
}
}
}
//绘制僵尸
void drawZM() {
int zmCount = sizeof(zms) / sizeof(zms[0]);
for (int i = 0; i < zmCount; i++) {
if (zms[i].used) {
IMAGE* img = &imgZM[zms[i].frameIndex];
putimagePNG(
zms[i].x,
zms[i].y - img->getheight(),
img);
}
}
}
已编写出的源码:
/*
* 开发日志
* 1.创建新项目(空白项目模板)使用VS2019
* 2.导入素材
* 3.实现最开始的游戏场景
* 4.实现游戏顶部的工具栏
* 5.实现工具栏中的植物卡牌
* 6.植物卡牌的选择与拖动
* 7.植物的种植
* 8.植物的摇摆
* 9.制作启动菜单
* 10.创建随机阳光
* 11.收集阳光,显示阳光值
* 12.创建僵尸
*/
#include
#include
#include
#include"tools.h"
#include
#pragma comment(lib,"winmm.lib");
#define WIN_WIDTH 900 //窗口宽度
#define WIN_HEIGHT 600 //窗口高度
enum {WAN_DOU , XIANG_RI_KUI , ZHI_WU_COUNT};
IMAGE imgBg; //表示背景图片
IMAGE imgBar; //植物卡牌工具栏
IMAGE imgCards[ZHI_WU_COUNT]; //植物卡牌
IMAGE* imgZhiWu[ZHI_WU_COUNT][20];
int curX, curY; //当前选中的植物,在移动过程中的位置
int curZhiWu; // 0 : 没有选中, 1 :选中了第一种植物
struct zhiwu {
int type; //0:没有植物; 1: 第一种植物
int frameIndex; //序列帧的序号
};
struct zhiwu map[3][9]; //地图
//阳光
/*
* 阳光旋转着落下
其动画通过播放很多张旋转的图片来实现,图片循环着播放,显示
阳光是垂直飘下的,只需确定y轴坐标即可,x轴坐标不变
*/
struct sunshineBall {
int x, y; //阳光球在飘落过程中的位置变化
int frameIndex; //当前显示的图片帧的序号
int destY; //飘落的目标位置的y坐标
int used; //是否在使用
int timer;//定时器
};
/*
* 预先准备一个阳光池,需要生产阳光时,从里面取出一个阳光,用完之后,再归还进池子
*/
//阳光池
struct sunshineBall balls[10];
//存储阳光球照片的数组
IMAGE imgSunshineBall[29];
//设置阳光初始值
int sunshine;
//定义僵尸
struct zm {
int x, y;
int frameIndex;
bool used;
int speed;
};
struct zm zms[10]; //定义10个僵尸
//僵尸图片数组
IMAGE imgZM[22];
bool fileExist(const char* name) {
FILE* fp = fopen(name, "r");
if (fp == NULL) {
return false;
}
else {
fclose(fp);
return true;
}
}
//游戏初始化
void gameInit() {
/*加载游戏背景图片
* 背景图片有两种加载方式
* 1.直接把背景图片打印到窗口里,这种方式会比较慢
* 2.把背景图片先放到内存变量里面去,再从变量里面显示就很快
* 使用第二种方式
*/
//把字符集修改为”多字节字符集“
loadimage(&imgBg, "res/bg.jpg"); //背景图片加载到变量 ""里是素材的路径
loadimage(&imgBar, "res/bar.png");
memset(imgZhiWu, 0, sizeof(imgZhiWu));//初始化
memset(map, 0, sizeof(map));
//初始化植物卡牌
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 = 150; //设置阳光初始值
memset(balls, 0, sizeof(balls));
for (int i = 0; i < 29; i++) {
sprintf_s(name, sizeof(name), "res/sunshine/%d.png", i + 1);
loadimage(&imgSunshineBall[i], name);
}
//配置随机种子
srand(time(NULL));
//创建游戏的图形窗口
initgraph(WIN_WIDTH, WIN_HEIGHT,1);
//设置字体
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);
//僵尸数据初始化
memset(zms, 0, sizeof(zms));
for (int i = 0; i < 22; i++) {
sprintf_s(name, sizeof(name), "res/zm/%d.png", i + 1);
loadimage(&imgZM[i], name);
}
}
//绘制僵尸
void drawZM() {
int zmCount = sizeof(zms) / sizeof(zms[0]);
for (int i = 0; i < zmCount; i++) {
if (zms[i].used) {
IMAGE* img = &imgZM[zms[i].frameIndex];
putimagePNG(
zms[i].x,
zms[i].y - img->getheight(),
img);
}
}
}
//更新窗口
void updateWindow() {
BeginBatchDraw(); //开始缓冲
putimage(0,0,&imgBg); //把图片渲染出来
//putimage(250,0,&imgBar);
putimagePNG(250, 0, &imgBar); //背景透明化
for (int i = 0; i < ZHI_WU_COUNT; i++) {
int x = 338 + i * 65;
int y = 6;
putimage(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 x = 256 + j * 81;
int y = 179 + i * 102 + 14;
int zhiWuType = map[i][j].type - 1;
int index = map[i][j].frameIndex;
putimagePNG(x, y, imgZhiWu[zhiWuType][index]);
}
}
}
//渲染 拖动过程中的植物
if (curZhiWu > 0) {
IMAGE* img = imgZhiWu[curZhiWu - 1][0];
putimagePNG(curX - img->getwidth() / 2, curY - img->getheight() / 2, img);
}
int ballMax = sizeof(balls) / sizeof(balls[0]);
for (int i = 0; i < ballMax; i++) {
if (balls[i].used) {
IMAGE* img = &imgSunshineBall[balls[i].frameIndex];
putimagePNG(balls[i].x, balls[i].y, img);
}
}
//渲染出阳光值
char scoreText[8];
sprintf_s(scoreText, sizeof(scoreText), "%d", sunshine);
outtextxy(276, 67, scoreText);
//绘制僵尸
drawZM();
EndBatchDraw(); //结束缓冲
}
//收集阳光
void collectSunshine(ExMessage* msg) {
int count = sizeof(balls) / sizeof(balls[0]);
int w = imgSunshineBall[0].getwidth();
int h = imgSunshineBall[0].getheight();
for (int i = 0; i < count; i++) {
if (balls[i].used) {
int x = balls[i].x;
int y = balls[i].y;
if (msg->x > x && msg->x
balls[i].used = false;
sunshine += 25;
//播放音效
mciSendString("play res/sunshine.mp3", 0, 0, 0);
}
}
}
}
//点击
void userClick() {
ExMessage msg;
static int status = 0; //判断拖动状态还是选择状态
if (peekmessage(&msg)) {//判断有没有消息
if (msg.message == WM_LBUTTONDOWN) {//如果是左键按下
//判断单击位置对不对,只有点击卡牌区域才响应
if (msg.x > 338 && msg.x < 338 + 65 * ZHI_WU_COUNT && msg.y < 96) {
int index = (msg.x - 338) / 65;//判断点击的是哪张卡牌
status = 1; //选择状态
curZhiWu = index + 1;
}
else
{
//是否在收集阳光
collectSunshine(&msg);
}
}
else if (msg.message == WM_MOUSEMOVE && status == 1) { //如果是鼠标移动
curX = msg.x;
curY = msg.y;
}
else if (msg.message == WM_LBUTTONUP) { //如果左键抬起来
if (msg.x > 256 && msg.y > 179 && msg.y < 489) {
int row = (msg.y - 179) / 102;
int col = (msg.x - 256) / 81;
//printf("%d,%d\n", row, col);
if (map[row][col].type == 0) {
map[row][col].type = curZhiWu;
map[row][col].frameIndex = 0;
}
}
curZhiWu = 0;
status = 0;
}
}
}
//创建阳光
void createSunshine() {
static int count = 0; //函数的调用次数
static int fre = 400;
count++;
if (count >= fre) { //调用xx次才生成阳光
fre = 200 + rand() % 200;
count = 0;
//从阳光池中取一个可以使用的
int ballMax = sizeof(balls) / sizeof(balls[0]);
int i = 0;
for (int i = 0; i < ballMax && balls[i].used; i++);
if (i >= ballMax) {
return;
}
balls[i].used = true;
balls[i].frameIndex = 0;
balls[i].x = 260 + rand() % (900 - 260); //260..900 阳光飘落的区域
balls[i].y = 60;
balls[i].destY = 200 + (rand() % 4) * 90;
balls[i].timer = 0;
}
}
//更新阳光状态
void updateSunshine() {
int ballMax = sizeof(balls) / sizeof(balls[0]);
for (int i = 0; i < ballMax; i++) {
if (balls[i].used) {
balls[i].frameIndex = (balls[i].frameIndex + 1) % 29;
if (balls[i].timer == 0) {
balls[i].y += 2;
}
if (balls[i].y >= balls[i].destY) {
//balls[i].used = false;
balls[i].timer++;
if (balls[i].timer > 100) {//定时器加到100时,才让阳光球消失,模拟阳光在草坪上停留的时间
balls[i].used = false;
}
}
}
}
}
//创建僵尸
void createZM() {
static int zmFre = 500;
static int count = 0;
count++;
if (count > zmFre) {
count = 0;
zmFre = rand() % 200 + 300;
int i = 0;
int zmMax = sizeof(zms) / sizeof(zms[0]);
for (int i = 0; i < zmMax && zms[i].used; i++);
if (i < zmMax) {
zms[i].used = true;
zms[i].x = WIN_WIDTH;
zms[i].y = 172 + (1 + rand() % 3) * 100;
zms[i].speed = 1;
}
}
}
//更新僵尸的状态
void updateZM() {
int zmMax = sizeof(zms) / sizeof(zms[0]);
//更新僵尸的位置
for (int i = 0; i < zmMax; i++) {
if (zms[i].used) {
zms[i].x -= zms[i].speed;
if (zms[i].x < 170) {
printf("GAME OVER\n");
MessageBox(NULL, "over", "over", 0); //待优化
exit(0); //待优化
}
}
}
}
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;
}
}
}
}
createSunshine(); //创建阳光
updateSunshine();//更新阳光状态
createZM(); //创建僵尸
updateZM();//更新僵尸的状态
}
//启动菜单
void startUI() {
IMAGE imgBg, imgMenu1, imgMenu2;
loadimage(&imgBg, "res/menu.png");
loadimage(&imgMenu1, "res/menu1.png");
loadimage(&imgMenu2, "res/menu2.png");
int flag = 0;
while (1) {
BeginBatchDraw();
putimage(0, 0, &imgBg);
putimagePNG(474, 75, flag ? &imgMenu2 : &imgMenu2);
ExMessage msg;
if (peekmessage(&msg)) {
if (msg.message == WM_LBUTTONDOWN &&
msg.x > 474 && msg.x < 474 + 300 && msg.y>75 && msg.y < 75 + 140) {
flag = 1;
}
else if (msg.message == WM_LBUTTONUP && flag ) {
return;
}
}
EndBatchDraw();
}
}
int main(void)
{
gameInit();
startUI();
int timer = 0;
bool flag = true;
while (1) {
userClick();
timer += getDelay();
if (timer > 20) {
flag = true;
timer = 0;
}
if (flag) {
flag = false;
updateWindow();
updateGame();
}
//Sleep(10);
}
system("pause");
return 0;
}