CodeAE 发表于 2024-10-5 12:17:05

C/C++实现植物大战僵尸

效果图:
一、准备工作
确保你安装了一个 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 = GRASS;
      }
    }

    currentSunshine = 0;
    plants.DeleteAllNode();
    zombies.DeleteAllNode();
    suns.DeleteAllNode();
    bangs.DeleteAllNode();

    for (int i = 0; i < 5; i++)
    {
      lawnmowers = 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 = { 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 = new Lawnmower();
      ::fread(&lawnmowers->location, sizeof(int), 1, fp);
      ::fread(&lawnmowers->isActivated, sizeof(int), 1, fp);
      ::fread(&lawnmowers->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);
      UCHAR g = (UCHAR)GetGValue(pSrcBuffer);
      UCHAR b = (UCHAR)GetBValue(pSrcBuffer);
      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 = (DWORD)RGBA(r, g, b, pSrcBuffer >> 24);
    }
}

6、绘制游戏元素的函数:
paintPlantsAndGraves函数绘制植物和墓碑。根据地图状态,在不同的位置绘制不同类型的植物和墓碑,并更新植物的状态。
void paintPlantsAndGraves()
{
    for (int i = 0; i < 5; i++)
    {
      for (int j = 0; j < 9; j++)
      {
            switch (mapState)
            {
            case GRASS:
                break;
            case GRAVE1:
            {
                transparentImage(NULL, xys.x - 5, xys.y, &grave);
                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->isOut == 0)
      {
            //...
      }
      // 如果僵尸前面有植物
      //...
      // 如果僵尸前面有除草机
      if (lawnmowers->isOut == 0 && zombieptr->location < lawnmowers->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->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);
      else
      {
            // 画旋转锤子
            transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &hammer);
            hammerRadius++;
            if (hammerRadius == 13)
            {
                hammerRadius = 0;
                isHitting = 0;
            }
      }
    }
    else if (cursor == CpotatoMine)
      transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &potaotoMinePictures);
    else if (cursor == Ciceshroom)
      transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &iceshroomPictures);
    else
      transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &gravebusterPictures);
}根据鼠标光标的状态(锤子、土豆雷、寒冰菇、墓碑吞噬者),在鼠标位置绘制相应的图像。如果是锤子状态且正在锤击(isHitting为真),则绘制旋转的锤子图像。

