C语言游戏实战(12):植物大战僵尸(坤版)

前言:
本游戏使用C语言和easyx图形库编写,通过这个项目我们可以深度的掌握C语言的各种语言特性和高级开发技巧,以及锻炼我们独立的项目开发能力,

在开始编写代码之前,我们需要先了解一下游戏的基本规则和功能:

游戏界面:游戏界面是一个矩形区域,玩家可以在区域内进行植物的放置和铲除等操作。

僵尸:僵尸会从游戏界面的右侧向左测移动,靠近植物后会停下来吃植物。

植物:不同的植物有不同的功能,在这里我们可以将植物分为三大类:

1. 生产型植物(如太阳花):这种植物的特点是在一定的时间生产出太阳,以增加太阳的产量。

2.发射型植物(如豌豆射手):这种植物的特点是发射相应类型的子弹,对僵尸产生伤害和特定的效果。

3. 爆炸性植物(火爆辣椒):这种植物的特点是对一定区域的所有僵尸产生高额伤害。(一次性植物)

接下来,我们将通过以下几个步骤来实现这个游戏:

初始化游戏界面。

实现僵尸的创建、僵尸的更新、僵尸吃植物的检测。

实现的植物的放置。

实现植物的功能:

对于生产型植物我们需要写出阳光的生产,以及阳光的收集操作。

对于发射型植物我们需要判断植物是否发射子弹,发射子弹后还需更新子弹、检测子弹与僵尸的碰撞。

对于爆炸型植物,我们需要判断僵尸是否在爆炸范围内,然后杀死在爆炸范围内的僵尸。

1. 初始化游戏界面


我们需要先将游戏地图、卡牌和卡牌槽绘制出来。可以利用windows自带的画图工具测出游戏地图的位置,从而将这些卡牌和卡牌槽放置到合适的位置。

//地图
putimage(-150, 0, &img);
//卡牌槽
putimagePNG(80, -10, &imgBar);    
//植物卡牌
    for (int i = 0; i < PLANT_COUNT + 2; i++)
    {
        if(i==PLANT_COUNT)
            putimagePNG(163 + i * 65 + 8, -5, &imgCards[i]);
        else
            putimagePNG(163 + i * 65, 0, &imgCards[i]);
    }
2.  放置植物
因为需要在这个9*5的草地区域内放置植物,所以我们得计算出每个草方块的位置。我利用画图软件测出每个草方块大约是长81、宽100个像素点。 第一个草方块距离游戏窗口大约101个像素点。

这样就可以得出每个草方块的位置:256 - 150 + col * 81;100 + row * 100 - 15; 

每个植物都有相似的特性,所以我们需要写一个放置植物信息的结构体。然后创建一个5*9的结构体数组,用来表示每个草方块上的植物。

enum {
    WAN_DOU, TAI_YANG, LA_JIAO, KUN_KUN, JIAN_GUO,
    HAN_BING_WAN_DOU, YING_TAO, SAN_TOU_WAN_DOU, PLANT_COUNT
};
struct plant
{
    int type;//植物类型
    int frameIndex;//植物动作帧
    //bool catched;//是否被吃
    int blood;//血量
 
    int shootTime;//植物子弹的射速
 
    int timer;//阳光生产的时间
    int x, y;//植物坐标
    bool shoot;//判断植物是否处于发射状态
};
struct plant map[5][9];
 在 Windows 编程中,我们可以利用下面的变量获取鼠标信息。

ExMessage msg;
msg.message
ExMessage msg;
static int status = 0;
if (peekmessage(&msg))//判断有没有消息
{
    if (msg.message == WM_LBUTTONDOWN)//左键按下
    {
        //鼠标是否在卡牌的位置按下
        if (msg.x > 163 && msg.x < 163 + 65 * (PLANT_COUNT+2) && msg.y < 96)
        {
            //mciSendString("play res/audio/bleep.mp3 alias BGM4", NULL, NULL, NULL);
            PlaySound("res/audio/bleep.wav", NULL, SND_FILENAME | SND_ASYNC);
            //PlaySound("res/sunshine.wav", NULL, SND_FILENAME | SND_ASYNC);
 
            int index = (msg.x - 163) / 65;
            //坤坤
        /*    if (index + 1 == KUN_KUN && sunshine >= 100)
            {
                curPlant = index + 1;
                status = 1;
                curX = msg.x;
                curY = msg.y;
                sunshine -= 100;
            }*/
            curPlant = index + 1;
            status = 1;
            curX = msg.x;
            curY = msg.y;
        }
    }
    else if (msg.message == WM_MOUSEMOVE && status == 1)//鼠标移动
    {
        curX = msg.x;
        curY = msg.y;
    }
    else if (msg.message == WM_LBUTTONUP)//鼠标放下
    {
        if (msg.x > 256 - 150 && msg.x < Wide - 70 && msg.y > 100 && msg.y < 590)
        {
            int row = (msg.y - 100) / 102;
            int col = (msg.x - 256 + 150 ) / 81;
            
            
            if (map[row][col].type == 0 && curPlant != PLANT_COUNT + 1 && curPlant != PLANT_COUNT + 2)
            {
                //printf("%d\n", map[col][row].type);
                map[row][col].type = curPlant;
                map[row][col].frameIndex = 0;
 
                if(curPlant!=0)
                    PlaySound("res/audio/coffee.wav", NULL, SND_FILENAME | SND_ASYNC);
 
                if (curPlant == 5)
                    map[row][col].blood = KUNKUN_BLOOD * 50;
                else
                    map[row][col].blood = KUNKUN_BLOOD;
 
                map[row][col].shootTime = 0;
                map[row][col].shoot = false;
 
                map[row][col].x = 256 - 150 + col * 81;
                map[row][col].y = 100 + row * 100 - 15;
                
            }
            else if (map[row][col].type != 0 && curPlant == PLANT_COUNT + 1)
            {
                PlaySound("res/audio/coffee.wav", NULL, SND_FILENAME | SND_ASYNC);
 
                map[row][col].type = 0;
                map[row][col].blood = 0;
                
            }
        }
    }
    else if (msg.message == WM_RBUTTONDOWN)//鼠标右键
    {
        curPlant = 0;
        status = 0;
    }
3. 僵尸
 3.1 创建僵尸
僵尸也是和植物一样需要创建一个结构体存放信息。然后创建一个结构体数组,作为一个僵尸池,当需要创建一个僵尸时,我们就从这个池里取一个未被使用的僵尸。

struct zm
{
    int x, y;//僵尸的坐标
    int frameIndex;//僵尸动作帧
    bool used;//僵尸是否被使用
    int speed;//僵尸每一次移动的位移
    int row;//僵尸所在行
    int blood;//僵尸血量
    bool dead;//僵尸是否死亡
    bool eating;//僵尸是否在吃植物
    bool boom;//僵尸是否被炸死
    int zmSpeed;//僵尸的移动快慢
};
struct zm zms[ZM_MAX];
//找一个可用的僵尸
int i;
for (i = 0; i < zmMax && zms[i].used && zms[i].dead == false; i++);
到一定的时间就创建一个僵尸。

 
void createZM()
{
    if (zmCount >= zmCount_max)
        return;
 
    static int zmFre = 500;
    static int count = 0;
    
    //控制僵尸的生成快慢
    count++;
    if (count > zmFre)
    {
        count = 0;
        zmFre = 200;
        int i = 0;
        int zmMax = sizeof(zms) / sizeof(zms[0]);
        for (i = 0; i < zmMax && zms[i].used && zms[i].dead == false; i++);
        if (i < zmMax)
        {
            memset(&zms[i], 0, sizeof(zms[i]));
            zms[i].used = true;
            zms[i].speed = 2;
            zms[i].row = rand() % 5;
            zms[i].y = 100 + (zms[i].row) * 100 + 70;
            zms[i].x = Wide;
            zms[i].blood = ORDINARY_ZM_BLOOD;
            zms[i].dead = false;
            zms[i].boom = false;
            zms[i].zmSpeed = 4;
            zmCount++;
        }
    }
}
3. 2 检测僵尸对植物的伤害检测
僵尸靠近植物就将僵尸置为吃东西的状态,减植物的血量,当植物的血量小于等于0时,就去除植物。

void checkZM2Zhiwu()
{
    char name[64];
    int zCount = sizeof(zms) / sizeof(zms[0]);
    for (int i = 0; i < zCount; i++)
    {
        //killCount = 0;
        if (zms[i].dead)continue;
 
        //zms[i].chomptime = 0;
        int row = zms[i].row;
        for (int j = 0; j < 9; j++)
        {
            //if (map[row][j].type == 0)continue;
            
            //
            int zhiwuX = 101 + j * 81;
            int x1 = zhiwuX;
            int x2 = zhiwuX + 81;
            int x3 = zms[i].x + 100;
            if (x3 >= x1 && x3 <= x2)
            {
                if (map[row][j].blood <= 0 || (map[row][j].type == 0 && zms[i].eating != false))
                {
                    map[row][j].blood = 0;
                    map[row][j].type = 0;
                    zms[i].eating = false;
                    //zms[i].frameIndex = 0;
                    zms[i].speed = 3;
                }
                else if (map[row][j].type != 0)
                {
                    //mciSendString("play ZM_BGM repeat", NULL, NULL, NULL);
                    //mciSendString("play name repeat", NULL, 0, NULL);
                    zms[i].eating = true;
                    zms[i].speed = 0;
                    if (map[row][j].type != 3 && map[row][j].type != 7)
                        map[row][j].blood--;
                    //zms[i].frameIndex = 0;
                }
 
            }
            else if (x3 > 830)
            {
                zms[i].eating = false;
                zms[i].speed = 3;
            }
        }
    }
}
4. 植物子弹
4.1 发射子弹
当僵尸出现在游戏界面时,与该僵尸同一行的发射性植物就发射出子弹。

同样需要创建一个结构体存放子弹的信息,然后创建一个子弹池。

//子弹
struct bullet
{
    double x, y;//子弹的坐标
    bool used;//子弹是否被使用
    int row;//子弹所在行
    int speed;//子弹速度
    bool blast;//是否发生爆炸
    int frameIndex;//帧序号
};
//坤坤
struct bullet bullets[1000];
 以坤坤为例:

void shoot()
{
    int lines[5] = { 0 };
    int bulletMax = sizeof(bullets) / sizeof(bullets[0]);
    
    int zmCount = sizeof(zms) / sizeof(zms[0]);
    int dangerX = Wide - 80;
    for (int i = 0; i < zmCount; i++)
    {
        if (zms[i].dead == false && zms[i].x < dangerX && zms[i].x>100)
        {
            lines[zms[i].row] = 1;
        }
    }
 
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 9; j++)
        {
            //坤坤
            if (map[i][j].type == KUN_KUN + 1 && lines[i])
            {
                map[i][j].shootTime++;
                if (map[i][j].shootTime > 20)
                {
                    map[i][j].shootTime = 0;
                    //子弹池
                    int k;
                    for (k = 0; k < bulletMax && bullets[k].used; k++);
                    if (k < bulletMax)
                    {
                        map[i][j].frameIndex = 3;
                        bullets[k].used = true;
                        bullets[k].row = i;
                        bullets[k].speed = 10;
 
                        bullets[k].blast = false;
                        bullets[k].frameIndex = 0;
 
                        int zwX = 256 - 150 + j * 81;
                        int zwY = 100 + i * 100 - 15;
                        bullets[k].x = zwX + imgPlant[map[i][j].type - 1][0]->getwidth() - 10;
                        bullets[k].y = zwY + 5;
                    }
                }
            }
 
            
        }
    }
}
4. 2  更新子弹
不断的改变加子弹的横坐标,当子弹出游戏界面时,子弹就被置为未被使用。

