C/C++实现植物大战僵尸(PVZ)(打地鼠版)

程序猿方梓燚 2024-09-19 11:35:02 阅读 83

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

🚀欢迎互三👉:程序猿方梓燚 💎💎

🚀关注博主,后期持续更新系列文章

🚀如果有错误感谢请大家批评指出,及时修改

🚀感谢大家点赞👍收藏⭐评论✍

游戏效果

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

一、准备工作

确保你安装了一个 C++ 编译器,如 Visual Studio 2019 等。安装了EasyX图形库。并且了解基本的 C++ 语法,包括变量声明、数据类型、控制结构(如循环和条件语句)等。

二、代码结构概述

整个代码实现了一个类似《植物大战僵尸》的游戏。

代码主要分为以下几个部分:

头文件(head.h):包含了游戏中所需的各种库的引用、宏定义、结构体、枚举类型、类的声明等。

源文件(PvZ.cpp):实现了游戏的各种功能函数和主函数。

三、头文件(<code>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(){ }

};

PotatoMineGraveBusterIceShroom类分别是土豆雷、墓碑吞噬者、寒冰菇的具体类,继承自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;

}

};

NormalZombieConeheadZombieBucketheadZombie类分别是普通僵尸、路障僵尸、铁桶僵尸的具体类,继承自Zombie类并设置了不同的生命值和类型,实现了不同僵尸的特定行为。Lawnmower类表示除草机,包含除草机的位置和状态等成员变量,用于在游戏中处理僵尸与除草机的交互。

class Lawnmower

{

public:

int location = -20;

int isActivated = 0;

int isOut = 0;

};

NodeLinkList模板类用于实现链表结构,分别表示链表节点和链表,用于管理游戏中的各种对象,如太阳、植物、僵尸等。

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(&currentSunshine, 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(&currentSunshine,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(&currentSunshine, 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;

}

素材

邮箱地址在评论区里发给我,我发给你。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。