7、随机生成游戏元素的函数:
generateSunshine函数在一定概率下生成阳光,并将其添加到游戏中。
void generateSunshine(int x, int y)
{
    // 一定概率产生 3 个阳光
    double p = rand() / (double)RAND_MAX;
    if (p < SunsFrequency)
    {
      Sun* sunshine;
      for (int i = 0; i < 3; i++)
      {
            sunshine = new Sun(x + 80 + rand() % 100 - 50, y + 60 + rand() % 50 - 25);
            suns.InsertNode(sunshine);
      }
    }
}这个函数根据给定的概率生成阳光对象,并将它们添加到太阳链表中。阳光的位置在一定范围内随机生成。
randomZombies函数随机生成僵尸。根据概率在地图上随机位置生成不同类型的僵尸,并播放相应的音效。
void randomZombies()
{
    // 随机产生僵尸
    for (int i = 0; i < 5; i++)
    {
      for (int j = 3; j < 9; j++)
      {
            if (1 <= mapState && mapState <= 8)
            {
                double p = rand() / (double)RAND_MAX;
                if (p < normalfrequency)
                {
                  NormalZombie* normalZombie = new NormalZombie();
                  normalZombie->row = i;
                  normalZombie->location = xys.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.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.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 == 0)
                {
                  mapState = 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.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;
IMAGE hammer;
IMAGE tmpImg;
IMAGE tmpImg2;
IMAGE potaotoMinePictures;
IMAGE iceshroomPictures;
IMAGE gravebusterPictures;
IMAGE sunPictures;
IMAGE normalZombieWalkPictures;
IMAGE normalZombieEmergePictures;
IMAGE normalZombieEatPictures;
IMAGE coneheadZombieWalkPictures;
IMAGE coneheadZombieEmergePictures;
IMAGE coneheadZombieEatPictures;
IMAGE bucketheadZombieWalkPictures;
IMAGE bucketheadZombieEmergePictures;
IMAGE bucketheadZombieEatPictures;
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;
CURSORFLAG cursor;
RECT rect = { 0, 500, 820, 600 };
char sunshineNum;
char username;
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;                // 地图状态。0:空,1:墓碑,2:地雷(没出土),3:地雷(已出土),4:寒冰菇
int currentSunshine;
LinkList<Sun> suns;
LinkList<Plant> plants;
LinkList<Zombie> zombies;
LinkList<Bang> bangs;
Lawnmower* lawnmowers;
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 = GRASS;
                }
      }

      currentSunshine = 0;
      plants.DeleteAllNode();
      zombies.DeleteAllNode();
      suns.DeleteAllNode();
      bangs.DeleteAllNode();

      for (int i = 0; i < 5; i++)
      {
                lawnmowers = 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 = { 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 = new Lawnmower();
                ::fread(&lawnmowers->location, sizeof(int), 1, fp);
                ::fread(&lawnmowers->isActivated, sizeof(int), 1, fp);
                ::fread(&lawnmowers->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 = { 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->location, sizeof(int), 1, fp);
                ::fwrite(&lawnmowers->isActivated, sizeof(int), 1, fp);
                ::fwrite(&lawnmowers->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)
                        {
                        case GRASS:
                              break;
                        case GRAVE1:
                        {
                              transparentImage(NULL, xys.x - 5, xys.y, &grave);
                              break;
                        }
                        case GRAVE2:
                        {
                              transparentImage(NULL, xys.x - 5, xys.y, &grave);
                              break;
                        }
                        case GRAVE3:
                        {
                              transparentImage(NULL, xys.x - 5, xys.y, &grave);
                              break;
                        }
                        case GRAVE4:
                        {
                              transparentImage(NULL, xys.x - 5, xys.y, &grave);
                              break;
                        }
                        case GRAVE5:
                        {
                              transparentImage(NULL, xys.x - 5, xys.y, &grave);
                              break;
                        }
                        case GRAVE6:
                        {
                              transparentImage(NULL, xys.x - 5, xys.y, &grave);
                              break;
                        }
                        case GRAVE7:
                        {
                              transparentImage(NULL, xys.x - 5, xys.y, &grave);
                              break;
                        }
                        case GRAVE8:
                        {
                              transparentImage(NULL, xys.x - 5, xys.y, &grave);
                              break;
                        }
                        case POTATO:
                        {
                              transparentImage(NULL, xys.x, xys.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 = 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.x, xys.y + 40, &potaotoMinePictures);
                                        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.x - 25, xys.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 = GRASS;
                                        }
                              }            

                              break;
                        }
                        case GRAVEBUSTER_GRAVE1:
                              transparentImage(NULL, xys.x-5, xys.y, &grave);
                              goto label;
                        case GRAVEBUSTER_GRAVE2:
                              transparentImage(NULL, xys.x - 5, xys.y, &grave);
                              goto label;
                        case GRAVEBUSTER_GRAVE3:
                              transparentImage(NULL, xys.x - 5, xys.y, &grave);
                              goto label;
                        case GRAVEBUSTER_GRAVE4:
                              transparentImage(NULL, xys.x - 5, xys.y, &grave);
                              goto label;
                        case GRAVEBUSTER_GRAVE5:
                              transparentImage(NULL, xys.x - 5, xys.y, &grave);
                              goto label;
                        case GRAVEBUSTER_GRAVE6:
                              transparentImage(NULL, xys.x - 5, xys.y, &grave);
                              goto label;
                        case GRAVEBUSTER_GRAVE7:
                              transparentImage(NULL, xys.x - 5, xys.y, &grave);
                              goto label;
                        case GRAVEBUSTER_GRAVE8:
                              transparentImage(NULL, xys.x - 5, xys.y, &grave);
                              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.x - 10, xys.y - 10, &gravebusterPictures);
                                        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 = 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.x, xys.y + 15, &iceshroomPictures);
                                        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 = 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);
                UCHAR g = (UCHAR)GetGValue(pSrcBuffer);
                UCHAR b = (UCHAR)GetBValue(pSrcBuffer);
                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 = (DWORD)RGBA(r, g, b, pSrcBuffer >> 24);
      }
}