以坤坤为例:

void updateBullets_kunkun()
{
    int countMax = sizeof(bullets) / sizeof(bullets[0]);
    for (int i = 0; i < countMax; i++)
    {
        if (bullets[i].used)
        {
            bullets[i].x += bullets[i].speed;
            
            if (bullets[i].x > Wide)
            {
                bullets[i].used = false;
            }
 
        }
    }
}
 4.3 检测子弹对僵尸的伤害
当子弹靠近僵尸时减去僵尸的一定量血量,然后对僵尸造成一定的效果(例如,坤坤子弹的效果是击退僵尸,那么我们只需要更改僵尸的横坐标即可。),最后将子弹置为未被使用。

以坤坤为例:

void checkBullet2Zm_kunkun()
{
    int bCount = sizeof(bullets) / sizeof(bullets[0]);
    int zCount = sizeof(zms) / sizeof(zms[0]);
    for (int i = 0; i < bCount; i++)
    {
        {
            for (int j = 0; j < zCount; j++)
            {
                if (zms[j].used == false)continue;
                int x1 = zms[j].x + 80;
                int x2 = zms[j].x + 110;
                int x = bullets[i].x;
                if (zms[j].dead == false &&
                    bullets[i].row == zms[j].row && x > x1 && x < x2 && bullets[i].used) {
                    zms[j].blood -= 20;
                    zms[j].x += 1;
                    bullets[i].blast = true;
                    bullets[i].speed = 0;
                    //bullets[i].x = 0;
 
                    if (zms[j].blood <= 0)
                    {
                        killCount++;
 
                        zms[j].dead = true;
                        zms[j].speed = 0;
                        zms[j].frameIndex = 0;
                    }
                    break;
                }
            }
        }
    }
}
 5. 爆炸性植物
爆炸性植物是一次性的,当植物的动作帧执行完最后一帧后植物就置为死亡,在爆炸范围内的僵尸也死亡。

以火爆辣椒为例:

void checkBoom2Zm()
{
    int zCount = sizeof(zms) / sizeof(zms[0]);
 
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 9; j++)
        {
            //火爆辣椒
            else if (map[i][j].type == LA_JIAO + 1)
            {
                if (map[i][j].frameIndex > 7)
                {
                    for (int k = 0; k < zCount; k++)
                    {
                        if (zms[k].used == false)continue;
 
                        if (zms[k].row == i && zms[k].x < Wide - 80 - 70 && zms[k].dead == false)
                        {
                            killCount++;
 
                            zms[k].boom = true;
                            zms[k].dead = true;
                            zms[k].speed = 0;
                            zms[k].frameIndex = 0;
                            zms[k].blood = 0;
                        }
                    }
                    if (map[i][j].frameIndex > 14)
                    {
                        map[i][j].type = 0;
                        map[i][j].frameIndex = 0;
                    }
                }
            }
        }
    }
}
6. 小推车
 创建存放小车信息的结构体数组,小推车一条路一辆共5辆,所以我们只需写一个大小为5的结构体数组即可。

//小推车
struct car
{
    bool move;//是否处于移动状态
    int x, y;//位置
    bool used;//是否被使用
};
struct car cars[5];
放置小推车 
    for (int i = 0; i < 5; i++)
    {
        cars[i].x = 50;
        cars[i].y = 100 + i * 100 - 15;
        cars[i].used = true;
        cars[i].move = false;
    }
检测小推车对小车的伤害 
当僵尸的横坐标小于等于小推车最左端的坐标时,小车置为移动状态,处于小推车左边的僵尸死亡。

void checkcars2Zm()
{
    for (int i = 0; i < 5; i++)
    {
        int carsX = cars[i].x + 70;
        for (int j = 0; j < ZM_MAX; j++)
        {
            if (zms[j].used && zms[j].dead == false && zms[j].row == i)
            {
                int zmX = zms[j].x + 80;
                if (carsX > zmX && cars[i].used)
                {
                    if (cars[i].move == false)
                        cars[i].move = true;
                    else
                    {
                        killCount++;
                        zms[j].dead = true;
                        zms[j].speed = 0;
                        zms[j].frameIndex = 0;
                    }
                }
            }
        }
    }
}
更新小推车的位置
当小车被置为移动时,小推车开始移动。

void updatecar()
{
    for (int i = 0; i < 5; i++)
    {
        if (cars[i].move)
        {
            cars[i].x += 20;
        }
        if (cars[i].x > Wide)
        {
            cars[i].move = false;
            cars[i].used = false;
        }
    }
}
源码:
test.cpp文件: 
#include"game.h"
 
//判断文件是否存在
bool fileExist(const char* name)
{
    FILE* pf = fopen(name, "r");
    if (pf == NULL)
    {
        return false;
    }
    else
    {
        fclose(pf);
        return true;
    }
}
 
