C/C++实现植物大战僵尸(PVZ)(打地鼠版)
🚀欢迎互三👉:程序猿方梓燚 💎💎
🚀关注博主,后期持续更新系列文章
🚀如果有错误感谢请大家批评指出,及时修改
🚀感谢大家点赞👍收藏⭐评论✍
游戏效果
一、准备工作
确保你安装了一个 C++ 编译器,如 Visual Studio 2019 等。安装了EasyX图形库。并且了解基本的 C++ 语法,包括变量声明、数据类型、控制结构(如循环和条件语句)等。
二、代码结构概述
整个代码实现了一个类似《植物大战僵尸》的游戏。
代码主要分为以下几个部分:
头文件(head.h):包含了游戏中所需的各种库的引用、宏定义、结构体、枚举类型、类的声明等。
源文件(PvZ.cpp):实现了游戏的各种功能函数和主函数。
三、头文件(head.h
)详解
1、库引用和宏定义:
-
#include <iostream>
等一系列库的引用为程序提供了输入输出、时间处理、图形绘制、声音播放等功能。
-
宏定义了各种游戏元素的类型,例如不同的植物和僵尸类型、地图状态等,方便在程序中使用统一的标识符来表示这些元素。
#define GRASS 0
#define GRAVE1 1
//...
#define BUCKETHEADZOMBIE 16
这些宏定义使得在程序中可以使用诸如GRASS
表示草地、BUCKETHEADZOMBIE
表示铁桶僵尸等,提高了代码的可读性和可维护性。
2、结构体和枚举类型:
coordinate
结构体定义了坐标,方便在程序中表示游戏元素的位置。
struct coordinate
{
int x;
int y;
};
CURSORFLAG
枚举类型定义了鼠标光标的不同状态,用于确定玩家当前可以进行的操作。
enum CURSORFLAG
{
Chammer,
CpotatoMine,
Ciceshroom,
Cgravebuster
};
3、类的声明:
Bang
类表示爆炸效果,包含爆炸的位置和倒计时等成员变量,用于在游戏中显示爆炸效果并控制其持续时间。
class Bang
{
public:
int No;
int x;
int y;
int countDown;
Bang(int x,int y)
{
No = bangNum;
bangNum++;
this->x = x;
this->y = y;
countDown = 20;
}
};
Sun
类表示太阳,包含太阳的位置、帧、编号等成员变量,用于在游戏中生成和管理太阳资源。
class Sun
{
public:
int x;
int y;
int frame;
int No;
int changeFrameCountDown;
int goToCount;
int goToCountFrame;
int tempX;
int tempY;
Sun(int x,int y)
{
frame = 0;
No=sunNum;
sunNum++;
this->x = x;
this->y = y;
this->tempX = x;
this->tempY = y;
changeFrameCountDown = 5;
goToCount = 0;
goToCountFrame = 10;
}
};
Plant
类是植物的基类,包含植物的类型、生命值、帧编号等成员变量,为不同类型的植物提供了共同的属性和方法。
class Plant
{
public:
int type;
int HP;
int frameNo;
int No;
int x;
int y;
int changeFrameCountDown;
Plant()
{
No = plantNum;
plantNum++;
changeFrameCountDown = 5;
HP = 6;
}
~Plant(){}
};
-
PotatoMine
、GraveBuster
、IceShroom
类分别是土豆雷、墓碑吞噬者、寒冰菇的具体类,继承自Plant
类并添加了各自特有的成员变量,实现了不同植物的特定功能。 Zombie
类是僵尸的基类,包含僵尸的生命值、行、位置、状态等成员变量,为不同类型的僵尸提供了共同的属性和方法。
class Zombie
{
public:
int HP;
int row;
int location;
int emerge1walk2eat3;
int frameNo;
int height;
int No;
int changeFrameCountDown;
int isFrozen;
int isSlowed;
int type;
Zombie()
{
No = zombieNum;
zombieNum++;
isFrozen = 0;
isSlowed = 0;
height = 115;
frameNo = 19;
emerge1walk2eat3 = 1;
changeFrameCountDown = 10;
}
};
NormalZombie
、ConeheadZombie
、BucketheadZombie
类分别是普通僵尸、路障僵尸、铁桶僵尸的具体类,继承自Zombie类并设置了不同的生命值和类型,实现了不同僵尸的特定行为。Lawnmower
类表示除草机,包含除草机的位置和状态等成员变量,用于在游戏中处理僵尸与除草机的交互。
class Lawnmower
{
public:
int location = -20;
int isActivated = 0;
int isOut = 0;
};
Node
和LinkList
模板类用于实现链表结构,分别表示链表节点和链表,用于管理游戏中的各种对象,如太阳、植物、僵尸等。
template<class T>
class Node
{
public:
T* content;
Node* next = NULL;
Node(T* t)
{
content = t;
}
};
template<class T>
class LinkList
{
public:
Node<T>* head;
Node<T>* tail;
LinkList()
{
head = NULL;
tail = NULL;
};
LinkList(Node<T> node)
{
head = node;
tail = node;
};
~LinkList()
{
DeleteAllNode();
}
void InsertNode(T* t)
//... (其他函数的实现)
};
四、源文件(PvZ.cpp)详解
1、函数声明和命名空间:
- 使用各种编译指令和命名空间声明,为程序提供必要的设置和功能。
using namespace std;
使得可以直接使用标准库中的名称而无需加上std::
前缀,方便了代码的编写。
2、初始化函数(init
):
void init()
{
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 9; j++)
{
mapState[i][j] = GRASS;
}
}
currentSunshine = 0;
plants.DeleteAllNode();
zombies.DeleteAllNode();
suns.DeleteAllNode();
bangs.DeleteAllNode();
for (int i = 0; i < 5; i++)
{
lawnmowers[i] = new Lawnmower();
}
normalfrequency = 0.002;
coneheadfrequency = 0.0025;
bucketheadfrequency = 0.0028;
SunsFrequency = 0.05;
isNewGame = 1;
isHitting = 0;
hammerRadius = 0;
drawingHint = 0;
hintCountDown = 70;
snowCountDown = 0;
graveNum = 0;
Win1Lose2 = 0;
}
- 这个函数初始化了游戏的各种参数,包括地图状态、阳光数量、各种链表的清空、除草机的状态、生成僵尸和太阳的频率等。它为游戏的开始或重新开始提供了一个干净的状态。
3、 读取存档函数(readArchive
)和写入存档函数(writeArchive
):
readArchive
函数从文件中读取游戏存档数据,包括地图状态、各种对象的状态等,并将其加载到游戏中。
void readArchive(char name[])
{
init();
char path[] = "./archives/", tmppath[200] = { 0 };
strcat(strcat(tmppath, path), name);
FILE* fp = fopen(tmppath, "rb");
::fread(&mapState, sizeof(mapState), 1, fp);
for (int i = 0; i < 5; i++)
{
lawnmowers[i] = new Lawnmower();
::fread(&lawnmowers[i]->location, sizeof(int), 1, fp);
::fread(&lawnmowers[i]->isActivated, sizeof(int), 1, fp);
::fread(&lawnmowers[i]->isOut, sizeof(int), 1, fp);
}
fread(¤tSunshine, sizeof(int), 1, fp);
//... (读取其他参数和对象的状态)
while (fread(&separator,sizeof(int),1,fp))
{
Sun* tmpSun = new Sun(0, 0);
fread(&tmpSun->x, sizeof(int), 1, fp);
fread(&tmpSun->y, sizeof(int), 1, fp);
fread(&tmpSun->frame, sizeof(int), 1, fp);
fread(&tmpSun->No, sizeof(int), 1, fp);
fread(&tmpSun->changeFrameCountDown, sizeof(int), 1, fp);
fread(&tmpSun->goToCount, sizeof(int), 1, fp);
fread(&tmpSun->goToCountFrame, sizeof(int), 1, fp);
fread(&tmpSun->tempX, sizeof(int), 1, fp);
fread(&tmpSun->tempY, sizeof(int), 1, fp);
suns.InsertNode(tmpSun);
}
fclose(fp);
}
writeArchive
函数将游戏当前状态写入文件以保存存档。
4、精确延时函数(HpSleep
)
void HpSleep(int ms)
{
static clock_t oldclock = clock();
oldclock += ms * CLOCKS_PER_SEC / 1000;
if (clock() > oldclock)
oldclock = clock();
else
while (clock() < oldclock)
Sleep(1);
}
- 这个函数通过计算时间差实现精确的延时功能,可以精确到 1ms。它用于控制游戏的帧率和动画效果的播放速度。
5、透明图像绘制函数(transparentImage
)和添加冰效果函数(addIce
):
transparentImage
函数用于将一个图像以透明的方式绘制到另一个图像上指定的位置。
void transparentImage(IMAGE* dstimg, int x, int y, IMAGE* srcimg)
{
HDC dstDC = GetImageHDC(dstimg);
HDC srcDC = GetImageHDC(srcimg);
int w = srcimg->getwidth();
int h = srcimg->getheight();
BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
AlphaBlend(dstDC, x, y, w, h, srcDC, 0, 0, w, h, bf);
}
addIce
函数用于给图像添加冰效果,通过调整图像的颜色值实现。
void addIce(IMAGE* targetImage, IMAGE* srcImage, int addRed = 0, int addGreen = 0, int addBlue = 50)
{
int srcImgWidth = srcImage->getwidth(), srcImgHeight = srcImage->getheight();
targetImage->Resize(srcImgWidth, srcImgHeight);
DWORD* pTargetBuffer = GetImageBuffer(targetImage);
DWORD* pSrcBuffer = GetImageBuffer(srcImage);
int allPixel = srcImgHeight * srcImgWidth;
for (int i = 0; i < allPixel; ++i)
{
UCHAR r = (UCHAR)GetRValue(pSrcBuffer[i]);
UCHAR g = (UCHAR)GetGValue(pSrcBuffer[i]);
UCHAR b = (UCHAR)GetBValue(pSrcBuffer[i]);
r = r + addRed;
r = r > 255? 255 : r;
g = g + addGreen;
g = g > 255? 255 : g;
b = b + addBlue;
b = b > 255? 255 : b;
pTargetBuffer[i] = (DWORD)RGBA(r, g, b, pSrcBuffer[i] >> 24);
}
}
6、绘制游戏元素的函数:
- paintPlantsAndGraves函数绘制植物和墓碑。根据地图状态,在不同的位置绘制不同类型的植物和墓碑,并更新植物的状态。
void paintPlantsAndGraves()
{
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 9; j++)
{
switch (mapState[i][j])
{
case GRASS:
break;
case GRAVE1:
{
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[0]);
break;
}
//... (处理其他地图状态)
}
}
}
}
paintZombies
函数绘制僵尸。根据僵尸的状态绘制不同的僵尸图像,并处理僵尸的移动、动画和状态变化。
void paintZombies()
{
Node<Zombie> *cur = zombies.head, *next = NULL;
while (cur!= NULL)
{
Zombie* zombieptr = cur->content;
if (zombieptr->emerge1walk2eat3 == 1)
{
//... (绘制正在冒出来的僵尸)
}
else if (zombieptr->emerge1walk2eat3 == 2)
{
//... (绘制正在行走的僵尸)
}
else if (zombieptr->emerge1walk2eat3 == 3)
{
//... (绘制正在吃植物的僵尸)
}
// 判断是否冻住或减速
if (zombieptr->isFrozen > 0)
{
//...
}
if (zombieptr->isSlowed > 0)
{
//...
}
// 如果僵尸走到最左边且此行有除草机
if (zombieptr->location < -50 && lawnmowers[zombieptr->row]->isOut == 0)
{
//...
}
// 如果僵尸前面有植物
//...
// 如果僵尸前面有除草机
if (lawnmowers[zombieptr->row]->isOut == 0 && zombieptr->location < lawnmowers[zombieptr->row]->location - 30)
{
//...
}
cur = cur->next;
}
}
paintSuns
函数绘制太阳。更新太阳的帧并处理太阳被收集的情况
void paintSuns()
{
Node<Sun> *cur = suns.head, *next;
while (cur!= NULL)
{
Sun* sun = cur->content;
transparentImage(NULL, sun->x, sun->y, &sunPictures[sun->frame]);
sun->changeFrameCountDown--;
if (sun->changeFrameCountDown == 0)
{
sun->changeFrameCountDown = 5;
sun->frame++;
if (sun->frame == 22) sun->frame = 0;
if (sun->goToCount == 1)
{
sun->x = sun->tempX / 10 * sun->goToCountFrame;
sun->y = sun->tempY / 10 * sun->goToCountFrame;
sun->goToCountFrame--;
if (sun->goToCountFrame == 0)
{
next = cur->next;
suns.DeleteNode(sun->No);
cur = next;
currentSunshine += 25;
continue;
}
}
}
cur = cur->next;
}
}
- 这个函数遍历太阳链表,绘制每个太阳的图像。通过更新太阳的帧编号和倒计时,实现太阳的动画效果。当太阳被点击 (
goToCount
为 1)时,太阳会逐渐移动到特定位置,然后被收集,增加阳光数量并从链表中删除。 - paintBangs函数绘制爆炸效果。根据爆炸的倒计时绘制爆炸图像,并在倒计时结束时删除爆炸对象。
void paintBangs()
{
Node<Bang>* cur = bangs.head,*pre;
while (cur!= NULL)
{
if (cur->content->countDown > 0)
{
cur->content->countDown--;
transparentImage(NULL, cur->content->x, cur->content->y, &bang);
}
pre = cur;
cur = cur->next;
if(pre->content->countDown<=0)
bangs.DeleteNode(pre->content->No);
}
}
- 该函数遍历爆炸效果链表,绘制每个爆炸的图像。随着倒计时的减少,不断更新爆炸的状态。当倒计时为 0 时,从链表中删除对应的爆炸对象。
paintCursor
函数绘制鼠标光标。根据光标的状态绘制不同的图像。
void paintCursor()
{
if (cursor == Chammer)
{
// 如果没锤,画正常角度锤子
if (!isHitting)
transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &hammer[0]);
else
{
// 画旋转锤子
transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &hammer[hammerRadius]);
hammerRadius++;
if (hammerRadius == 13)
{
hammerRadius = 0;
isHitting = 0;
}
}
}
else if (cursor == CpotatoMine)
transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &potaotoMinePictures[0]);
else if (cursor == Ciceshroom)
transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &iceshroomPictures[0]);
else
transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &gravebusterPictures[0]);
}
- 根据鼠标光标的状态(锤子、土豆雷、寒冰菇、墓碑吞噬者),在鼠标位置绘制相应的图像。如果是锤子状态且正在锤击(
isHitting
为真),则绘制旋转的锤子图像。
7、随机生成游戏元素的函数:
generateSunshine
函数在一定概率下生成阳光,并将其添加到游戏中。
void generateSunshine(int x, int y)
{
// 一定概率产生 3 个阳光
double p = rand() / (double)RAND_MAX;
if (p < SunsFrequency)
{
Sun* sunshine[3];
for (int i = 0; i < 3; i++)
{
sunshine[i] = new Sun(x + 80 + rand() % 100 - 50, y + 60 + rand() % 50 - 25);
suns.InsertNode(sunshine[i]);
}
}
}
- 这个函数根据给定的概率生成阳光对象,并将它们添加到太阳链表中。阳光的位置在一定范围内随机生成。
randomZombies
函数随机生成僵尸。根据概率在地图上随机位置生成不同类型的僵尸,并播放相应的音效。
void randomZombies()
{
// 随机产生僵尸
for (int i = 0; i < 5; i++)
{
for (int j = 3; j < 9; j++)
{
if (1 <= mapState[i][j] && mapState[i][j] <= 8)
{
double p = rand() / (double)RAND_MAX;
if (p < normalfrequency)
{
NormalZombie* normalZombie = new NormalZombie();
normalZombie->row = i;
normalZombie->location = xys[i][j].x - 75;
zombies.InsertNode(normalZombie);
mciSendString("play./Music/dirt_rise.mp3 from 0", 0, 0, 0);
}
else if (normalfrequency <= p && p < coneheadfrequency)
{
ConeheadZombie* coneheadZombie = new ConeheadZombie();
coneheadZombie->row = i;
coneheadZombie->location = xys[i][j].x - 75;
zombies.InsertNode(coneheadZombie);
mciSendString("play./Music/dirt_rise.mp3 from 0", 0, 0, 0);
}
else if (coneheadfrequency <= p && p < bucketheadfrequency)
{
BucketheadZombie* bucketheadZombie = new BucketheadZombie();
bucketheadZombie->row = i;
bucketheadZombie->location = xys[i][j].x - 75;
zombies.InsertNode(bucketheadZombie);
mciSendString("play./Music/dirt_rise.mp3 from 0", 0, 0, 0);
}
}
}
}
// 随机呻吟声
double p = rand() / (double)RAND_MAX;
if (p < groanFrequency)
{
int px = rand() % 6 + 1;
switch (px)
{
case 1:
mciSendString("play./Music/groan.mp3 from 0", 0, 0, 0);
break;
case 2:
mciSendString("play./Music/groan2.mp3 from 0", 0, 0, 0);
break;
case 3:
mciSendString("play./Music/groan3.mp3 from 0", 0, 0, 0);
break;
case 4:
mciSendString("play./Music/groan4.mp3 from 0", 0, 0, 0);
break;
case 5:
mciSendString("play./Music/groan5.mp3 from 0", 0, 0, 0);
break;
case 6:
mciSendString("play./Music/groan6.mp3 from 0", 0, 0, 0);
break;
}
}
}
- 这个函数在游戏中随机生成僵尸。首先,根据给定的概率在地图上的特定位置生成普通僵尸、路障僵尸或铁桶僵尸,并播放相应的音效。然后,再次根据概率随机播放僵尸的呻吟声。
randomGraves
函数随机生成墓碑。确保游戏中有一定数量的墓碑,并随机分布在地图上。
void randomGraves()
{
// 随机产生墓碑
while (graveNum < 6 || graveNum > 13)
{
graveNum = 0;
for (int i = 0; i < 5; i++)
{
int num = rand() % 4;
for (int j = 0; j < num; j++)
{
int column = rand() % 6 + 3;
if (mapState[i][column] == 0)
{
mapState[i][column] = rand() % 8 + 1;
graveNum++;
}
else j--;
}
}
}
}
- 该函数用于在游戏开始时随机生成一定数量的墓碑。通过不断调整墓碑的数量,确保游戏中有 6 到 13 个墓碑随机分布在地图上。
8、绘制存档名称函数(paintNames
)和绘制提示函数(drawHint
):
paintNames
函数读取存档文件夹中的存档文件,并在游戏界面上绘制存档名称。如果存档过多或没有存档,会显示相应的提示信息。
void paintNames()
{
// 画出存档名称
getFiles("./archives");
RECT rect;
setbkmode(TRANSPARENT);
settextcolor(RGB(222, 186, 97));
if (files.size() > 5)
{
settextstyle(20, 0, "华文隶书");
rect = { 268, 135, 538, 335 };
drawtext("存档过多,请删除 archives", &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
rect = { 268, 175, 538, 375 };
drawtext("文件夹下的存档并重启!", &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
else if (files.size() == 0)
{
settextstyle(40, 0, "华文隶书");
rect = { 268, 159, 538, 360 };
drawtext("没有存档!", &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
else
{
int h = 189;
settextstyle(35, 0, "华文隶书");
for (int i = 0; i < files.size(); ++i)
{
rect = { 268, h, 538, h + 40 };
drawtext(files[i].c_str(), &rect, DT_CENTER);
h += 40;
}
}
}
- 这个函数首先获取存档文件夹中的存档文件列表。然后,根据存档数量的不同情况,在游戏界面上绘制相应的提示信息或存档名称。如果存档过多,会提示玩家删除一些存档并重启游戏;如果没有存档,则显示 “没有存档!”;如果有存档,则逐个绘制存档名称。
drawHint
函数根据游戏状态绘制提示信息,如 “此处不能种植物!” 或 “阳光不足!”。
void drawHint()
{
if (drawingHint!= 0)
{
settextcolor(WHITE);
settextstyle(40, 0, "隶书");
if (drawingHint == 1)
{
drawtext("此处不能种植物!", &rect, DT_CENTER);
}
else if (drawingHint == 2)
drawtext("阳光不足!", &rect, DT_CENTER);
hintCountDown--;
if (hintCountDown == 0)
{
hintCountDown = 70;
drawingHint = 0;
}
}
}
- 该函数根据游戏中的提示状态(
drawingHint
)绘制相应的提示信息在游戏界面上。如果提示状态为 1,则绘制 “此处不能种植物!”;如果提示状态为 2,则绘制 “阳光不足!”。提示会持续一段时间(由hintCountDown
控制),然后消失。
五、完整代码&素材
head.h
#include <iostream>
#include <ctime>
#include <string>
#include <graphics.h>
#include <conio.h>
#include <Windows.h>
#include <io.h>
#include <vector>
#include <stdio.h>
#include <cmath>
#include <mmsystem.h>
using namespace std;
#define GRASS 0
#define GRAVE1 1
#define GRAVE2 2
#define GRAVE3 3
#define GRAVE4 4
#define GRAVE5 5
#define GRAVE6 6
#define GRAVE7 7
#define GRAVE8 8
#define POTATO 9
#define POTATOMINE 10
#define POTATOBOOM 11
#define GRAVEBUSTER_GRAVE1 12
#define GRAVEBUSTER_GRAVE2 13
#define GRAVEBUSTER_GRAVE3 14
#define GRAVEBUSTER_GRAVE4 15
#define GRAVEBUSTER_GRAVE5 16
#define GRAVEBUSTER_GRAVE6 17
#define GRAVEBUSTER_GRAVE7 18
#define GRAVEBUSTER_GRAVE8 19
#define ICESHROOM 20
#define NORMALZOMBIE 21
#define CONEHEADZOMBIE 22
#define BUCKETHEADZOMBIE 16
//非游戏参数
int zombieNum=0;
int plantNum=0;
int sunNum=0;
int bangNum=0;
double groanFrequency = 0.0005;
IMAGE potatoBoom;
IMAGE potato;
IMAGE grave[8];
IMAGE hammer[13];
IMAGE tmpImg;
IMAGE tmpImg2;
IMAGE potaotoMinePictures[8];
IMAGE iceshroomPictures[11];
IMAGE gravebusterPictures[28];
IMAGE sunPictures[22];
IMAGE normalZombieWalkPictures[47];
IMAGE normalZombieEmergePictures[20];
IMAGE normalZombieEatPictures[10];
IMAGE coneheadZombieWalkPictures[47];
IMAGE coneheadZombieEmergePictures[20];
IMAGE coneheadZombieEatPictures[10];
IMAGE bucketheadZombieWalkPictures[47];
IMAGE bucketheadZombieEmergePictures[20];
IMAGE bucketheadZombieEatPictures[10];
IMAGE plantsBar;
IMAGE menu;
IMAGE background;
IMAGE selectID;
IMAGE iceTrap;
IMAGE snow;
IMAGE lawnmower;
IMAGE loseGame;
IMAGE winGame;
IMAGE bang;
ExMessage mousemsg;
struct coordinate
{
int x;
int y;
};
enum CURSORFLAG
{
Chammer,
CpotatoMine,
Ciceshroom,
Cgravebuster
};
coordinate xys[32][32];
CURSORFLAG cursor;
RECT rect = { 0, 500, 820, 600 };
char sunshineNum[10];
char username[200];
vector<string> files;
class Bang
{
public:
int No;
int x;
int y;
int countDown;
Bang(int x,int y)
{
No = bangNum;
bangNum++;
this->x = x;
this->y = y;
countDown = 20;
}
};
class Sun
{
public:
int x;
int y;
int frame;
int No;
int changeFrameCountDown;
int goToCount;
int goToCountFrame;
int tempX;
int tempY;
Sun(int x,int y)
{
frame = 0;
No=sunNum;
sunNum++;
this->x = x;
this->y = y;
this->tempX = x;
this->tempY = y;
changeFrameCountDown = 5;
goToCount = 0;
goToCountFrame = 10;
}
};
class Plant
{
public:
int type;
int HP;
int frameNo;
int No;
int x;
int y;
int changeFrameCountDown;
Plant()
{
No = plantNum;
plantNum++;
changeFrameCountDown = 5;
HP = 6;
}
~Plant(){}
};
// 土豆雷
class PotatoMine : public Plant
{
public:
int underCountDown = 400;
int boomCountDown = 50;
PotatoMine()
{
frameNo = 0;
type = POTATOMINE;
}
};
// 墓碑吞噬者
class GraveBuster : public Plant
{
public:
GraveBuster()
{
frameNo = 1;
type = GRAVEBUSTER_GRAVE1;
}
};
// 寒冰菇
class IceShroom : public Plant
{
public:
int frozenCountDown = 200;
int slowingCountDown = 1000;
IceShroom()
{
frameNo = 0;
type = ICESHROOM;
}
};
class Zombie
{
public:
int HP;
int row;
int location;
int emerge1walk2eat3;
int frameNo;
int height;
int No;
int changeFrameCountDown;
int isFrozen;
int isSlowed;
int type;
Zombie()
{
No = zombieNum;
zombieNum++;
isFrozen = 0;
isSlowed = 0;
height = 115; // 僵尸图像高度
frameNo = 19; // 表示播放到第几帧
emerge1walk2eat3 = 1; // 正在冒出来用 1 表示,正在行走用 2 表示,正在吃植物用 3 表示
changeFrameCountDown = 10;
}
};
class NormalZombie : public Zombie
{
public:
NormalZombie()
{
HP = 1;
type = NORMALZOMBIE;
}
};
class ConeheadZombie : public Zombie
{
public:
ConeheadZombie()
{
HP = 2;
type = CONEHEADZOMBIE;
}
};
class BucketheadZombie : public Zombie
{
public:
BucketheadZombie()
{
HP = 3;
type = BUCKETHEADZOMBIE;
}
};
class Lawnmower
{
public:
int location = -20;
int isActivated = 0;
int isOut = 0;
};
template<class T>
class Node
{
public:
T* content;
Node* next = NULL;
Node(T* t)
{
content = t;
}
};
template<class T>
class LinkList
{
public:
Node<T>* head;
Node<T>* tail;
LinkList()
{
head = NULL;
tail = NULL;
};
LinkList(Node<T> node)
{
head = node;
tail = node;
};
~LinkList()
{
DeleteAllNode();
}
void InsertNode(T* t)
{
Node<T>* node=new Node<T>(t);
if (head == NULL)
{
head = node;
tail = node;
}
else
{
tail->next = node;
tail = node;
}
};
void DeleteNode(int No)
{
Node<T>* cur = head,*pre=NULL;
while (cur != NULL && cur->content->No != No)
{
pre = cur;
cur = cur->next;
}
if (pre == NULL)
{
head = cur->next;
}
else if (cur == NULL)
{
cout << "没有找到符合条件的结点!" << endl;
return;
}
else
{
pre->next = cur->next;
}
if (cur == tail)
{
tail = pre;
}
delete cur;
};
void DeleteAllNode()
{
Node<T>* cur = head,*pre=NULL;
while (tail != NULL)
{
pre = cur;
cur = cur->next;
DeleteNode(pre->content->No);
}
};
};
PvZ.cpp
#include "head.h"
#pragma warning (disable:4996)
#pragma comment( lib, "MSIMG32.LIB")
#pragma comment( lib, "winmm.lib")
// 游戏参数
int mapState[32][32]; // 地图状态。0:空,1:墓碑,2:地雷(没出土),3:地雷(已出土),4:寒冰菇
int currentSunshine;
LinkList<Sun> suns;
LinkList<Plant> plants;
LinkList<Zombie> zombies;
LinkList<Bang> bangs;
Lawnmower* lawnmowers[5];
double normalfrequency;
double coneheadfrequency;
double bucketheadfrequency;
double SunsFrequency;
int isNewGame;
int isHitting;
int hammerRadius;
int drawingHint;
int hintCountDown;
int snowCountDown;
int graveNum;
int Win1Lose2;
void init()
{
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 9; j++)
{
mapState[i][j] = GRASS;
}
}
currentSunshine = 0;
plants.DeleteAllNode();
zombies.DeleteAllNode();
suns.DeleteAllNode();
bangs.DeleteAllNode();
for (int i = 0; i < 5; i++)
{
lawnmowers[i] = new Lawnmower();
}
normalfrequency = 0.002;
coneheadfrequency = 0.0025;
bucketheadfrequency = 0.0028;
SunsFrequency = 0.05;
isNewGame = 1;
isHitting = 0;
hammerRadius = 0;
drawingHint = 0;
hintCountDown = 70;
snowCountDown = 0;
graveNum = 0;
Win1Lose2 = 0;
}
void getFiles(string path)
{
files.clear();
//文件句柄
intptr_t hFile = 0;
//文件信息
struct _finddata_t fileinfo;
string p;
if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
{
do
{
files.push_back(fileinfo.name);
} while (_findnext(hFile, &fileinfo) == 0);
_findclose(hFile);
}
files.erase(files.begin());
files.erase(files.begin());
}
void readArchive(char name[])
{
init();
char path[] = "./archives/", tmppath[200] = { 0 };
strcat(strcat(tmppath, path), name);
FILE* fp = fopen(tmppath, "rb");
::fread(&mapState, sizeof(mapState), 1, fp);
for (int i = 0; i < 5; i++)
{
lawnmowers[i] = new Lawnmower();
::fread(&lawnmowers[i]->location, sizeof(int), 1, fp);
::fread(&lawnmowers[i]->isActivated, sizeof(int), 1, fp);
::fread(&lawnmowers[i]->isOut, sizeof(int), 1, fp);
}
fread(¤tSunshine, sizeof(int), 1, fp);
fread(&normalfrequency, sizeof(double), 1, fp);
fread(&coneheadfrequency, sizeof(double), 1, fp);
fread(&bucketheadfrequency, sizeof(double), 1, fp);
fread(&SunsFrequency, sizeof(double), 1, fp);
fread(&isNewGame, sizeof(int), 1, fp);
fread(&isHitting, sizeof(int), 1, fp);
fread(&hammerRadius, sizeof(int), 1, fp);
fread(&drawingHint, sizeof(int), 1, fp);
fread(&hintCountDown, sizeof(int), 1, fp);
fread(&snowCountDown, sizeof(int), 1, fp);
fread(&graveNum, sizeof(int), 1, fp);
fread(&Win1Lose2, sizeof(int), 1, fp);
int separator;
while (1)
{
fread(&separator, sizeof(int), 1, fp);
if (separator!=1234567)
{
Zombie* tmpZombie = new Zombie();
fseek(fp, -(int)sizeof(int), SEEK_CUR);
fread(&tmpZombie->HP, sizeof(int), 1, fp);
fread(&tmpZombie->row, sizeof(int), 1, fp);
fread(&tmpZombie->location, sizeof(int), 1, fp);
fread(&tmpZombie->emerge1walk2eat3, sizeof(int), 1, fp);
fread(&tmpZombie->frameNo, sizeof(int), 1, fp);
fread(&tmpZombie->height, sizeof(int), 1, fp);
fread(&tmpZombie->No, sizeof(int), 1, fp);
fread(&tmpZombie->changeFrameCountDown, sizeof(int), 1, fp);
fread(&tmpZombie->isFrozen, sizeof(int), 1, fp);
fread(&tmpZombie->isSlowed, sizeof(int), 1, fp);
fread(&tmpZombie->type, sizeof(int), 1, fp);
zombies.InsertNode(tmpZombie);
}
else break;
}
int tmpPlantType;
while (1)
{
fread(&separator, sizeof(int), 1, fp);
if (separator!=7654321)
{
fseek(fp, -(int)sizeof(int), SEEK_CUR);
fread(&tmpPlantType, sizeof(int), 1, fp);
switch (tmpPlantType)
{
case POTATOMINE:
{
PotatoMine* tmpPotatoMine = new PotatoMine();
tmpPotatoMine->type = tmpPlantType;
fread(&tmpPotatoMine->frameNo, sizeof(int), 1, fp);
fread(&tmpPotatoMine->No, sizeof(int), 1, fp);
fread(&tmpPotatoMine->x, sizeof(int), 1, fp);
fread(&tmpPotatoMine->y, sizeof(int), 1, fp);
fread(&tmpPotatoMine->changeFrameCountDown, sizeof(int), 1, fp);
fread(&tmpPotatoMine->underCountDown, sizeof(int), 1, fp);
fread(&tmpPotatoMine->boomCountDown, sizeof(int), 1, fp);
plants.InsertNode(tmpPotatoMine);
break;
}
case GRAVEBUSTER_GRAVE1:
{
GraveBuster* tmpGraveBuster = new GraveBuster();
tmpGraveBuster->type = tmpPlantType;
fread(&tmpGraveBuster->frameNo, sizeof(int), 1, fp);
fread(&tmpGraveBuster->No, sizeof(int), 1, fp);
fread(&tmpGraveBuster->x, sizeof(int), 1, fp);
fread(&tmpGraveBuster->y, sizeof(int), 1, fp);
fread(&tmpGraveBuster->changeFrameCountDown, sizeof(int), 1, fp);
plants.InsertNode(tmpGraveBuster);
break;
}
case ICESHROOM:
{
IceShroom* tmpIceShroom = new IceShroom();
tmpIceShroom->type = tmpPlantType;
fread(&tmpIceShroom->frameNo, sizeof(int), 1, fp);
fread(&tmpIceShroom->No, sizeof(int), 1, fp);
fread(&tmpIceShroom->x, sizeof(int), 1, fp);
fread(&tmpIceShroom->y, sizeof(int), 1, fp);
fread(&tmpIceShroom->changeFrameCountDown, sizeof(int), 1, fp);
fread(&tmpIceShroom->frozenCountDown, sizeof(int), 1, fp);
fread(&tmpIceShroom->slowingCountDown, sizeof(int), 1, fp);
plants.InsertNode(tmpIceShroom);
break;
}
}
}
else break;
}
while (1)
{
fread(&separator, sizeof(int), 1, fp);
if (separator != 357421)
{
Bang* tmpBang = new Bang(0,0);
fseek(fp, -(int)sizeof(int), SEEK_CUR);
fread(&tmpBang->No, sizeof(int), 1, fp);
fread(&tmpBang->x, sizeof(int), 1, fp);
fread(&tmpBang->y, sizeof(int), 1, fp);
fread(&tmpBang->countDown, sizeof(int), 1, fp);
bangs.InsertNode(tmpBang);
}
else
break;
}
while (fread(&separator,sizeof(int),1,fp))
{
Sun* tmpSun = new Sun(0, 0);
fread(&tmpSun->x, sizeof(int), 1, fp);
fread(&tmpSun->y, sizeof(int), 1, fp);
fread(&tmpSun->frame, sizeof(int), 1, fp);
fread(&tmpSun->No, sizeof(int), 1, fp);
fread(&tmpSun->changeFrameCountDown, sizeof(int), 1, fp);
fread(&tmpSun->goToCount, sizeof(int), 1, fp);
fread(&tmpSun->goToCountFrame, sizeof(int), 1, fp);
fread(&tmpSun->tempX, sizeof(int), 1, fp);
fread(&tmpSun->tempY, sizeof(int), 1, fp);
suns.InsertNode(tmpSun);
}
fclose(fp);
}
void writeArchive(char name[])
{
char path[] = "./archives/", tmppath[200] = { 0 };
strcat(strcat(tmppath, path), name);
FILE* fp = fopen(tmppath, "wb");
::fwrite(mapState, sizeof(mapState), 1, fp);
for (int i = 0; i < 5; i++)
{
::fwrite(&lawnmowers[i]->location, sizeof(int), 1, fp);
::fwrite(&lawnmowers[i]->isActivated, sizeof(int), 1, fp);
::fwrite(&lawnmowers[i]->isOut, sizeof(int), 1, fp);
}
::fwrite(¤tSunshine, sizeof(int), 1, fp);
::fwrite(&normalfrequency, sizeof(double), 1, fp);
::fwrite(&coneheadfrequency, sizeof(double), 1, fp);
::fwrite(&bucketheadfrequency, sizeof(double), 1, fp);
::fwrite(&SunsFrequency, sizeof(double), 1, fp);
::fwrite(&isNewGame, sizeof(int), 1, fp);
::fwrite(&isHitting, sizeof(int), 1, fp);
::fwrite(&hammerRadius, sizeof(int), 1, fp);
::fwrite(&drawingHint, sizeof(int), 1, fp);
::fwrite(&hintCountDown, sizeof(int), 1, fp);
::fwrite(&snowCountDown, sizeof(int), 1, fp);
::fwrite(&graveNum, sizeof(int), 1, fp);
::fwrite(&Win1Lose2, sizeof(int), 1, fp);
Node<Zombie>* curZombie = zombies.head;
while (curZombie != NULL)
{
Zombie* zombie = curZombie->content;
::fwrite(&zombie->HP, sizeof(int), 1, fp);
::fwrite(&zombie->row, sizeof(int), 1, fp);
::fwrite(&zombie->location, sizeof(int), 1, fp);
::fwrite(&zombie->emerge1walk2eat3, sizeof(int), 1, fp);
::fwrite(&zombie->frameNo, sizeof(int), 1, fp);
::fwrite(&zombie->height, sizeof(int), 1, fp);
::fwrite(&zombie->No, sizeof(int), 1, fp);
::fwrite(&zombie->changeFrameCountDown, sizeof(int), 1, fp);
::fwrite(&zombie->isFrozen, sizeof(int), 1, fp);
::fwrite(&zombie->isSlowed, sizeof(int), 1, fp);
::fwrite(&zombie->type, sizeof(int), 1, fp);
curZombie = curZombie->next;
}
int separator1 = 1234567;
::fwrite(&separator1, sizeof(int), 1, fp);
Node<Plant>* curPlant = plants.head;
while (curPlant != NULL)
{
switch (curPlant->content->type)
{
case POTATOMINE:
{
PotatoMine* potatoMine = static_cast<PotatoMine*>(curPlant->content);
::fwrite(&potatoMine->type, sizeof(int), 1, fp);
::fwrite(&potatoMine->frameNo, sizeof(int), 1, fp);
::fwrite(&potatoMine->No, sizeof(int), 1, fp);
::fwrite(&potatoMine->x, sizeof(int), 1, fp);
::fwrite(&potatoMine->y, sizeof(int), 1, fp);
::fwrite(&potatoMine->changeFrameCountDown, sizeof(int), 1, fp);
::fwrite(&potatoMine->underCountDown, sizeof(int), 1, fp);
::fwrite(&potatoMine->boomCountDown, sizeof(int), 1, fp);
break;
}
case ICESHROOM:
{
IceShroom* iceShroom = static_cast<IceShroom*>(curPlant->content);
::fwrite(&iceShroom->type, sizeof(int), 1, fp);
::fwrite(&iceShroom->frameNo, sizeof(int), 1, fp);
::fwrite(&iceShroom->No, sizeof(int), 1, fp);
::fwrite(&iceShroom->x, sizeof(int), 1, fp);
::fwrite(&iceShroom->y, sizeof(int), 1, fp);
::fwrite(&iceShroom->changeFrameCountDown, sizeof(int), 1, fp);
::fwrite(&iceShroom->frozenCountDown, sizeof(int), 1, fp);
::fwrite(&iceShroom->slowingCountDown, sizeof(int), 1, fp);
break;
}
case GRAVEBUSTER_GRAVE1:
{
GraveBuster* graveBuster = static_cast<GraveBuster*>(curPlant->content);
::fwrite(&graveBuster->type, sizeof(int), 1, fp);
::fwrite(&graveBuster->frameNo, sizeof(int), 1, fp);
::fwrite(&graveBuster->No, sizeof(int), 1, fp);
::fwrite(&graveBuster->x, sizeof(int), 1, fp);
::fwrite(&graveBuster->y, sizeof(int), 1, fp);
::fwrite(&graveBuster->changeFrameCountDown, sizeof(int), 1, fp);
break;
}
}
curPlant = curPlant->next;
}
int separator2 = 7654321;
::fwrite(&separator2, sizeof(int), 1, fp);
Node<Bang>* curBang = bangs.head;
while (curBang!= NULL)
{
Bang* bang = curBang->content;
::fwrite(&bang->No, sizeof(int), 1, fp);
::fwrite(&bang->x, sizeof(int), 1, fp);
::fwrite(&bang->y, sizeof(int), 1, fp);
::fwrite(&bang->countDown, sizeof(int), 1, fp);
curBang = curBang->next;
}
int separator3 = 357421;
::fwrite(&separator3, sizeof(int), 1, fp);
Node<Sun>* curSun = suns.head;
while (curSun != NULL)
{
Sun* sun = curSun->content;
::fwrite(&sun->x, sizeof(int), 1, fp);
::fwrite(&sun->y, sizeof(int), 1, fp);
::fwrite(&sun->frame, sizeof(int), 1, fp);
::fwrite(&sun->No, sizeof(int), 1, fp);
::fwrite(&sun->changeFrameCountDown, sizeof(int), 1, fp);
::fwrite(&sun->goToCount, sizeof(int), 1, fp);
::fwrite(&sun->goToCountFrame, sizeof(int), 1, fp);
::fwrite(&sun->tempX, sizeof(int), 1, fp);
::fwrite(&sun->tempY, sizeof(int), 1, fp);
curSun = curSun->next;
}
fclose(fp);
}
// 精确延时函数(可以精确到 1ms,精度 ±1ms)
// by yangw80<yw80@qq.com>, 2011-5-4
void HpSleep(int ms)
{
static clock_t oldclock = clock(); // 静态变量,记录上一次 tick
oldclock += ms * CLOCKS_PER_SEC / 1000; // 更新 tick
if (clock() > oldclock) // 如果已经超时,无需延时
oldclock = clock();
else
while (clock() < oldclock) // 延时
Sleep(1); // 释放 CPU 控制权,降低 CPU 占用率
// Sleep(0); // 更高精度、更高 CPU 占用率
}
void transparentImage(IMAGE* dstimg, int x, int y, IMAGE* srcimg)
{
HDC dstDC = GetImageHDC(dstimg);
HDC srcDC = GetImageHDC(srcimg);
int w = srcimg->getwidth();
int h = srcimg->getheight();
BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
AlphaBlend(dstDC, x, y, w, h, srcDC, 0, 0, w, h, bf);
}
void paintPlantsAndGraves()
{
// 画植物和墓碑
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 9; j++)
{
switch (mapState[i][j])
{
case GRASS:
break;
case GRAVE1:
{
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[0]);
break;
}
case GRAVE2:
{
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[1]);
break;
}
case GRAVE3:
{
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[2]);
break;
}
case GRAVE4:
{
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[3]);
break;
}
case GRAVE5:
{
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[4]);
break;
}
case GRAVE6:
{
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[5]);
break;
}
case GRAVE7:
{
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[6]);
break;
}
case GRAVE8:
{
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[7]);
break;
}
case POTATO:
{
transparentImage(NULL, xys[i][j].x, xys[i][j].y + 37, &potato);
Node<Plant>* cur = plants.head;
while (cur != NULL)
{
if (cur->content->x == i && cur->content->y == j)
{
break;
}
else cur = cur->next;
}
if (cur != NULL)
{
PotatoMine* potato = static_cast<PotatoMine*>(cur->content);
potato->underCountDown--;
if (potato->underCountDown == 0)
{
mapState[i][j] = POTATOMINE;
mciSendString("play ./Music/dirt_rise.mp3 from 0 ", 0, 0, 0);
}
}
break;
}
case POTATOMINE:
{
Node<Plant>* cur = plants.head;
while (cur != NULL)
{
if (cur->content->x == i && cur->content->y == j)break;
else cur = cur->next;
}
if (cur != NULL)
{
transparentImage(NULL, xys[i][j].x, xys[i][j].y + 40, &potaotoMinePictures[cur->content->frameNo]);
cur->content->changeFrameCountDown--;
if (cur->content->changeFrameCountDown == 0)
{
cur->content->changeFrameCountDown = 20;
cur->content->frameNo++;
if (cur->content->frameNo == 7)
{
cur->content->frameNo = 0;
}
}
}
break;
}
case POTATOBOOM:
{
transparentImage(NULL, xys[i][j].x - 25, xys[i][j].y + 20, &potatoBoom);
Node<Plant>* cur = plants.head;
while (cur != NULL)
{
if (cur->content->x == i && cur->content->y == j)break;
else cur = cur->next;
}
if (cur != NULL)
{
PotatoMine* potato = static_cast<PotatoMine*>(cur->content);
potato->boomCountDown--;
if (potato->boomCountDown == 0)
{
plants.DeleteNode(potato->No);
mapState[i][j] = GRASS;
}
}
break;
}
case GRAVEBUSTER_GRAVE1:
transparentImage(NULL, xys[i][j].x-5, xys[i][j].y, &grave[0]);
goto label;
case GRAVEBUSTER_GRAVE2:
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[1]);
goto label;
case GRAVEBUSTER_GRAVE3:
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[2]);
goto label;
case GRAVEBUSTER_GRAVE4:
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[3]);
goto label;
case GRAVEBUSTER_GRAVE5:
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[4]);
goto label;
case GRAVEBUSTER_GRAVE6:
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[5]);
goto label;
case GRAVEBUSTER_GRAVE7:
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[6]);
goto label;
case GRAVEBUSTER_GRAVE8:
transparentImage(NULL, xys[i][j].x - 5, xys[i][j].y, &grave[7]);
goto label;
{
label:
Node<Plant>* cur = plants.head;
while (cur != NULL)
{
if (cur->content->x == i && cur->content->y == j)break;
else cur = cur->next;
}
if (cur != NULL)
{
transparentImage(NULL, xys[i][j].x - 10, xys[i][j].y - 10, &gravebusterPictures[cur->content->frameNo]);
cur->content->changeFrameCountDown--;
if (cur->content->changeFrameCountDown == 0)
{
cur->content->changeFrameCountDown = 10;
cur->content->frameNo++;
if (cur->content->frameNo > 27)
{
plants.DeleteNode(cur->content->No);
mapState[i][j] = GRASS;
graveNum--;
if (graveNum == 5)
{
SunsFrequency = 0.2;
normalfrequency = 0.003;
coneheadfrequency = 0.0035;
bucketheadfrequency = 0.0038;
}
else if (graveNum == 3)
{
SunsFrequency = 0.4;
normalfrequency=0.006;
coneheadfrequency=0.0065;
bucketheadfrequency=0.0068;
}
}
}
}
break;
}
case ICESHROOM:
{
Node<Plant>* cur = plants.head;
while (cur != NULL)
{
if (cur->content->x == i && cur->content->y == j)break;
else cur = cur->next;
}
if (cur != NULL)
{
transparentImage(NULL, xys[i][j].x, xys[i][j].y + 15, &iceshroomPictures[cur->content->frameNo]);
cur->content->changeFrameCountDown--;
if (cur->content->changeFrameCountDown == 0)
{
cur->content->changeFrameCountDown = 8;
cur->content->frameNo++;
if (cur->content->frameNo > 10)
{
plants.DeleteNode(cur->content->No);
mciSendString("play ./Music/shoop.mp3 from 0 ", 0, 0, 0);
mapState[i][j] = 0;
snowCountDown = 20;
Node<Zombie>* cur = zombies.head;
while (cur != NULL)
{
cur->content->isFrozen = 200;
cur = cur->next;
}
}
}
}
break;
}
}
}
}
}
void addIce(IMAGE* targetImage, IMAGE* srcImage, int addRed = 0, int addGreen = 0, int addBlue = 50)
{
int srcImgWidth = srcImage->getwidth(), srcImgHeight = srcImage->getheight();
targetImage->Resize(srcImgWidth, srcImgHeight);
DWORD* pTargetBuffer = GetImageBuffer(targetImage);
DWORD* pSrcBuffer = GetImageBuffer(srcImage);
int allPixel = srcImgHeight * srcImgWidth;
#define RGBA(r, g, b, a) ((b) + (g << 8) + (r << 16) + (a << 24))
for (int i = 0; i < allPixel; ++i)
{
UCHAR r = (UCHAR)GetRValue(pSrcBuffer[i]);
UCHAR g = (UCHAR)GetGValue(pSrcBuffer[i]);
UCHAR b = (UCHAR)GetBValue(pSrcBuffer[i]);
r = r + addRed;
r = r > 255 ? 255 : r;
g = g + addGreen;
g = g > 255 ? 255 : g;
b = b + addBlue;
b = b > 255 ? 255 : b;
pTargetBuffer[i] = (DWORD)RGBA(r, g, b, pSrcBuffer[i] >> 24);
}
}
void generateSunshine(int x, int y)
{
// 一定概率产生3个阳光
double p = rand() / (double)RAND_MAX;
if (p < SunsFrequency)
{
Sun* sunshine[3];
for (int i = 0; i < 3; i++)
{
sunshine[i] = new Sun(x + 80 + rand() % 100 - 50, y + 60 + rand() % 50 - 25);
suns.InsertNode(sunshine[i]);
}
}
}
void paintZombies()
{
// 画僵尸
Node<Zombie> *cur = zombies.head, *next = NULL;
while (cur != NULL)
{
Zombie* zombieptr = cur->content;
if (zombieptr->location < -150)
{
cur = cur->next;
zombies.DeleteNode(zombieptr->No);
continue;
}
if (zombieptr->emerge1walk2eat3 == 1)
{
if (zombieptr->type == NORMALZOMBIE)
tmpImg=normalZombieEmergePictures[zombieptr->frameNo];
else if (zombieptr->type == CONEHEADZOMBIE)
tmpImg = coneheadZombieEmergePictures[zombieptr->frameNo];
else
tmpImg = bucketheadZombieEmergePictures[zombieptr->frameNo];
transparentImage(NULL, zombieptr->location, xys[zombieptr->row][0].y - 40, &tmpImg);
zombieptr->frameNo--;
if (zombieptr->frameNo == 0)
{
zombieptr->emerge1walk2eat3 = 2;
}
}
else if (zombieptr->emerge1walk2eat3 == 2)
{
if (zombieptr->type == NORMALZOMBIE)
tmpImg = normalZombieWalkPictures[zombieptr->frameNo];
else if (zombieptr->type == CONEHEADZOMBIE)
tmpImg = coneheadZombieWalkPictures[zombieptr->frameNo];
else
tmpImg = bucketheadZombieWalkPictures[zombieptr->frameNo];
if (zombieptr->isFrozen)
{
addIce(&tmpImg2, &tmpImg);
transparentImage(NULL, zombieptr->location, xys[zombieptr->row][0].y - 40, &tmpImg2);
}
else if (zombieptr->isSlowed)
{
addIce(&tmpImg2, &tmpImg);
transparentImage(NULL, zombieptr->location, xys[zombieptr->row][0].y - 40, &tmpImg2);
zombieptr->changeFrameCountDown -= 1;
if (zombieptr->changeFrameCountDown <= 0)
{
zombieptr->changeFrameCountDown = 6;
zombieptr->location -= 1;
zombieptr->frameNo++;
if (zombieptr->frameNo > 46)
{
zombieptr->frameNo = 0;
}
}
}
else
{
transparentImage(NULL, zombieptr->location, xys[zombieptr->row][0].y - 40, &tmpImg);
zombieptr->changeFrameCountDown -= 2;
if (zombieptr->changeFrameCountDown <= 0)
{
zombieptr->changeFrameCountDown = 6;
zombieptr->location -= 2;
zombieptr->frameNo++;
if (zombieptr->frameNo > 46)
{
zombieptr->frameNo = 0;
}
}
}
}
else if (zombieptr->emerge1walk2eat3 == 3)
{
/*if (zombieptr->type == NORMALZOMBIE)tmpImg = normalZombieEatPictures[zombieptr->frameNo];
else if (zombieptr->type == CONEHEADZOMBIE)tmpImg = coneheadZombieEatPictures[zombieptr->frameNo];
else tmpImg = bucketheadZombieEatPictures[zombieptr->frameNo];
if (zombieptr->isFrozen) {
addIce(&tmpImg2, &tmpImg);
transparentImage(NULL, zombieptr->location, xys[zombieptr->row][0].y - 40, &tmpImg2);
}
else if (zombieptr->isSlowed) {
addIce(&tmpImg2, &tmpImg);
transparentImage(NULL, zombieptr->location, xys[zombieptr->row][0].y - 40, &tmpImg2);
zombieptr->changeFrameCountDown -= 1;
if (zombieptr->changeFrameCountDown <= 0) {
zombieptr->changeFrameCountDown = 6;
zombieptr->location -= 1;
zombieptr->frameNo++;
if (zombieptr->frameNo > 46) {
zombieptr->frameNo = 0;
}
}
}
else {
transparentImage(NULL, zombieptr->location, xys[zombieptr->row][0].y - 40, &tmpImg);
zombieptr->changeFrameCountDown -= 2;
if (zombieptr->changeFrameCountDown <= 0) {
zombieptr->changeFrameCountDown = 25;
zombieptr->frameNo++;
}
}*/
}
// 判断是否冻住
if (zombieptr->isFrozen > 0)
{
zombieptr->isFrozen--;
if (zombieptr->isFrozen == 0) zombieptr->isSlowed = 400;
transparentImage(NULL, zombieptr->location+100, xys[zombieptr->row][0].y+70, &iceTrap);
}
// 判断是否减速
if (zombieptr->isSlowed > 0)
{
zombieptr->isSlowed--;
}
// 如果僵尸走到最左边且此行有除草机
if (zombieptr->location < -50 && lawnmowers[zombieptr->row]->isOut == 0)
{
lawnmowers[zombieptr->row]->isActivated = 1;
mciSendString("play lawnmower from 0", 0, 0, 0);
}
如果僵尸前面有植物
//Node<Plant>* curPlant = plants.head,*pre;
//while (curPlant != NULL)
//{
// Plant* plant = curPlant->content;
// if (zombieptr->row == plant->x
// && zombieptr->location < xys[plant->x][plant->y].x- 25
// && zombieptr->location > xys[plant->x][plant->y-1].x-25)
// {
// if (zombieptr->emerge1walk2eat3 == 2)
// {
// zombieptr->emerge1walk2eat3 = 3;
// zombieptr->frameNo = 0;
// mciSendString("play ./Music/chomp.mp3 from 0", 0, 0, 0);
// }
// if (zombieptr->emerge1walk2eat3 == 3 && zombieptr->frameNo > 9)
// {
// zombieptr->frameNo = 0;
// mciSendString("play ./Music/chomp.mp3 from 0", 0, 0, 0);
// plant->HP--;
// if (plant->HP == 0)
// {
// pre = curPlant;
// curPlant = curPlant->next;
// plants.DeleteNode(pre->content->No);
// zombieptr->emerge1walk2eat3 = 2;
// continue;
// }
// }
// }
// curPlant = curPlant->next;
//}
// 如果僵尸前面有除草机
if (lawnmowers[zombieptr->row]->isOut == 0 && zombieptr->location < lawnmowers[zombieptr->row]->location - 30)
{
next = cur->next;
zombies.DeleteNode(zombieptr->No);
generateSunshine(zombieptr->location, xys[zombieptr->row][0].y);
cur = next;
continue;
}
cur = cur->next;
}
}
void paintSuns()
{
Node<Sun> *cur = suns.head, *next;
while (cur != NULL)
{
Sun* sun = cur->content;
transparentImage(NULL, sun->x, sun->y, &sunPictures[sun->frame]);
sun->changeFrameCountDown--;
if (sun->changeFrameCountDown == 0)
{
sun->changeFrameCountDown = 5;
sun->frame++;
if (sun->frame == 22)sun->frame = 0;
if (sun->goToCount ==1 )
{
sun->x = sun->tempX / 10 * sun->goToCountFrame;
sun->y = sun->tempY / 10 * sun->goToCountFrame;
sun->goToCountFrame--;
if (sun->goToCountFrame == 0)
{
next = cur->next;
suns.DeleteNode(sun->No);
cur = next;
currentSunshine += 25;
continue;
}
}
}
cur = cur->next;
}
}
void paintBangs()
{
Node<Bang>* cur = bangs.head,*pre;
while (cur != NULL)
{
if (cur->content->countDown > 0)
{
cur->content->countDown--;
transparentImage(NULL, cur->content->x, cur->content->y, &bang);
}
pre = cur;
cur = cur->next;
if(pre->content->countDown<=0)
bangs.DeleteNode(pre->content->No);
}
}
void paintCursor()
{
if (cursor == Chammer)
{
// 如果没锤,画正常角度锤子
if (!isHitting)
transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &hammer[0]);
else
{
// 画旋转锤子
transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &hammer[hammerRadius]);
hammerRadius++;
if (hammerRadius == 13)
{
hammerRadius = 0;
isHitting = 0;
}
}
}
else if (cursor == CpotatoMine)
transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &potaotoMinePictures[0]);
else if (cursor == Ciceshroom)
transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &iceshroomPictures[0]);
else
transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &gravebusterPictures[0]);
}
void randomZombies()
{
// 随机产生僵尸
for (int i = 0; i < 5; i++)
{
for (int j = 3; j < 9; j++)
{
if (1 <= mapState[i][j] && mapState[i][j] <= 8)
{
double p = rand() / (double)RAND_MAX;
if (p < normalfrequency)
{
NormalZombie* normalZombie = new NormalZombie();
normalZombie->row = i;
normalZombie->location = xys[i][j].x-75;
zombies.InsertNode(normalZombie);
mciSendString("play ./Music/dirt_rise.mp3 from 0", 0, 0, 0);
}
else if (normalfrequency <= p && p < coneheadfrequency)
{
ConeheadZombie* coneheadZombie = new ConeheadZombie();
coneheadZombie->row = i;
coneheadZombie->location = xys[i][j].x-75;
zombies.InsertNode(coneheadZombie);
mciSendString("play ./Music/dirt_rise.mp3 from 0", 0, 0, 0);
}
else if (coneheadfrequency <= p && p < bucketheadfrequency)
{
BucketheadZombie* bucketheadZombie = new BucketheadZombie();
bucketheadZombie->row = i;
bucketheadZombie->location = xys[i][j].x-75;
zombies.InsertNode(bucketheadZombie);
mciSendString("play ./Music/dirt_rise.mp3 from 0", 0, 0, 0);
}
}
}
}
// 随机呻吟声
double p = rand() / (double)RAND_MAX;
if (p < groanFrequency)
{
int px = rand() % 6 + 1;
switch (px)
{
case 1:
mciSendString("play ./Music/groan.mp3 from 0", 0, 0, 0);
break;
case 2:
mciSendString("play ./Music/groan2.mp3 from 0", 0, 0, 0);
break;
case 3:
mciSendString("play ./Music/groan3.mp3 from 0", 0, 0, 0);
break;
case 4:
mciSendString("play ./Music/groan4.mp3 from 0", 0, 0, 0);
break;
case 5:
mciSendString("play ./Music/groan5.mp3 from 0", 0, 0, 0);
break;
case 6:
mciSendString("play ./Music/groan6.mp3 from 0", 0, 0, 0);
break;
}
}
}
void paintNames()
{
// 画出存档名称
getFiles("./archives");
RECT rect;
setbkmode(TRANSPARENT);
settextcolor(RGB(222, 186, 97));
if (files.size() > 5)
{
settextstyle(20, 0, "华文隶书");
rect = { 268, 135, 538, 335 };
drawtext("存档过多,请删除archives", &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
rect = { 268, 175, 538, 375 };
drawtext("文件夹下的存档并重启!", &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
else if (files.size() == 0)
{
settextstyle(40, 0, "华文隶书");
rect = { 268, 159, 538, 360 };
drawtext("没有存档!", &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
else
{
int h = 189;
settextstyle(35, 0, "华文隶书");
for (int i = 0; i < files.size(); ++i)
{
rect = { 268, h, 538, h + 40 };
drawtext(files[i].c_str(), &rect, DT_CENTER);
h += 40;
}
}
}
void drawHint()
{
if (drawingHint !=0)
{
settextcolor(WHITE);
settextstyle(40, 0, "隶书");
if (drawingHint == 1)
{
drawtext("此处不能种植物!", &rect, DT_CENTER);
}
else if(drawingHint == 2)
drawtext("阳光不足!", &rect, DT_CENTER);
hintCountDown--;
if (hintCountDown == 0)
{
hintCountDown = 70;
drawingHint = 0;
}
}
}
void randomGraves()
{
// 随机产生墓碑
while (graveNum < 6 || graveNum>13)
{
graveNum = 0;
for (int i = 0; i < 5; i++)
{
int num = rand() % 4;
for (int j = 0; j < num; j++)
{
int column = rand() % 6 + 3;
if (mapState[i][column] == 0)
{
mapState[i][column] = rand() % 8 + 1;
graveNum++;
}
else j--;
}
}
}
}
void beginGame()
{
// 如果是新游戏
if (isNewGame)
{
// 随机产生墓碑
randomGraves();
isNewGame = 0;
cursor = Chammer;
}
mciSendString("open ./Music/Loonboon.mp3 alias BGM2", 0, 0, 0);
mciSendString("play BGM2 repeat", 0, 0, 0);
mciSendString("play ./Music/theZombiesareComing.mp3 from 0", 0, 0, 0);
while (1)
{
// 绘图
cleardevice();
// 画背景、植物条、菜单、阳光数
putimage(0, 0, &background);
putimage(0, 0, &plantsBar);
transparentImage(NULL, 685, 0, &menu);
RECT r = { 8, 63, 68, 85 }; // 12, 62, 68, 84
settextstyle(20, 0, "微软雅黑", 0, 0, FW_BOLD, false, false, false);
settextcolor(BLACK);
drawtext(itoa(currentSunshine,sunshineNum,10), &r, DT_CENTER);
// 画植物和墓碑
paintPlantsAndGraves();
// 画僵尸
paintZombies();
// 画除草机
for (int i = 0; i < 5; i++)
{
if (lawnmowers[i]->isOut == 0)
{
transparentImage(NULL, lawnmowers[i]->location, xys[i][0].y + 45, &lawnmower);
}
}
drawHint(); // 画提示
paintSuns(); // 画太阳
paintBangs(); // 画 bang
paintCursor(); // 画鼠标
// 画雪花
if (snowCountDown > 0)
{
snowCountDown--;
transparentImage(NULL, 0, 0, &snow);
}
FlushBatchDraw();
// 计算
// 除草机状态
for (int i = 0; i < 5; i++)
{
if (lawnmowers[i]->isActivated == 1)
{
lawnmowers[i]->location += 5;
if (lawnmowers[i]->location > 800)
{
lawnmowers[i]->isOut = 1;
}
}
}
// 如果点了鼠标
while (peekmessage(&mousemsg, EM_MOUSE))
{
if (mousemsg.message == WM_LBUTTONDOWN)
{
if (mousemsg.x > 692 && mousemsg.y > 0 && mousemsg.x < 815 && mousemsg.y < 44)
{
// 如果点击了菜单,存档退出
writeArchive(username);
goto stopGame;
}
if (cursor == Chammer)
{
// 如果鼠标是锤子
// 如果点了土豆雷
if (mousemsg.x > 86 && mousemsg.y > 10 && mousemsg.x < 133 && mousemsg.y < 79)
{
if (currentSunshine >= 25)
cursor = CpotatoMine;
else
drawingHint = 2;
}
// 如果点了墓碑吞噬者
else if (mousemsg.x > 145 && mousemsg.y > 10 && mousemsg.x < 191 && mousemsg.y < 79)
{
if (currentSunshine >= 75)
cursor = Cgravebuster;
else
drawingHint = 2;
}
// 如果点了寒冰菇
else if (mousemsg.x > 204 && mousemsg.y > 10 && mousemsg.x < 253 && mousemsg.y < 79)
{
if (currentSunshine >= 75)
cursor = Ciceshroom;
else
drawingHint = 2;
}
else
{
hammerRadius = 0;
isHitting = 1;
mciSendString("play ./Music/hit.mp3 from 0", 0, 0, 0);
Node<Zombie>* cur = zombies.head;
while (cur != NULL)
{
Zombie* zombie = cur->content;
if (mousemsg.x > zombie->location + 97 && mousemsg.y > xys[zombie->row][0].y - 40
&& mousemsg.x < zombie->location + 164 && mousemsg.y < xys[zombie->row][0].y + zombie->height)
{
// 如果锤到了僵尸,僵尸减血或死亡
bangs.InsertNode(new Bang(mousemsg.x - 70, mousemsg.y - 30));
zombie->HP--;
if (zombie->HP == 0)
{
zombies.DeleteNode(zombie->No);
generateSunshine(zombie->location, xys[zombie->row][0].y);
}
else if (zombie->HP == 1)
zombie->type = NORMALZOMBIE;
goto skipLittleWhile;
}
cur = cur->next;
}
Node<Sun>* curSun = suns.head;
while (curSun != NULL)
{
Sun* sun = curSun->content;
if (mousemsg.x > sun->x + 20 && mousemsg.y > sun->y - 18 && mousemsg.x < sun->x + 108 && mousemsg.y < sun->y + 80)
{
// 如果锤中太阳
curSun->content->goToCount = 1;
mciSendString("play ./Music/sunshine.mp3 from 0", 0, 0, 0);
goto skipLittleWhile;
}
curSun = curSun->next;
}
}
}
// 如果鼠标是植物
else
{
int i, j, isInPlantZone = 0;
for (i = 0; i < 5; i++)
{
for (j = 0; j < 9; j++)
{
if (mousemsg.x > xys[i][j].x && mousemsg.y > xys[i][j].y
&& mousemsg.x < xys[i][j].x + 80 && mousemsg.y < xys[i][j].y + 100)
{
isInPlantZone = 1;
break;
}
}
if (isInPlantZone)break;
}
if ((cursor != Cgravebuster && mapState[i][j] != GRASS) || isInPlantZone == 0)
{
drawingHint = 1;
continue;
}
switch (cursor)
{
case CpotatoMine:
{
currentSunshine -= 25;
mapState[i][j] = POTATO;
PotatoMine* potatoMine = new PotatoMine();
potatoMine->x = i;
potatoMine->y = j;
plants.InsertNode(potatoMine);
mciSendString("play ./Music/plant.mp3 from 0", 0, 0, 0);
break;
}
case Ciceshroom:
{
currentSunshine -= 75;
mapState[i][j] = ICESHROOM;
IceShroom* iceshroom = new IceShroom();
iceshroom->x = i;
iceshroom->y = j;
plants.InsertNode(iceshroom);
mciSendString("play ./Music/plant.mp3 from 0", 0, 0, 0);
break;
}
case Cgravebuster:
{
if (mapState[i][j] < 1 || mapState[i][j]>8)
{
drawingHint = 1;
continue;
}
currentSunshine -= 75;
switch (mapState[i][j])
{
case GRAVE1:
mapState[i][j] = GRAVEBUSTER_GRAVE1;
break;
case GRAVE2:
mapState[i][j] = GRAVEBUSTER_GRAVE2;
break;
case GRAVE3:
mapState[i][j] = GRAVEBUSTER_GRAVE3;
break;
case GRAVE4:
mapState[i][j] = GRAVEBUSTER_GRAVE4;
break;
case GRAVE5:
mapState[i][j] = GRAVEBUSTER_GRAVE5;
break;
case GRAVE6:
mapState[i][j] = GRAVEBUSTER_GRAVE6;
break;
case GRAVE7:
mapState[i][j] = GRAVEBUSTER_GRAVE7;
break;
case GRAVE8:
mapState[i][j] = GRAVEBUSTER_GRAVE8;
break;
default:
continue;
break;
}
GraveBuster* gravebuster = new GraveBuster();
gravebuster->x = i;
gravebuster->y = j;
plants.InsertNode(gravebuster);
mciSendString("play ./Music/gravebusterchomp.mp3 from 0", 0, 0, 0);
break;
}
}
cursor = Chammer;
}
}
else if(mousemsg.message == WM_RBUTTONDOWN)
{
cursor = Chammer;
}
}
//判断土豆雷是否被触发
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 9; j++)
{
if (mapState[i][j] == POTATOMINE)
{
Node<Zombie>* curZombie = zombies.head, * pre = NULL;
while (curZombie != NULL)
{
pre = curZombie;
curZombie = curZombie->next;
if (pre->content->row == i && pre->content->location>xys[i][j].x - 135 && pre->content->location < xys[i][j].x - 20)
{
mapState[i][j] = POTATOBOOM;
mciSendString("play ./Music/potato_mine.mp3 from 0", 0, 0, 0);
zombies.DeleteNode(pre->content->No);
}
}
}
}
}
//随机产生僵尸
randomZombies();
//判断输赢
if (graveNum == 0 && zombies.head==NULL)
{
Win1Lose2 = 1;
mciSendString("play ./Music/trophy.mp3 from 0", 0, 0, 0);
goto stopGame;
}
Node<Zombie>* cur = zombies.head;
while (cur != NULL)
{
if (cur->content->location < -150)
{
Win1Lose2 = 2;
mciSendString("play ./Music/losemusic.mp3 from 0", 0, 0, 0);
goto stopGame;
}
cur = cur->next;
}
skipLittleWhile:
//延时
HpSleep(15);
}
stopGame:
mciSendString("close BGM2", 0, 0, 0);
}
void loadImages(IMAGE imgs[], char path[],int n,int begin)
{
for (int i = 0; i < n; i++)
{
char tmpPath[200], frameNo[4];
strcpy_s(tmpPath, 200, path);
strcat(strcat(tmpPath, itoa(i + begin, frameNo, 10)), ".png");
loadimage(&imgs[i], tmpPath);
}
}
void loading()
{
loadImages(grave, "./graphics/GraveStones/", 8, 1);
loadImages(hammer, "./graphics/Screen/hammer/hammer", 13, 1);
loadImages(sunPictures, "./graphics/Plants/Sun/Sun_", 22, 0);
loadImages(potaotoMinePictures, "./graphics/Plants/PotatoMine/PotatoMine/PotatoMine_", 8, 0);
loadImages(iceshroomPictures, "./graphics/Plants/IceShroom/IceShroom/IceShroom_", 11, 0);
loadImages(gravebusterPictures, "./graphics/Plants/GraveBuster/GraveBuster-", 28, 1);
loadImages(normalZombieWalkPictures, "./graphics/Zombies/NormalZombie/Zombie/Zombie-", 47, 1);
loadImages(coneheadZombieWalkPictures, "./graphics/Zombies/ConeheadZombie/ConeheadZombie/ConeheadZombie-", 47, 1);
loadImages(bucketheadZombieWalkPictures, "./graphics/Zombies/BucketheadZombie/BucketheadZombie/BucketheadZombie-", 47, 1);
loadImages(normalZombieEmergePictures, "./graphics/Zombies/NormalZombie/ZombieEmerge/Zombie-", 20, 1);
loadImages(coneheadZombieEmergePictures, "./graphics/Zombies/ConeheadZombie/ConeheadZombieEmerge/Zombie-", 20, 1);
loadImages(bucketheadZombieEmergePictures, "./graphics/Zombies/BucketheadZombie/BucketheadZombieEmerge/Zombie-", 20, 1);
loadImages(normalZombieEatPictures, "./graphics/Zombies/NormalZombie/ZombieAttack/ZombieAttack_", 10, 0);
loadImages(coneheadZombieEatPictures, "./graphics/Zombies/ConeheadZombie/ConeheadZombieAttack/ConeheadZombieAttack_", 10, 0);
loadImages(bucketheadZombieEatPictures, "./graphics/Zombies/BucketheadZombie/BucketheadZombieAttack/BucketheadZombieAttack_", 10, 0);
loadimage(&potatoBoom, "./graphics/Plants/PotatoMine/PotatoMineExplode/PotatoMineExplode_0.png");
loadimage(&potato, "./graphics/Plants/PotatoMine/PotatoMineInit/PotatoMineInit_0.png");
loadimage(&plantsBar, "./graphics/Screen/ChooserBackground.png");
loadimage(&background, "./graphics/Screen/Background.jpg");
loadimage(&selectID, "./graphics/Screen/selectID.png");
loadimage(&iceTrap, "./graphics/Plants/IceShroom/IceShroomTrap_0.png");
loadimage(&snow, "./graphics/Plants/IceShroom/IceShroomSnow_0.png");
loadimage(&menu, "./graphics/Screen/menu.png");
loadimage(&lawnmower, "./graphics/Screen/lawnmower.png");
loadimage(&loseGame, "./graphics/Screen/lose.png");
loadimage(&winGame, "./graphics/Screen/win.png");
loadimage(&bang, "./graphics/Screen/bang.png");
mciSendString("open ./Music/chomp.mp3", 0, 0, 0);
mciSendString("open ./Music/dirt_rise.mp3", 0, 0, 0);
mciSendString("open ./Music/gravebusterchomp.mp3", 0, 0, 0);
mciSendString("open ./Music/groan.mp3", 0, 0, 0);
mciSendString("open ./Music/groan2.mp3", 0, 0, 0);
mciSendString("open ./Music/groan3.mp3", 0, 0, 0);
mciSendString("open ./Music/groan4.mp3", 0, 0, 0);
mciSendString("open ./Music/groan5.mp3", 0, 0, 0);
mciSendString("open ./Music/groan6.mp3", 0, 0, 0);
mciSendString("open ./Music/hit.mp3", 0, 0, 0);
mciSendString("open ./Music/lawnmower.mp3 alias lawnmower", 0, 0, 0);
mciSendString("open ./Music/losemusic.mp3", 0, 0, 0);
mciSendString("open ./Music/plant.mp3", 0, 0, 0);
mciSendString("open ./Music/potato_mine.mp3", 0, 0, 0);
mciSendString("open ./Music/shoop.mp3", 0, 0, 0);
mciSendString("open ./Music/theZombiesareComing.mp3", 0, 0, 0);
mciSendString("open ./Music/trophy.mp3", 0, 0, 0);
mciSendString("open ./Music/sunshine.mp3", 0, 0, 0);
}
int main()
{
srand((unsigned)time(NULL));
loading();
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 9; j++)
{
xys[i][j].x = 40 + j * 82;
xys[i][j].y = 70 + i * 100;
//cout << "xys[" << i << "][" << j << "]:" << xys[i][j].x << "," << xys[i][j].y << endl;;
}
}
initgraph(820, 600);
BeginBatchDraw();
labelBGM:
mciSendString("open ./Music/Cerebrawl.mp3 alias BGM1", 0, 0, 0);
mciSendString("play BGM1 repeat", 0, 0, 0);
label2:
cleardevice();
//背景
putimage(0, 0, &background);
//对话框
if (Win1Lose2 == 0)
{
transparentImage(NULL, 177, 35, &selectID);
paintNames();
}
else if (Win1Lose2 == 1)
{
transparentImage(NULL, 230, 140, &winGame);
}
else if (Win1Lose2 == 2)
{
transparentImage(NULL, 230, 140, &loseGame);
}
FlushBatchDraw();
while (1)
{
getmessage(&mousemsg, EM_MOUSE);
if (mousemsg.message == WM_LBUTTONDOWN)
{
cout << mousemsg.x << "," << mousemsg.y << endl;
if (Win1Lose2 == 0)
{
if (mousemsg.x > 236 && mousemsg.y > 436 && mousemsg.x < 391 && mousemsg.y < 474)
{
//点击了“没有我的名字”
char s[10];
InputBox(s, 10, "请输入你的姓名:");
init();
writeArchive(s);
goto label2;
}
else if (mousemsg.x > 410 && mousemsg.y > 438 && mousemsg.x < 566 && mousemsg.y < 473)
{
//点击了退出,存档
if (strcmp(username, "") != 0)
writeArchive(username);
return 0;
}
else if (mousemsg.x > 268 && mousemsg.y > 190 && mousemsg.x < 538 && mousemsg.y < 385)
{
//点击了存档位置
if (190 <= mousemsg.y && mousemsg.y < 229)
{
if (0 < files.size() && files.size() < 6)
strcpy(username, (char*)files[0].c_str());
else continue;
}
else if (229 <= mousemsg.y && mousemsg.y < 268)
{
if (1 < files.size() && files.size() < 6)
strcpy(username, (char*)files[1].c_str());
else continue;
}
else if (268 <= mousemsg.y && mousemsg.y < 307)
{
if (2 < files.size() && files.size() < 6)
strcpy(username, (char*)files[2].c_str());
else continue;
}
else if (307 <= mousemsg.y && mousemsg.y < 346)
{
if (3 < files.size() && files.size() < 6)
strcpy(username, (char*)files[3].c_str());
else continue;
}
else if (346 <= mousemsg.y && mousemsg.y < 385)
{
if (4 < files.size() && files.size() < 6)
strcpy(username, (char*)files[4].c_str());
else continue;
}
readArchive(username);
mciSendString("close BGM1", 0, 0, 0);
beginGame();
if (Win1Lose2 == 0)
goto labelBGM;
else goto label2;
}
}
else
{
if (mousemsg.x > 297 && mousemsg.y > 331 && mousemsg.x < 500 && mousemsg.y < 369)
{
init();
mciSendString("close BGM1", 0, 0, 0);
beginGame();
if (Win1Lose2 == 0)
goto labelBGM;
else goto label2;
}
}
}
}
getch();
EndBatchDraw();
closegraph();
return 0;
}
素材
邮箱地址在评论区里发给我,我发给你。