void generateSunshine(int x, int y)
{
      // 一定概率产生3个阳光
      double p = rand() / (double)RAND_MAX;
      if (p < SunsFrequency)
      {
                Sun* sunshine;
                for (int i = 0; i < 3; i++)
                {
                        sunshine = new Sun(x + 80 + rand() % 100 - 50, y + 60 + rand() % 50 - 25);
                        suns.InsertNode(sunshine);
                }
      }
}

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;
                        else if (zombieptr->type == CONEHEADZOMBIE)
                              tmpImg = coneheadZombieEmergePictures;
                        else
                              tmpImg = bucketheadZombieEmergePictures;

                        transparentImage(NULL, zombieptr->location, xys.y - 40, &tmpImg);
                        zombieptr->frameNo--;
                        if (zombieptr->frameNo == 0)
                        {
                              zombieptr->emerge1walk2eat3 = 2;
                        }
                }
                else if (zombieptr->emerge1walk2eat3 == 2)
                {
                        if (zombieptr->type == NORMALZOMBIE)
                              tmpImg = normalZombieWalkPictures;
                        else if (zombieptr->type == CONEHEADZOMBIE)
                              tmpImg = coneheadZombieWalkPictures;
                        else
                              tmpImg = bucketheadZombieWalkPictures;

                        if (zombieptr->isFrozen)
                        {
                              addIce(&tmpImg2, &tmpImg);
                              transparentImage(NULL, zombieptr->location, xys.y - 40, &tmpImg2);
                        }
                        else if (zombieptr->isSlowed)
                        {
                              addIce(&tmpImg2, &tmpImg);
                              transparentImage(NULL, zombieptr->location, xys.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.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;
                        else if (zombieptr->type == CONEHEADZOMBIE)tmpImg = coneheadZombieEatPictures;
                        else tmpImg = bucketheadZombieEatPictures;
                        if (zombieptr->isFrozen) {
                              addIce(&tmpImg2, &tmpImg);
                              transparentImage(NULL, zombieptr->location, xys.y - 40, &tmpImg2);
                        }
                        else if (zombieptr->isSlowed) {
                              addIce(&tmpImg2, &tmpImg);
                              transparentImage(NULL, zombieptr->location, xys.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.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.y+70, &iceTrap);         
                }
                // 判断是否减速
                if (zombieptr->isSlowed > 0)
                {
                        zombieptr->isSlowed--;
                }
                // 如果僵尸走到最左边且此行有除草机
                if (zombieptr->location < -50 && lawnmowers->isOut == 0)
                {
                        lawnmowers->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.x- 25
                //                && zombieptr->location > xys.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->isOut == 0 && zombieptr->location < lawnmowers->location - 30)
                {
                        next = cur->next;
                        zombies.DeleteNode(zombieptr->No);
                        generateSunshine(zombieptr->location, xys.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->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);
                else
                {
                        // 画旋转锤子
                        transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &hammer);
                        hammerRadius++;
                        if (hammerRadius == 13)
                        {
                              hammerRadius = 0;
                              isHitting = 0;
                        }
                }
      }
      else if (cursor == CpotatoMine)
                transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &potaotoMinePictures);
      else if (cursor == Ciceshroom)
                transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &iceshroomPictures);
      else
                transparentImage(NULL, mousemsg.x - 45, mousemsg.y - 45, &gravebusterPictures);
}