//初始化豌豆子弹的帧图片数组
void bulletsInit()
{
    //坤坤篮球
    loadimage(&imgBulletNormal, "res/bullets/basketball.png", 40, 40);
    memset(bullets, 0, sizeof(bullets));
    //初始化豌豆子弹的帧图片数组
    loadimage(&imgBallBlast[3], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png");
    for (int i = 0; i < 3; i++)
    {
        float k = (i + 1) * 0.2;
        loadimage(&imgBallBlast[i], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png",
            imgBallBlast[3].getwidth() * k,
            imgBallBlast[3].getheight() * k, true);
    }
    //豌豆子弹
    loadimage(&imgBulletNormal_wandou, "res/bullets/bullet_normal.png");
    memset(bullets_wandou, 0, sizeof(bullets_wandou));
    //初始化豌豆子弹的帧图片数组
    loadimage(&imgBallBlast_wandou[3], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png");
    for (int i = 0; i < 3; i++)
    {
        float k = (i + 1) * 0.2;
        loadimage(&imgBallBlast_wandou[i], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png",
            imgBallBlast_wandou[3].getwidth() * k,
            imgBallBlast_wandou[3].getheight() * k, true);
    }
    //寒冰豌豆子弹
    loadimage(&imgBulletNormal_hanbing, "res/bullets/PeaIce/PeaIce_0.png");
    memset(bullets_hanbing, 0, sizeof(bullets_hanbing));
    //初始化豌豆子弹的帧图片数组
    loadimage(&imgBallBlast_hanbing[3], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png");
    for (int i = 0; i < 3; i++)
    {
        float k = (i + 1) * 0.2;
        loadimage(&imgBallBlast_hanbing[i], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png",
            imgBallBlast_hanbing[3].getwidth() * k,
            imgBallBlast_hanbing[3].getheight() * k, true);
    }
    //三头豌豆子弹
    loadimage(&imgBulletNormal_santou, "res/bullets/bullet_normal.png");
    memset(bullets_santou, 0, sizeof(bullets_santou));
    //初始化豌豆子弹的帧图片数组
    loadimage(&imgBallBlast_santou[3], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png");
    for (int i = 0; i < 3; i++)
    {
        float k = (i + 1) * 0.2;
        loadimage(&imgBallBlast_santou[i], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png",
            imgBallBlast_santou[3].getwidth() * k,
            imgBallBlast_santou[3].getheight() * k, true);
    }
}
 
void gameInit()
{
    char name[64];
    //音效
    mciSendString("open res/bg.mp3 alias BGM", NULL, NULL, NULL);
    mciSendString("open res/audio/UraniwaNi.mp3 alias BGM2", NULL, NULL, NULL);
    mciSendString("open res/audio/WateryGraves.mp3 alias BGM3", NULL, NULL, NULL);
    mciSendString("open res/audio/readysetplant.mp3 alias BGM4", NULL, NULL, NULL);
    mciSendString("open res/audio/chomp.mp3 alias ZM_BGM", NULL, NULL, NULL);
    
    loadimage(&img, "res/map/map0.jpg");
    loadimage(&imgBar, "res/bar5.png");
    //loadimage(&imgnotify, "res/screen/PanelBackground.png");
    
    memset(imgPlant, 0, sizeof(imgPlant));
    memset(map, 0, sizeof(map));
    memset(cars, 0, sizeof(cars));
 
    //开场动画
    for (int i = 0; i < 29; i++)
    {
        sprintf_s(name, sizeof(name), "res/yuanshen/%d.png", i + 1);
        loadimage(&imgopena[i], name, 1196, 670);
    }
 
    //植物卡牌
    for (int i = 0; i < PLANT_COUNT + 2; i++)
    {
        sprintf_s(name, sizeof(name), "res/Cards/card_%d.png", i + 1);
        loadimage(&imgCards[i], name,64,89);
 
        for (int j = 0; j < 20; j++)
        {
            sprintf_s(name, sizeof(name), "res/zhiwu/%d/%d.png",i , j + 1);
            //先判断文件是否存在
            if (fileExist(name))
            {
                imgPlant[i][j] = new IMAGE;
                if (i != 3)
                {
                    loadimage(imgPlant[i][j], name);
                }
                else
                {
                    loadimage(imgPlant[i][j], name,65,100);
                }
            }
            else
            {
                break;
            }
        }
    }
 
    memset(balls, 0, sizeof(balls));
    for (int i = 0; i < 29; i++)
    {
        sprintf_s(name, sizeof(name), "res/sunshine/%d.png", i + 1);
        loadimage(&imgSunshineBall[i], name);
    }
 
    curPlant = 0;
    sunshine = 50;
 
    initgraph(Wide, Hight);
 
    //设置字体
    LOGFONT f;
    gettextstyle(&f);
    f.lfHeight = 30;
    f.lfWeight = 15;
    strcpy(f.lfFaceName, "Segoe UI Black");
    f.lfQuality = ANTIALIASED_QUALITY;//抗锯齿效果
    settextstyle(&f);
    setbkmode(TRANSPARENT);//字体透明
    setcolor(BLACK);
 
    //初始化子弹的帧图片数组
    bulletsInit();
 
    //初始化僵尸数据
    memset(zms, 0, sizeof(zms));
    for (int i = 0; i < 22; i++)
    {
        sprintf_s(name, sizeof(name), "res/zm/%d.png", i + 1);
        loadimage(&imgZm[i], name);
    }
 
    killCount = 0;
    zmCount = 0;
    gameStatus = GOING;
 
    //初始化僵尸
    for (int i = 0; i < 38; i++)
    {
        sprintf_s(name, sizeof(name), "res/zm_dead/%d.png",i + 1);
        loadimage(&imgZMDead[i], name);
    }
 
    for (int i = 0; i < 21; i++)
    {
        sprintf_s(name, sizeof(name), "res/zm_eat/%d.png", i + 1);
        loadimage(&imgZMEat[i], name);
    }
 
    for (int i = 0; i < 11; i++)
    {
        sprintf_s(name, sizeof(name), "res/zm_stand/%d.png", i + 1);
        loadimage(&imgZmStand[i], name);
    }
    for (int i = 0; i < 20; i++)
    {
        sprintf_s(name, sizeof(name), "res/zm_dead2/%d.png", i + 1);
        loadimage(&imgzmboom[i], name);
    }
    //小推车
    loadimage(&imgcar, "res/Screen/car.png");
    for (int i = 0; i < 5; i++)
    {
        cars[i].x = 50;
        cars[i].y = 100 + i * 100 - 15;
        cars[i].used = true;
        cars[i].move = false;
    }
    //StartButton
    loadimage(&imgready, "res/Screen/Boom.png");
}
 
void drawZm()
{
    int zmCount = sizeof(zms) / sizeof(zms[0]);
    for (int i = 0; i < zmCount; i++)
    {
        if (zms[i].used)
        {//IMAGE* img = (zms[i].dead) ? &imgZMDead[zms[i].frameIndex] : &imgZm[zms[i].frameIndex];
            IMAGE* img = NULL;
            if (zms[i].dead)
            {
                if (zms[i].boom == true)
                    img = &imgzmboom[zms[i].frameIndex];
                else
                    img = &imgZMDead[zms[i].frameIndex];
            }
            else if (zms[i].eating) img = &imgZMEat[zms[i].frameIndex];
            else img = &imgZm[zms[i].frameIndex];
 
            putimagePNG(zms[i].x, zms[i].y - img->getheight(), img);
        }
    }
}
 
void drawSunshine()
{
    int ballMax = sizeof(balls) / sizeof(balls[0]);
    for (int i = 0; i < ballMax; i++)
    {
        //if (balls[i].used || balls[i].xoff)
        if(balls[i].used)
        {
            IMAGE* img = &imgSunshineBall[balls->frameIndex];
            //putimagePNG(balls[i].x, balls[i].y, img);
            putimagePNG(balls[i].pCur.x, balls[i].pCur.y, img);
        }
    }
}
 
void drawBullets_kunkun()
{
    int bulletsMax = sizeof(bullets) / sizeof(bullets[0]);
    for (int i = 0; i < bulletsMax; i++)
    {
        if (bullets[i].used) {
            if (bullets[i].blast) {
                IMAGE* img = &imgBallBlast[bullets[i].frameIndex];
                putimagePNG(bullets[i].x, bullets[i].y - 10, img);
            }
            else {
                putimagePNG(bullets[i].x, bullets[i].y, &imgBulletNormal);
            }
        }
    }
}
 
void drawBullets_wandou()
{
    int bulletsMax = sizeof(bullets_wandou) / sizeof(bullets_wandou[0]);
    for (int i = 0; i < bulletsMax; i++)
    {
        if (bullets_wandou[i].used) {
            if (bullets_wandou[i].blast) {
                IMAGE* img = &imgBallBlast_wandou[bullets_wandou[i].frameIndex];
                putimagePNG(bullets_wandou[i].x, bullets_wandou[i].y, img);
            }
            else {
                putimagePNG(bullets_wandou[i].x, bullets_wandou[i].y, &imgBulletNormal_wandou);
            }
        }
    }
}
 
void drawBullets_hanbing()
{
    int bulletsMax = sizeof(bullets_hanbing) / sizeof(bullets_hanbing[0]);
    for (int i = 0; i < bulletsMax; i++)
    {
        if (bullets_hanbing[i].used) {
            if (bullets_hanbing[i].blast) {
                IMAGE* img = &imgBallBlast_hanbing[bullets_hanbing[i].frameIndex];
                putimagePNG(bullets_hanbing[i].x, bullets_hanbing[i].y, img);
            }
            else {
                putimagePNG(bullets_hanbing[i].x, bullets_hanbing[i].y, &imgBulletNormal_hanbing);
            }
        }
    }
}
 
void drawBullets_santou()
{
    int bulletsMax = sizeof(bullets_santou) / sizeof(bullets_santou[0]);
    for (int i = 0; i < bulletsMax; i++)
    {
        if (bullets_santou[i].used) {
            if (bullets_santou[i].blast) {
                IMAGE* img = &imgBallBlast_santou[bullets_santou[i].frameIndex];
                putimagePNG(bullets_santou[i].x, bullets_santou[i].y, img);
            }
            else {
                putimagePNG(bullets_santou[i].x, bullets_santou[i].y, &imgBulletNormal_santou);
            }
        }
    }
}
 
void drawBullets()
{
    //坤坤
    drawBullets_kunkun();
    //豌豆
    drawBullets_wandou();
    //寒冰豌豆
    drawBullets_hanbing();
    //三头豌豆
    drawBullets_santou();
}
 
void show()//渲染游戏画面
{
    BeginBatchDraw();
 
    putimage(-150, 0, &img);
    putimagePNG(80, -10, &imgBar);
    char scoreText[8];
    char scoreText1[16];
    sprintf_s(scoreText, sizeof(scoreText), "%d", sunshine);
    sprintf_s(scoreText1, sizeof(scoreText1), "Wave %d zombies", wava_count);
    //sprintf_s(name, sizeof(name), "res/yuanshen/%d.png", i + 1);
    outtextxy(105, 60, scoreText);
    outtextxy(700, 570, scoreText1);
    //outtextxy(700, 570, "s");
 
    //小推车
    for (int i = 0; i < 5; i++)
    {
        if(cars[i].used)
            putimagePNG(cars[i].x, cars[i].y, &imgcar);
    }
 
    //植物卡牌
    for (int i = 0; i < PLANT_COUNT + 2; i++)
    {
        if(i==PLANT_COUNT)
            putimagePNG(163 + i * 65 + 8, -5, &imgCards[i]);
        else
            putimagePNG(163 + i * 65, 0, &imgCards[i]);
    }
 
 
    //植物
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 9; j++)
        {
            if (map[i][j].type > 0)
            {
                /*int x = 256 - 150 + j * 81;
                int y = 100 + i * 100 - 15;*/
                int PlantType = map[i][j].type - 1;
                int index = map[i][j].frameIndex;
                if (map[i][j].type != 4 && map[i][j].type != YING_TAO + 1 && map[i][j].type != LA_JIAO + 1)
                {
                    putimagePNG(map[i][j].x, map[i][j].y, imgPlant[PlantType][index]);
                }
                else if (map[i][j].type == YING_TAO + 1)
                {
                    if (index == 8)
                        putimagePNG(map[i][j].x - 75, map[i][j].y-35, imgPlant[PlantType][index]);
                    else
                        putimagePNG(map[i][j].x - 22, map[i][j].y, imgPlant[PlantType][index]);
                }
                else if (map[i][j].type == LA_JIAO + 1)
                {
                    if (index > 7)
                        putimagePNG(100, map[i][j].y - 35, imgPlant[PlantType][index]);
                    else
                        putimagePNG(map[i][j].x, map[i][j].y, imgPlant[PlantType][index]);
                }
                else
                {
                    putimagePNG(map[i][j].x + 5, map[i][j].y - 20, imgPlant[PlantType][index]);
                }
            }
        }
    }
 
    //渲染子弹
    drawBullets();
 
    //铲子
    if (curPlant != PLANT_COUNT + 1)
    {
        IMAGE* img = imgPlant[8][0];
        putimagePNG(163 + 8 * 65 + 8, 0, img);
    }
 
    //僵尸
    drawZm();
 
    //渲染拖动中的植物
    if (curPlant > 0)
    {
        IMAGE* img = imgPlant[curPlant - 1][0];
        putimagePNG(curX - img->getwidth() / 2, curY - img->getheight() / 2, img);
    }
 
    //渲染阳光
    drawSunshine();
    EndBatchDraw();
}
 
void collectSunshine(ExMessage* msg)
{
    int count = sizeof(balls) / sizeof(balls[0]);
    int w = imgSunshineBall[0].getwidth();
    int h = imgSunshineBall[0].getheight();
    for (int i = 0; i < count; i++)
    {
        if (balls[i].used)
        {
            //int x = balls[i].x;
            //int y = balls[i].y;
            int x = balls[i].pCur.x;
            int y = balls[i].pCur.y;
 
            if (msg->x > x && msg->x<x + w
                && msg->y>y && msg->y < y + h)
            {
                sunshine += 25;
                //balls[i].used = false;
                balls[i].status = SUNSHINE_COLLECT;
                //音效
                //mciSendString("play res/sunshine.mp3", 0, 0, 0);
                //不支持MP3格式
                PlaySound("res/sunshine.wav", NULL, SND_FILENAME | SND_ASYNC);
                balls[i].p1 = balls[i].pCur;
                balls[i].p4 = vector2(100, 0);
                balls[i].t = 0;
                float distance = dis(balls[i].p1 - balls[i].p4);
                float off = 8;
                balls[i].speed = 1.0 / (distance / off);
                break;
                /*float destX = 0;
                float destY = 262;
                float angle = atan((y - destY) / (x - destX));
                balls[i].xoff = 4 * cos(angle);
                balls[i].yoff = 4 * sin(angle);*/
            }
        }
    }
}
 
void userClick()
{
    ExMessage msg;
    static int status = 0;
    if (peekmessage(&msg))//判断有没有消息
    {
        if (msg.message == WM_LBUTTONDOWN)//左键按下
        {
            if (msg.x > 163 && msg.x < 163 + 65 * (PLANT_COUNT+2) && msg.y < 96)
            {
                //mciSendString("play res/audio/bleep.mp3 alias BGM4", NULL, NULL, NULL);
                PlaySound("res/audio/bleep.wav", NULL, SND_FILENAME | SND_ASYNC);
                //PlaySound("res/sunshine.wav", NULL, SND_FILENAME | SND_ASYNC);
 
                int index = (msg.x - 163) / 65;
                //坤坤
            /*    if (index + 1 == KUN_KUN && sunshine >= 100)
                {
                    curPlant = index + 1;
                    status = 1;
                    curX = msg.x;
                    curY = msg.y;
                    sunshine -= 100;
                }*/
                curPlant = index + 1;
                status = 1;
                curX = msg.x;
                curY = msg.y;
            }
            else
            {
                collectSunshine(&msg);
            }
        }
        else if (msg.message == WM_MOUSEMOVE && status == 1)//鼠标移动
        {
            curX = msg.x;
            curY = msg.y;
        }
        else if (msg.message == WM_LBUTTONUP)//鼠标放下
        {
            if (msg.x > 256 - 150 && msg.x < Wide - 70 && msg.y > 100 && msg.y < 590)
            {
                int row = (msg.y - 100) / 102;
                int col = (msg.x - 256 + 150 ) / 81;
                
                
                if (map[row][col].type == 0 && curPlant != PLANT_COUNT + 1 && curPlant != PLANT_COUNT + 2)
                {
                    //printf("%d\n", map[col][row].type);
                    map[row][col].type = curPlant;
                    map[row][col].frameIndex = 0;
 
                    if(curPlant!=0)
                        PlaySound("res/audio/coffee.wav", NULL, SND_FILENAME | SND_ASYNC);
 
                    if (curPlant == 5)
                        map[row][col].blood = KUNKUN_BLOOD * 50;
                    else
                        map[row][col].blood = KUNKUN_BLOOD;
 
                    map[row][col].shootTime = 0;
                    map[row][col].shoot = false;
 
                    map[row][col].x = 256 - 150 + col * 81;
                    map[row][col].y = 100 + row * 100 - 15;
                    
                }
                else if (map[row][col].type != 0 && curPlant == PLANT_COUNT + 1)
                {
                    PlaySound("res/audio/coffee.wav", NULL, SND_FILENAME | SND_ASYNC);
 
                    map[row][col].type = 0;
                    map[row][col].blood = 0;
                    
                }
                else if (curPlant == PLANT_COUNT + 2)
                {
 
                    if (zmCount >= ZM_MAX)
                        return;
 
                    int i = 0;
                    int zmMax = sizeof(zms) / sizeof(zms[0]);
                    for (i = 0; i < zmMax && zms[i].used; i++);
                    if (i < zmMax)
                    {
                        PlaySound("res/audio/coffee.wav", NULL, SND_FILENAME | SND_ASYNC);
                        memset(&zms[i], 0, sizeof(zms[i]));
                        zms[i].used = true;
                        zms[i].speed = 2;
                        zms[i].row = row;
                        zms[i].y = 100 + (zms[i].row) * 100 + 70;
                        zms[i].x = 256 - 150 + (col - 1) * 81;
                        zms[i].blood = ORDINARY_ZM_BLOOD;
                        zms[i].dead = false;
                        zms[i].boom = false;
                        zms[i].zmSpeed = 4;
                        zmCount++;
                    }
                }
            }
        }
        else if (msg.message == WM_RBUTTONDOWN)
        {
            curPlant = 0;
            status = 0;
        }
    }
}
 
void createSunshine()
{
 
    static int count = 0;
    static int fre = 200;
    count++;
    if (count >= fre)
    {
        fre = 200 + rand() % 200;
        count = 0;
 
        //从阳光池取一个可以使用的
        int ballMax = sizeof(balls) / sizeof(balls[0]);
 
        int i;
        for (i = 0; i < ballMax && balls[i].used; i++);
            if (i >= ballMax)return;
 
            balls[i].used = true;
            balls[i].frameIndex = 0;
        /*    balls[i].x = 160 + rand() % 600;
            balls[i].y = 60;
            balls[i].destY = (rand() % 4) * 90 + 160;*/
            balls[i].timer = 0;
        /*    balls[i].xoff = 0;
            balls[i].yoff = 0;*/
 
            balls[i].status = SUNSHINE_DOWN;
            balls[i].t = 0;
            balls[i].p1 = vector2(160 + rand() % 600, 60);
            balls[i].p4 = vector2(balls[i].p1.x, (rand() % 4) * 90 + 160);
            int off = 2;
            float distance = balls[i].p4.y - balls[i].p1.y;
            balls[i].speed = 1.0 / (distance / off);
    }
 
    int ballMax = sizeof(balls) / sizeof(balls[0]);
    //向日葵生产阳光
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 9; j++)
        {
            if (map[i][j].type == TAI_YANG + 1)
            {
                map[i][j].timer++;
                if (map[i][j].timer > 100)
                {
                    map[i][j].timer = 0;
 
                    int k;
                    for (k = 0; k < ballMax && balls[k].used; k++);
                    if (k >= ballMax)return;
 
                    balls[k].used = true;
                    balls[k].p1 = vector2(map[i][j].x, map[i][j].y);
                    int w = (40 + rand() % 50) * (rand() % 2 ? 1 : -1);
                    balls[k].p4 = vector2(map[i][j].x + w,
                        map[i][j].y + imgPlant[TAI_YANG][0]->getheight() - imgSunshineBall[0].getheight());
                    balls[k].p2 = vector2(balls[k].p1.x + w * 0.3, balls[k].p1.y - 100);
                    balls[k].p3 = vector2(balls[k].p1.x + w * 0.7, balls[k].p1.y - 100);
                    balls[k].status = SUNSHINE_RPODUCT;
                    balls[k].speed = 0.05;
                    balls[k].t = 0;
                }
            }
        }
    }
 
}
 
void updatSunshine()
{
    int ballMax = sizeof(balls) / sizeof(balls[0]);
    for (int i = 0; i < ballMax; i++)
    {
        if (balls[i].used)
        {
            balls[i].frameIndex = (balls[i].frameIndex + 1) % 29;
            if (balls[i].status == SUNSHINE_DOWN)
            {
                struct sunshineBall* sun = &balls[i];
                sun->t += sun->speed;
                sun->pCur = sun->p1 + sun->t * (sun->p4 - sun->p1);
                if (sun->t >= 1)
                {
                    sun->status = SUNSHINE_GROUND;
                    sun->timer = 0;
                }
            }
            else if (balls[i].status == SUNSHINE_GROUND)
            {
                balls[i].timer++;
                if (balls[i].timer > 100)
                {
                    balls[i].used = false;
                    balls[i].timer = 0;
                }
            }
            else if (balls[i].status == SUNSHINE_COLLECT)
            {
                struct sunshineBall* sun = &balls[i];
                sun->t += sun->speed;
                sun->pCur = sun->p1 + sun->t * (sun->p4 - sun->p1);
                if (sun->t > 1)
                {
                    sun->used = false;
                    sunshine += 25;
                }
            }
            else if (balls[i].status == SUNSHINE_RPODUCT)
            {
                struct sunshineBall* sun = &balls[i];
                sun->t += sun->speed;
                sun->pCur = calcBezierPoint(sun->t,sun->p1, sun->p2, sun->p3, sun->p4);
                if (sun->t > 1)
                {
                    sun->status = SUNSHINE_GROUND;
                    sun->timer = 0;
                }
 
            }
        }
    }
}
 