void randomZombies()
{
      // 随机产生僵尸
      for (int i = 0; i < 5; i++)
      {
                for (int j = 3; j < 9; j++)
                {
                        if (1 <= mapState && mapState <= 8)
                        {
                              double p = rand() / (double)RAND_MAX;
                              if (p < normalfrequency)
                              {
                                        NormalZombie* normalZombie = new NormalZombie();
                                        normalZombie->row = i;
                                        normalZombie->location = xys.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.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.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.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 == 0)
                              {
                                        mapState = 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->isOut == 0)
                        {
                              transparentImage(NULL, lawnmowers->location, xys.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->isActivated == 1)
                        {
                              lawnmowers->location += 5;
                              if (lawnmowers->location > 800)
                              {
                                        lawnmowers->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.y - 40
                                                                && mousemsg.x < zombie->location + 164 && mousemsg.y < xys.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.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.x && mousemsg.y > xys.y
                                                                && mousemsg.x < xys.x + 80 && mousemsg.y < xys.y + 100)
                                                      {
                                                                isInPlantZone = 1;
                                                                break;
                                                      }
                                                }
                                                if (isInPlantZone)break;
                                        }

                                        if ((cursor != Cgravebuster && mapState != GRASS) || isInPlantZone == 0)
                                        {
                                                drawingHint = 1;
                                                continue;
                                        }

                                        switch (cursor)
                                        {
                                                case CpotatoMine:
                                                {
                                                      currentSunshine -= 25;
                                                      mapState = 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 = 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 < 1 || mapState>8)
                                                      {
                                                                drawingHint = 1;
                                                                continue;
                                                      }
                                                      currentSunshine -= 75;
                                                      switch (mapState)
                                                      {
                                                                case GRAVE1:
                                                                        mapState = GRAVEBUSTER_GRAVE1;
                                                                        break;
                                                                case GRAVE2:
                                                                        mapState = GRAVEBUSTER_GRAVE2;
                                                                        break;
                                                                case GRAVE3:
                                                                        mapState = GRAVEBUSTER_GRAVE3;
                                                                        break;
                                                                case GRAVE4:
                                                                        mapState = GRAVEBUSTER_GRAVE4;
                                                                        break;
                                                                case GRAVE5:
                                                                        mapState = GRAVEBUSTER_GRAVE5;
                                                                        break;
                                                                case GRAVE6:
                                                                        mapState = GRAVEBUSTER_GRAVE6;
                                                                        break;
                                                                case GRAVE7:
                                                                        mapState = GRAVEBUSTER_GRAVE7;
                                                                        break;
                                                                case GRAVE8:
                                                                        mapState = 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 == 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.x - 135 && pre->content->location < xys.x - 20)
                                                {
                                                      mapState = 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, frameNo;
                strcpy_s(tmpPath, 200, path);
                strcat(strcat(tmpPath, itoa(i + begin, frameNo, 10)), ".png");
                loadimage(&imgs, 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.x = 40 + j * 82;
                        xys.y = 70 + i * 100;
                        //cout << "xys[" << i << "][" << j << "]:" << xys.x << "," << xys.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;
                                        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.c_str());
                                                else continue;
                                        }
                                        else if (229 <= mousemsg.y && mousemsg.y < 268)
                                        {
                                                if (1 < files.size() && files.size() < 6)
                                                      strcpy(username, (char*)files.c_str());
                                                else continue;
                                        }
                                        else if (268 <= mousemsg.y && mousemsg.y < 307)
                                        {
                                                if (2 < files.size() && files.size() < 6)
                                                      strcpy(username, (char*)files.c_str());
                                                else continue;
                                        }
                                        else if (307 <= mousemsg.y && mousemsg.y < 346)
                                        {
                                                if (3 < files.size() && files.size() < 6)
                                                      strcpy(username, (char*)files.c_str());
                                                else continue;
                                        }
                                        else if (346 <= mousemsg.y && mousemsg.y < 385)
                                        {
                                                if (4 < files.size() && files.size() < 6)
                                                      strcpy(username, (char*)files.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;
}
素材请自行下载


https://blog.csdn.net/fzy20110826/article/details/142005979

页: [1]
查看完整版本: C/C++实现植物大战僵尸