int mciZmTime = 0;
void createZM()
{
    if (zmCount >= zmCount_max)
        return;
 
    static int zmFre = 5000000;
    static int count = 0;
    
    count++;
    if (count > zmFre)
    {
        if (mciZmTime == 0)
        {
            mciSendString("play res/audio/awooga.mp3", 0, 0, 0);
            mciZmTime++;
        }
        count = 0;
        zmFre = 202 - 20 * wava_count;
        int i = 0;
        int zmMax = sizeof(zms) / sizeof(zms[0]);
        for (i = 0; i < zmMax && zms[i].used && zms[i].dead == false; i++);
        if (i < zmMax)
        {
            memset(&zms[i], 0, sizeof(zms[i]));
            zms[i].used = true;
            zms[i].speed = 2;
            zms[i].row = rand() % 5;
            zms[i].y = 100 + (zms[i].row) * 100 + 70;
            zms[i].x = Wide;
            zms[i].blood = ORDINARY_ZM_BLOOD;
            zms[i].dead = false;
            zms[i].boom = false;
            zms[i].zmSpeed = 4;
            zmCount++;
        }
    }
}
 
int zmSpeed = 6;
void updateZM()
{
    int zmMax = sizeof(zms) / sizeof(zms[0]);
    static int count[ZM_MAX] = { 0 };
    //更新僵尸的位置
    for (int i = 0; i < zmMax; i++)
    {
        count[i]++;
        if (count[i] >= (gameStatus == GOING ? zms[i].zmSpeed : zmSpeed))
        {
            //printf("%d ", (gameStatus == GOING ? zms[i].zmSpeed : zmSpeed));
            count[i] = 0;
 
            if (zms[i].used)
            {
                if (zms[i].dead)
                {
                    zms[i].frameIndex++;
                    if (zms[i].boom == true)
                    {
                        if (zms[i].frameIndex >= 20)
                        {
                            //printf("%d ", killCount);
                            zms[i].used = false;
                            zms[i].row = 0;
                            //killCount++;
                            if (killCount >= ZM_MAX)
                                gameStatus = WIN;
                            else if (killCount >= zmCount_max)
                            {
                                wava_count++;
                                zmCount_max *= 2;
                                killCount = 0;
                                zmCount = 0;
                            }
                        }
                    }
                    else
                    {
                        if (zms[i].frameIndex >= 38)
                        {
                            //printf("%d ", killCount);
 
                            zms[i].used = false;
                            zms[i].row = 0;
                            
                            if (killCount >= ZM_MAX)
                                gameStatus = WIN;
                            else if (killCount >= zmCount_max)
                            {
                                wava_count++;
                                zmCount_max *= 2;
                                killCount = 0;
                                zmCount = 0;
                            }
                        }
                    }
                }
                else if (zms[i].eating)
                {
 
                    //mciSendString("play res/audio/chomp.mp3", 0, 0, 0);
                    //mciSendString("play res/audio/chompsoft.mp3", 0, 0, 0);
                    zms[i].frameIndex = (zms[i].frameIndex + 1) % 21;
                }
                else
                {
                    zms[i].frameIndex++;
                    if (zms[i].frameIndex >= 22)
                    {
                        zms[i].frameIndex = 0;
                    }
                }
                zms[i].x -= zms[i].speed;
                if (zms[i].x < 0)
                {
                    //printf("GAME OVER\n");
                    //MessageBox(NULL, "over", "over", 0);//待优化
                    //exit(0);//待优化
                    gameStatus = FAIL;
                }
            }
        }
    }
}
 
void shoot()
{
    int lines[5] = { 0 };
    int bulletMax = sizeof(bullets) / sizeof(bullets[0]);
    int bulletMax_wandou = sizeof(bullets_wandou) / sizeof(bullets_wandou[0]);
    int bulletMax_hanbing = sizeof(bullets_hanbing) / sizeof(bullets_hanbing[0]);
    int bulletMax_santou = sizeof(bullets_santou) / sizeof(bullets_santou[0]);
    int zmCount = sizeof(zms) / sizeof(zms[0]);
    int dangerX = Wide - 80;
    for (int i = 0; i < zmCount; i++)
    {
        if (zms[i].dead == false && zms[i].x < dangerX && zms[i].x>100)
        {
            lines[zms[i].row] = 1;
        }
    }
 
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 9; j++)
        {
            //坤坤
            if (map[i][j].type == KUN_KUN + 1 && lines[i])
            {
                map[i][j].shootTime++;
                if (map[i][j].shootTime > 20)
                {
                    map[i][j].shootTime = 0;
 
                    int k;
                    for (k = 0; k < bulletMax && bullets[k].used; k++);
                    if (k < bulletMax)
                    {
                        map[i][j].frameIndex = 3;
                        bullets[k].used = true;
                        bullets[k].row = i;
                        bullets[k].speed = 10;
 
                        bullets[k].blast = false;
                        bullets[k].frameIndex = 0;
 
                        int zwX = 256 - 150 + j * 81;
                        int zwY = 100 + i * 100 - 15;
                        bullets[k].x = zwX + imgPlant[map[i][j].type - 1][0]->getwidth() - 10;
                        bullets[k].y = zwY + 5;
                    }
                }
            }
 
            //豌豆
            else if (map[i][j].type == WAN_DOU + 1 && lines[i])
            {
                map[i][j].shootTime++;
                if (map[i][j].shootTime > 35)
                {
                    map[i][j].shootTime = 0;
                    int k;
                    for (k = 0; k < bulletMax_wandou && bullets_wandou[k].used; k++);
                    if (k < bulletMax_wandou)
                    {
                        //map[i][j].shoot = true;
                        //if(map[i][j].frameIndex > 1)
                        map[i][j].frameIndex = 2;
                        bullets_wandou[k].used = true;
                        bullets_wandou[k].row = i;
                        bullets_wandou[k].speed = 8;
 
                        bullets_wandou[k].blast = false;
                        bullets_wandou[k].frameIndex = 0;
 
                        int zwX = 256 - 150 + j * 81;
                        int zwY = 100 + i * 100 - 15;
                        bullets_wandou[k].x = zwX + imgPlant[map[i][j].type - 1][0]->getwidth() - 10;
                        bullets_wandou[k].y = zwY + 5;
                    }
                }
            }
 
            //寒冰豌豆
            else if (map[i][j].type == HAN_BING_WAN_DOU + 1 && lines[i])
            {
                map[i][j].shootTime++;
                if (map[i][j].shootTime > 35)
                {
                    map[i][j].shootTime = 0;
                    int k;
                    for (k = 0; k < bulletMax_hanbing && bullets_hanbing[k].used; k++);
                    if (k < bulletMax_hanbing)
                    {
                        //map[i][j].shoot = true;
                        //if(map[i][j].frameIndex > 1)
                        map[i][j].frameIndex = 4;
                        bullets_hanbing[k].used = true;
                        bullets_hanbing[k].row = i;
                        bullets_hanbing[k].speed = 10;
 
                        bullets_hanbing[k].blast = false;
                        bullets_hanbing[k].frameIndex = 0;
 
                        int zwX = 256 - 150 + j * 81;
                        int zwY = 100 + i * 100 - 15;
                        bullets_hanbing[k].x = zwX + imgPlant[map[i][j].type - 1][0]->getwidth() - 10;
                        bullets_hanbing[k].y = zwY + 5;
                    }
                }
            }
 
            //三头豌豆
            else if (map[i][j].type == SAN_TOU_WAN_DOU + 1 && lines[i])
            {
                map[i][j].shootTime++;
                if (map[i][j].shootTime > 35)
                {
                    map[i][j].shootTime = 0;
                    int k;
                    for (int b = 0; b < 3; b++)
                    {
                        for (k = 0; k < bulletMax_santou && bullets_santou[k].used; k++);
                        if (k < bulletMax_santou)
                        {
                            //map[i][j].shoot = true;
                            //if(map[i][j].frameIndex > 1)
                            //map[i][j].frameIndex = 2;
                            bullets_santou[k].used = true;
                            bullets_santou[k].row = i;
                            bullets_santou[k].speed = 8;
 
                            bullets_santou[k].blast = false;
                            bullets_santou[k].frameIndex = 0;
 
                            int zwX = 256 - 150 + j * 81;
                            int zwY = 100 + i * 100 - 15;
                            bullets_santou[k].x = zwX + imgPlant[map[i][j].type - 1][0]->getwidth() - 30;
                            bullets_santou[k].y = zwY + 16;
                            direction_santou[k] = b;
                            row_santou[k] = i;
                        }
                    }
                }
            }
        }
    }
}
 
void updateBullets_kunkun()
{
    int countMax = sizeof(bullets) / sizeof(bullets[0]);
    for (int i = 0; i < countMax; i++)
    {
        if (bullets[i].used)
        {
            //static double angle = 0;
            bullets[i].x += bullets[i].speed;
            //angle += bullets[i].speed;
            //bullets[i].y += 10;
 
            //bullets[i].x += bullets[i].speed;
            if (bullets[i].x > Wide)
            {
                bullets[i].used = false;
            }
 
            //待完善
            if (bullets[i].blast)
            {
                bullets[i].frameIndex++;
                if (bullets[i].frameIndex >= 4)
                {
                    bullets[i].used = false;
                }
            }
        }
    }
}
 
void updateBullets_wandou()
{
    int countMax_wandou = sizeof(bullets_wandou) / sizeof(bullets_wandou[0]);
    for (int i = 0; i < countMax_wandou; i++)
    {
        if (bullets_wandou[i].used)
        {
            //static double angle = 0;
            bullets_wandou[i].x += bullets_wandou[i].speed;
            //angle += bullets[i].speed;
            //bullets[i].y += 10;
 
            //bullets[i].x += bullets[i].speed;
            if (bullets_wandou[i].x > Wide)
            {
                bullets_wandou[i].used = false;
            }
 
            //待完善
            if (bullets_wandou[i].blast)
            {
                bullets_wandou[i].frameIndex++;
                if (bullets_wandou[i].frameIndex >= 4)
                {
                    bullets_wandou[i].used = false;
                }
            }
        }
    }
}
 
void updateBullets_hanbing()
{
    int countMax_hanbing = sizeof(bullets_hanbing) / sizeof(bullets_hanbing[0]);
    for (int i = 0; i < countMax_hanbing; i++)
    {
        if (bullets_hanbing[i].used)
        {
            //static double angle = 0;
            bullets_hanbing[i].x += bullets_hanbing[i].speed;
            //angle += bullets[i].speed;
            //bullets[i].y += 10;
 
            //bullets[i].x += bullets[i].speed;
            if (bullets_hanbing[i].x > Wide)
            {
                bullets_hanbing[i].used = false;
            }
 
            //待完善
            if (bullets_hanbing[i].blast)
            {
                bullets_hanbing[i].frameIndex++;
                if (bullets_hanbing[i].frameIndex >= 4)
                {
                    bullets_hanbing[i].used = false;
                }
            }
        }
    }
}
 
void updateBullets_santou()
{
    int countMax_santou = sizeof(bullets_santou) / sizeof(bullets_santou[0]);
    for (int i = 0; i < countMax_santou; i++)
    {
        if (bullets_santou[i].used)
        {
            if (direction_santou[i] == MIDDLE)
            {//static double angle = 0;
                bullets_santou[i].x += bullets_santou[i].speed;
 
                //bullets[i].x += bullets[i].speed;
                if (bullets_santou[i].x > Wide)
                {
                    bullets_santou[i].used = false;
                }    
            }
            else if (direction_santou[i] == UP)
            {
                int destY = 85 + (row_santou[i] - 1) * 100;
                //int zwX = 256 - 150 + j * 81;
                float angle = atan(0.6);
                bullets_santou[i].x += bullets_santou[i].speed;
                bullets_santou[i].y -= bullets_santou[i].speed * tan(angle);
                //printf("%d\n", row_santou[i]);
                //printf("destY = %d\n", destY);
                //printf("bullets[i].y = %lf\n", bullets[i].y);
                if (bullets_santou[i].y <= destY + 16)
                {
                    direction_santou[i] = MIDDLE;
                }
 
            }
            else if (direction_santou[i] == DOWN)
            {
                int destY = 85 + (row_santou[i] + 1) * 100;
                float angle = atan(0.6);
                bullets_santou[i].x += bullets_santou[i].speed;
                bullets_santou[i].y += bullets_santou[i].speed * tan(angle);
                if (bullets_santou[i].y >= destY + 16)
                {
                    direction_santou[i] = MIDDLE;
                }
            }
            //待完善
            if (bullets_santou[i].blast)
            {
                bullets_santou[i].frameIndex++;
                if (bullets_santou[i].frameIndex >= 4)
                {
                    bullets_santou[i].used = false;
                }
            }
        }
    }
}
 
void updateBullets()
{
    //坤坤
    updateBullets_kunkun();
    //豌豆射手
    updateBullets_wandou();
    //寒冰豌豆
    updateBullets_hanbing();
    //三头豌豆
    updateBullets_santou();
}
 
void checkBullet2Zm_kunkun()
{
    int bCount = sizeof(bullets) / sizeof(bullets[0]);
    int zCount = sizeof(zms) / sizeof(zms[0]);
    for (int i = 0; i < bCount; i++)
    {
        //if (bullets[i].used || bullets[i].blast == false)
        {
            for (int j = 0; j < zCount; j++)
            {
                if (zms[j].used == false)continue;
                int x1 = zms[j].x + 80;
                int x2 = zms[j].x + 110;
                int x = bullets[i].x;
                if (zms[j].dead == false &&
                    bullets[i].row == zms[j].row && x > x1 && x < x2 && bullets[i].used) {
                    zms[j].blood -= 20;
                    zms[j].x += 1;
                    bullets[i].blast = true;
                    bullets[i].speed = 0;
                    //bullets[i].x = 0;
 
                    if (zms[j].blood <= 0)
                    {
                        killCount++;
 
                        zms[j].dead = true;
                        zms[j].speed = 0;
                        zms[j].frameIndex = 0;
                    }
                    break;
                }
            }
        }
    }
}
 
void checkBullet2Zm_wandou()
{
    int bCount = sizeof(bullets_wandou) / sizeof(bullets_wandou[0]);
    int zCount = sizeof(zms) / sizeof(zms[0]);
    for (int i = 0; i < bCount; i++)
    {
        //if (bullets[i].used || bullets[i].blast == false)
            for (int j = 0; j < zCount; j++)
            {
                if (zms[j].used == false)continue;
                int x1 = zms[j].x + 80;
                int x2 = zms[j].x + 110;
                int x = bullets_wandou[i].x;
                if (zms[j].dead == false &&
                    bullets_wandou[i].row == zms[j].row && x > x1 && x < x2 && bullets_wandou[i].used) {
                    zms[j].blood -= 20;
                    bullets_wandou[i].blast = true;
                    bullets_wandou[i].speed = 0;
                    //bullets_wandou[i].x = 0;
 
                    if (zms[j].blood <= 0)
                    {
                        killCount++;
 
                        zms[j].dead = true;
                        zms[j].speed = 0;
                        zms[j].frameIndex = 0;
                    }
                    break;
                }
            }
    }
}
 
void checkBullet2Zm_hanbing()
{
    int bCount = sizeof(bullets_hanbing) / sizeof(bullets_hanbing[0]);
    int zCount = sizeof(zms) / sizeof(zms[0]);
    for (int i = 0; i < bCount; i++)
    {
        //if (bullets[i].used || bullets[i].blast == false)
        for (int j = 0; j < zCount; j++)
        {
            if (zms[j].used == false)continue;
            int x1 = zms[j].x + 80;
            int x2 = zms[j].x + 110;
            int x = bullets_hanbing[i].x;
            if (zms[j].dead == false &&
                bullets_hanbing[i].row == zms[j].row && x > x1 && x < x2 && bullets_hanbing[i].used) {
                zms[j].blood -= 20;
                zms[j].zmSpeed = 7;
                bullets_hanbing[i].blast = true;
                bullets_hanbing[i].speed = 0;
                //bullets_hanbing[i].x = 0;
 
                if (zms[j].blood <= 0)
                {
                    killCount++;
                    zms[j].dead = true;
                    zms[j].speed = 0;
                    zms[j].frameIndex = 0;
                    zms[j].zmSpeed = 4;
                }
                break;
            }
        }
    }
}
 
void checkBullet2Zm_santou()
{
    int bCount = sizeof(bullets_santou) / sizeof(bullets_santou[0]);
    int zCount = sizeof(zms) / sizeof(zms[0]);
    for (int i = 0; i < bCount; i++)
    {
        bullets_santou[i].row = (bullets_santou[i].y - 85+5) / 100;
        //if (bullets[i].used || bullets[i].blast == false)
        for (int j = 0; j < zCount; j++)
        {
            //100 + i * 100 - 15
 
            if (zms[j].used == false)continue;
            int x1 = zms[j].x + 80;
            int x2 = zms[j].x + 110;
            int x = bullets_santou[i].x;
            if (zms[j].dead == false &&
                bullets_santou[i].row == zms[j].row && x > x1 && x < x2 && bullets_santou[i].used) {
                zms[j].blood -= 20;
                bullets_santou[i].blast = true;
                bullets_santou[i].speed = 0;
                //bullets_santou[i].x = 0;
 
                if (zms[j].blood <= 0)
                {
                    killCount++;
 
                    zms[j].dead = true;
                    zms[j].speed = 0;
                    zms[j].frameIndex = 0;
                    zms[j].zmSpeed = 4;
                }
                break;
            }
        }
    }
}
 
void checkBullet2Zm()
{
    //坤坤
    checkBullet2Zm_kunkun();
    //豌豆
    checkBullet2Zm_wandou();
    //寒冰豌豆
    checkBullet2Zm_hanbing();
    //三头豌豆
    checkBullet2Zm_santou();
}
 
void checkBoom2Zm()
{
    int zCount = sizeof(zms) / sizeof(zms[0]);
 
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 9; j++)
        {
            //樱桃
            if (map[i][j].type == YING_TAO + 1)
            {
                if (map[i][j].frameIndex > 8)
                {
                    PlaySound("res/audio/cherrybomb.wav", NULL, SND_FILENAME | SND_ASYNC);
                    //map[row][col].x = 256 - 150 + col * 81;
                    //map[row][col].y = 100 + row * 100 - 15;
                    map[i][j].type = 0;
                    map[i][j].frameIndex = 0;
                    int x1 = 100 + 81 * (j - 1);
                    int x2 = 100 + 81 * (j + 2);
                    int y1 = 85 + (i - 1) * 100;
                    int y2 = 85 + (i + 2) * 100;
                    for (int k = 0; k < zCount; k++)
                    {
                        if (zms[k].used == false)continue;
 
                        int zmX = zms[k].x + imgZm[0].getwidth() / 2;
                        int zmY = zms[k].y;
                        if (zmX <= x2 && zmX >= x1 && zmY >= y1 && zmY <= y2 && zms[k].dead == false)
                        {
                            killCount++;
 
                            zms[k].boom = true;
                            zms[k].dead = true;
                            zms[k].speed = 0;
                            zms[k].frameIndex = 0;
                            zms[k].blood = 0;
                        
                        }
                    }
                }
            }
            //火爆辣椒
            else if (map[i][j].type == LA_JIAO + 1)
            {
                if (map[i][j].frameIndex > 7)
                {
                    if (map[i][j].frameIndex == 8)
                        PlaySound("res/audio/firepea.wav", NULL, SND_FILENAME | SND_ASYNC);
 
                    for (int k = 0; k < zCount; k++)
                    {
                        if (zms[k].used == false)continue;
 
                        if (zms[k].row == i && zms[k].x < Wide - 80 - 70 && zms[k].dead == false)
                        {
                            killCount++;
 
                            zms[k].boom = true;
                            zms[k].dead = true;
                            zms[k].speed = 0;
                            zms[k].frameIndex = 0;
                            zms[k].blood = 0;
                        }
                    }
                    if (map[i][j].frameIndex > 14)
                    {
                        map[i][j].type = 0;
                        map[i][j].frameIndex = 0;
                    }
                }
            }
        }
    }
}
 
void checkZM2Zhiwu()
{
    int chomp = 0;
    //mciSendString("play ZM_BGM repeat", NULL, NULL, NULL);
    char name[64];
    int bCount = sizeof(bullets) / sizeof(bullets[0]);
    int zCount = sizeof(zms) / sizeof(zms[0]);
    for (int i = 0; i < zCount; i++)
    {
        //killCount = 0;
        if (zms[i].dead)continue;
 
        //zms[i].chomptime = 0;
        int row = zms[i].row;
        for (int j = 0; j < 9; j++)
        {
            //if (map[row][j].type == 0)continue;
            
            //
            int zhiwuX = 101 + j * 81;
            int x1 = zhiwuX;
            int x2 = zhiwuX + 81;
            int x3 = zms[i].x + 100;
            if (x3 >= x1 && x3 <= x2)
            {
                if (map[row][j].blood <= 0 || (map[row][j].type == 0 && zms[i].eating != false))
                {
                    map[row][j].blood = 0;
                    map[row][j].type = 0;
                    zms[i].eating = false;
                    //zms[i].frameIndex = 0;
                    zms[i].speed = 3;
                }
                else if (map[row][j].type != 0)
                {
                    //mciSendString("play ZM_BGM repeat", NULL, NULL, NULL);
                    //mciSendString("play name repeat", NULL, 0, NULL);
                    zms[i].eating = true;
                    zms[i].speed = 0;
                    if (map[row][j].type != 3 && map[row][j].type != 7)
                        map[row][j].blood--;
                    //zms[i].frameIndex = 0;
                }
                if (zms[i].eating && chomp == 0)
                    chomp = 1;
 
            }
            else if (x3 > 830)
            {
                zms[i].eating = false;
                zms[i].speed = 3;
            }
        }
    }
    static int chomp_time = 0;
    chomp_time++;
    if (chomp&&chomp_time>20)
    {
        chomp_time = 0;
        PlaySound("res/audio/chomp.wav", NULL, SND_FILENAME | SND_ASYNC);
        //mciSendString("play ZM_BGM", NULL, NULL, NULL);
        //printf("1 ");
    }
}
 
void checkcars2Zm()
{
    for (int i = 0; i < 5; i++)
    {
        int carsX = cars[i].x + 70;
        for (int j = 0; j < ZM_MAX; j++)
        {
            if (zms[j].used && zms[j].dead == false && zms[j].row == i)
            {
                int zmX = zms[j].x + 80;
                if (carsX > zmX && cars[i].used)
                {
                    if (cars[i].move == false)
                        cars[i].move = true;
                    else
                    {
                        killCount++;
                        zms[j].dead = true;
                        zms[j].speed = 0;
                        zms[j].frameIndex = 0;
                    }
                }
            }
        }
    }
}
 
void collistionCheck()
{
    //子弹对僵尸的检测
    checkBullet2Zm();
    //僵尸对植物的检测
    checkZM2Zhiwu();
    //爆炸对植物的检测
    checkBoom2Zm();
    //小推车对僵尸的检测
    checkcars2Zm();
}
 
void updatecar()
{
    for (int i = 0; i < 5; i++)
    {
        if (cars[i].move)
        {
            cars[i].x += 20;
        }
        if (cars[i].x > Wide)
        {
            cars[i].move = false;
            cars[i].used = false;
        }
    }
}
 
void updateGame()
{
    srand((unsigned)time(NULL));
    static int count = 0;
    count++;
    if (count > 4)
    {
        count = 0;
        for (int i = 0; i < 5; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                if (map[i][j].type > 0)
                {
                    map[i][j].frameIndex++;
                    int PlantType = map[i][j].type - 1;
                    int index = map[i][j].frameIndex;
                    if (map[i][j].shoot)
                    {
                        if (map[i][j].frameIndex > 1)
                        {
                            map[i][j].shoot = false;
                        }
                    }
                    else
                    {
                        if (imgPlant[PlantType][index] == NULL)
                        {
                            map[i][j].frameIndex = 0;
                        }
                    }
                }
            }
        }
    }
 
    createSunshine();//创建阳光
    updatSunshine();//更新阳光状态
 
    createZM();//创建僵尸
    updateZM();//更新僵尸状态
 
    shoot();//发射豌豆子弹
    updateBullets();//更新子弹
    collistionCheck();//实现豌豆子弹的碰撞检测
 
    updatecar();//更新小推车
}
 
void menu()
{
    mciSendString("play BGM", NULL, NULL, NULL);
 
    IMAGE imgBg, imgMenu1, imgMenu2;
    loadimage(&imgBg, "res/menu.png");
    loadimage(&imgMenu1, "res/menu2.png");
    loadimage(&imgMenu2, "res/menu1.png");
    int flag = 0;
 
    while (1)
    {
        BeginBatchDraw();
        putimage(0, 0, &imgBg);
        putimagePNG(474, 75, flag ? &imgMenu1 : &imgMenu2);
 
        ExMessage msg;
        if (peekmessage(&msg))
        {
            if (msg.message == WM_LBUTTONDOWN &&
                msg.x > 474 && msg.x < 474 + 300 &&
                msg.y>75 && msg.y < 75 + 140)
            {
                flag = 1;
                PlaySound("res/audio/bleep.wav", NULL, SND_FILENAME | SND_ASYNC);
            }
            else if (msg.message == WM_LBUTTONUP && flag == 1)
            {
                EndBatchDraw();
                break;
            }
        }
        EndBatchDraw();
    }
}
 
void viewScence()
{
    mciSendString("play BGM3", NULL, NULL, NULL);
 
    //开头场景时僵尸的位置
    vector2 points[9] = {
        {550,80},{530,160},{630,170},{530,200},{515,270},
        {565,370},{605,340},{705,280},{690,340}
    };
    int index[9];
    for (int i = 0; i < 9; i++)
    {
        index[i] = rand() % 11;
    }
 
    int count = 0;
    for (int i = 0; i >= -500; i-=3)
    {
        BeginBatchDraw();
        putimage(i, 0, &img);
 
        count++;
        for (int k = 0; k < 9; k++)
        {
            putimagePNG(points[k].x + 500 + i,
                points[k].y, &imgZmStand[index[k]]);
            if (count >= 10)
            {
                index[k] = (index[k] + 1) % 11;
            } 
        }
        if (count >= 10)count = 0;
        EndBatchDraw();
        Sleep(10);
    }
    
    for (int i = 0; i < 60; i++)
    {
        BeginBatchDraw();
 
        putimage(-500, 0, &img);
        for (int k = 0; k < 9; k++)
        {
            putimagePNG(points[k].x, points[k].y, &imgZmStand[index[k]]);
            index[k] = (index[k] + 1) % 11;
        }
 
        EndBatchDraw();
        Sleep(50);
    }
 
    for (int i = -500; i <= -150; i += 2)
    {
        BeginBatchDraw();
 
        putimage(i, 0, &img);
        count++;
        for (int k = 0; k < 9; k++)
        {
            putimagePNG(points[k].x + 500 + i,
                points[k].y, &imgZmStand[index[k]]);
            if (count >= 10)
            {
                index[k] = (index[k] + 1) % 11;
            }
            if (count >= 10) count = 0;
        }
        EndBatchDraw();
        Sleep(10);
    }
 
}
 
void barsDown()
{
    int height = imgBar.getheight();
    for (int y = -height; y <= -10; y++)
    {
        BeginBatchDraw();
 
        putimagePNG(80, y, &imgBar);
        for (int i = 0; i < PLANT_COUNT + 2; i++)
        {
            putimagePNG(163 + i * 65, y + 10, &imgCards[i]);
        }
        
        EndBatchDraw();
        Sleep(10);
    }
    for (int i = 0; i < 5; i++)
    {
        putimagePNG(50, 100 + i * 100 - 15, &imgcar);
    }
    mciSendString("close BGM3", NULL, 0, NULL);
    mciSendString("play BGM4", NULL, NULL, NULL);
    Sleep(1000);
    putimagePNG(450 - imgready.getwidth()/2, 300 - imgready.getheight()/2, &imgready);
    Sleep(200);
}
 
void failScence()
{
    for (int i = -150; i <= -100; i += 1)
    {
        BeginBatchDraw();
        //zmSpeed = 6;
        putimage(i, 0, &img);
        //show();
        drawZm();
        //updateGame();
        createZM();//创建僵尸
        updateZM();//更新僵尸状态
        
        EndBatchDraw();
        Sleep(50);
    }
}
 
bool checkOver()
{
    int ret = false;
    if (gameStatus == WIN)
    {
        mciSendString("close BGM2", NULL, NULL, NULL);
 
        loadimage(0, "res/win2.png");
        mciSendString("play res/win.mp3", 0, 0, 0);
        ret = true;
    }
    else if (gameStatus == FAIL)
    {
        mciSendString("close BGM2", NULL, NULL, NULL);
 
        mciSendString("play res/lose.mp3", 0, 0, 0);
        failScence();
        Sleep(500);
        loadimage(0, "res/fail2.png");
        ret = true;
    }
    return ret;
}
 
void OpeningAnimation()
{
    mciSendString("play res/audio/yuanshen.mp3", 0, 0, 0);
    for (int i = 0; i < 29; i++)
    {
        BeginBatchDraw();
        putimage(-148, -35, &imgopena[i]);
 
        EndBatchDraw();
        Sleep(50);
    }
    Sleep(4000);
}
 
int main()
{
    //加载游戏画面
    gameInit();
    //开场动画
    OpeningAnimation();
    menu();
    mciSendString("close BGM", NULL, 0, NULL);
    //游戏开始时的场景切换
    viewScence();
    //游戏开始时卡牌和卡牌槽的下落
    barsDown();
    int timer = 0;
    bool flag = true;
    
    mciSendString("play BGM2 repeat", NULL, NULL, NULL);
    while (1)
    {
        //用户操作
        userClick();
        //游戏更新时间
        timer += getDelay();
        if (timer > 20)
        {
            flag = true;
            timer = 0;
        }
        if (flag)
        {
            flag = false;
            //绘制游戏画面
            show();
            //更新游戏画面
            updateGame();
            if(checkOver()) break;
        }
    }
    closegraph;
    system("pause");
    return 0;

————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/weixin_58252863/article/details/138923241

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值