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


    前言:

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

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

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

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

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

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

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

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

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

    初始化游戏界面。

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

    实现的植物的放置。

    实现植物的功能:

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

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

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

    1. 初始化游戏界面

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

    1. //地图
    2. putimage(-150, 0, &img);
    3. //卡牌槽
    4. putimagePNG(80, -10, &imgBar);
    5. //植物卡牌
    6. for (int i = 0; i < PLANT_COUNT + 2; i++)
    7. {
    8. if(i==PLANT_COUNT)
    9. putimagePNG(163 + i * 65 + 8, -5, &imgCards[i]);
    10. else
    11. putimagePNG(163 + i * 65, 0, &imgCards[i]);
    12. }

    2.  放置植物

    因为需要在这个9*5的草地区域内放置植物,所以我们得计算出每个草方块的位置。我利用画图软件测出每个草方块大约是长81、宽100个像素点。 第一个草方块距离游戏窗口大约101个像素点。

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

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

    1. enum {
    2. WAN_DOU, TAI_YANG, LA_JIAO, KUN_KUN, JIAN_GUO,
    3. HAN_BING_WAN_DOU, YING_TAO, SAN_TOU_WAN_DOU, PLANT_COUNT
    4. };
    5. struct plant
    6. {
    7. int type;//植物类型
    8. int frameIndex;//植物动作帧
    9. //bool catched;//是否被吃
    10. int blood;//血量
    11. int shootTime;//植物子弹的射速
    12. int timer;//阳光生产的时间
    13. int x, y;//植物坐标
    14. bool shoot;//判断植物是否处于发射状态
    15. };
    16. struct plant map[5][9];

     在 Windows 编程中,我们可以利用下面的变量获取鼠标信息。

    1. ExMessage msg;
    2. msg.message
    1. ExMessage msg;
    2. static int status = 0;
    3. if (peekmessage(&msg))//判断有没有消息
    4. {
    5. if (msg.message == WM_LBUTTONDOWN)//左键按下
    6. {
    7. //鼠标是否在卡牌的位置按下
    8. if (msg.x > 163 && msg.x < 163 + 65 * (PLANT_COUNT+2) && msg.y < 96)
    9. {
    10. //mciSendString("play res/audio/bleep.mp3 alias BGM4", NULL, NULL, NULL);
    11. PlaySound("res/audio/bleep.wav", NULL, SND_FILENAME | SND_ASYNC);
    12. //PlaySound("res/sunshine.wav", NULL, SND_FILENAME | SND_ASYNC);
    13. int index = (msg.x - 163) / 65;
    14. //坤坤
    15. /* if (index + 1 == KUN_KUN && sunshine >= 100)
    16. {
    17. curPlant = index + 1;
    18. status = 1;
    19. curX = msg.x;
    20. curY = msg.y;
    21. sunshine -= 100;
    22. }*/
    23. curPlant = index + 1;
    24. status = 1;
    25. curX = msg.x;
    26. curY = msg.y;
    27. }
    28. }
    29. else if (msg.message == WM_MOUSEMOVE && status == 1)//鼠标移动
    30. {
    31. curX = msg.x;
    32. curY = msg.y;
    33. }
    34. else if (msg.message == WM_LBUTTONUP)//鼠标放下
    35. {
    36. if (msg.x > 256 - 150 && msg.x < Wide - 70 && msg.y > 100 && msg.y < 590)
    37. {
    38. int row = (msg.y - 100) / 102;
    39. int col = (msg.x - 256 + 150 ) / 81;
    40. if (map[row][col].type == 0 && curPlant != PLANT_COUNT + 1 && curPlant != PLANT_COUNT + 2)
    41. {
    42. //printf("%d\n", map[col][row].type);
    43. map[row][col].type = curPlant;
    44. map[row][col].frameIndex = 0;
    45. if(curPlant!=0)
    46. PlaySound("res/audio/coffee.wav", NULL, SND_FILENAME | SND_ASYNC);
    47. if (curPlant == 5)
    48. map[row][col].blood = KUNKUN_BLOOD * 50;
    49. else
    50. map[row][col].blood = KUNKUN_BLOOD;
    51. map[row][col].shootTime = 0;
    52. map[row][col].shoot = false;
    53. map[row][col].x = 256 - 150 + col * 81;
    54. map[row][col].y = 100 + row * 100 - 15;
    55. }
    56. else if (map[row][col].type != 0 && curPlant == PLANT_COUNT + 1)
    57. {
    58. PlaySound("res/audio/coffee.wav", NULL, SND_FILENAME | SND_ASYNC);
    59. map[row][col].type = 0;
    60. map[row][col].blood = 0;
    61. }
    62. }
    63. }
    64. else if (msg.message == WM_RBUTTONDOWN)//鼠标右键
    65. {
    66. curPlant = 0;
    67. status = 0;
    68. }

    3. 僵尸

     3.1 创建僵尸

    僵尸也是和植物一样需要创建一个结构体存放信息。然后创建一个结构体数组,作为一个僵尸池,当需要创建一个僵尸时,我们就从这个池里取一个未被使用的僵尸。

    1. struct zm
    2. {
    3. int x, y;//僵尸的坐标
    4. int frameIndex;//僵尸动作帧
    5. bool used;//僵尸是否被使用
    6. int speed;//僵尸每一次移动的位移
    7. int row;//僵尸所在行
    8. int blood;//僵尸血量
    9. bool dead;//僵尸是否死亡
    10. bool eating;//僵尸是否在吃植物
    11. bool boom;//僵尸是否被炸死
    12. int zmSpeed;//僵尸的移动快慢
    13. };
    14. struct zm zms[ZM_MAX];
    1. //找一个可用的僵尸
    2. int i;
    3. for (i = 0; i < zmMax && zms[i].used && zms[i].dead == false; i++);

    到一定的时间就创建一个僵尸。

    1. void createZM()
    2. {
    3. if (zmCount >= zmCount_max)
    4. return;
    5. static int zmFre = 500;
    6. static int count = 0;
    7. //控制僵尸的生成快慢
    8. count++;
    9. if (count > zmFre)
    10. {
    11. count = 0;
    12. zmFre = 200;
    13. int i = 0;
    14. int zmMax = sizeof(zms) / sizeof(zms[0]);
    15. for (i = 0; i < zmMax && zms[i].used && zms[i].dead == false; i++);
    16. if (i < zmMax)
    17. {
    18. memset(&zms[i], 0, sizeof(zms[i]));
    19. zms[i].used = true;
    20. zms[i].speed = 2;
    21. zms[i].row = rand() % 5;
    22. zms[i].y = 100 + (zms[i].row) * 100 + 70;
    23. zms[i].x = Wide;
    24. zms[i].blood = ORDINARY_ZM_BLOOD;
    25. zms[i].dead = false;
    26. zms[i].boom = false;
    27. zms[i].zmSpeed = 4;
    28. zmCount++;
    29. }
    30. }
    31. }

    3. 2 检测僵尸对植物的伤害检测

    僵尸靠近植物就将僵尸置为吃东西的状态,减植物的血量,当植物的血量小于等于0时,就去除植物。

    1. void checkZM2Zhiwu()
    2. {
    3. char name[64];
    4. int zCount = sizeof(zms) / sizeof(zms[0]);
    5. for (int i = 0; i < zCount; i++)
    6. {
    7. //killCount = 0;
    8. if (zms[i].dead)continue;
    9. //zms[i].chomptime = 0;
    10. int row = zms[i].row;
    11. for (int j = 0; j < 9; j++)
    12. {
    13. //if (map[row][j].type == 0)continue;
    14. //
    15. int zhiwuX = 101 + j * 81;
    16. int x1 = zhiwuX;
    17. int x2 = zhiwuX + 81;
    18. int x3 = zms[i].x + 100;
    19. if (x3 >= x1 && x3 <= x2)
    20. {
    21. if (map[row][j].blood <= 0 || (map[row][j].type == 0 && zms[i].eating != false))
    22. {
    23. map[row][j].blood = 0;
    24. map[row][j].type = 0;
    25. zms[i].eating = false;
    26. //zms[i].frameIndex = 0;
    27. zms[i].speed = 3;
    28. }
    29. else if (map[row][j].type != 0)
    30. {
    31. //mciSendString("play ZM_BGM repeat", NULL, NULL, NULL);
    32. //mciSendString("play name repeat", NULL, 0, NULL);
    33. zms[i].eating = true;
    34. zms[i].speed = 0;
    35. if (map[row][j].type != 3 && map[row][j].type != 7)
    36. map[row][j].blood--;
    37. //zms[i].frameIndex = 0;
    38. }
    39. }
    40. else if (x3 > 830)
    41. {
    42. zms[i].eating = false;
    43. zms[i].speed = 3;
    44. }
    45. }
    46. }
    47. }

    4. 植物子弹

    4.1 发射子弹

    当僵尸出现在游戏界面时,与该僵尸同一行的发射性植物就发射出子弹。

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

    1. //子弹
    2. struct bullet
    3. {
    4. double x, y;//子弹的坐标
    5. bool used;//子弹是否被使用
    6. int row;//子弹所在行
    7. int speed;//子弹速度
    8. bool blast;//是否发生爆炸
    9. int frameIndex;//帧序号
    10. };
    11. //坤坤
    12. struct bullet bullets[1000];

     以坤坤为例:

    1. void shoot()
    2. {
    3. int lines[5] = { 0 };
    4. int bulletMax = sizeof(bullets) / sizeof(bullets[0]);
    5. int zmCount = sizeof(zms) / sizeof(zms[0]);
    6. int dangerX = Wide - 80;
    7. for (int i = 0; i < zmCount; i++)
    8. {
    9. if (zms[i].dead == false && zms[i].x < dangerX && zms[i].x>100)
    10. {
    11. lines[zms[i].row] = 1;
    12. }
    13. }
    14. for (int i = 0; i < 5; i++)
    15. {
    16. for (int j = 0; j < 9; j++)
    17. {
    18. //坤坤
    19. if (map[i][j].type == KUN_KUN + 1 && lines[i])
    20. {
    21. map[i][j].shootTime++;
    22. if (map[i][j].shootTime > 20)
    23. {
    24. map[i][j].shootTime = 0;
    25. //子弹池
    26. int k;
    27. for (k = 0; k < bulletMax && bullets[k].used; k++);
    28. if (k < bulletMax)
    29. {
    30. map[i][j].frameIndex = 3;
    31. bullets[k].used = true;
    32. bullets[k].row = i;
    33. bullets[k].speed = 10;
    34. bullets[k].blast = false;
    35. bullets[k].frameIndex = 0;
    36. int zwX = 256 - 150 + j * 81;
    37. int zwY = 100 + i * 100 - 15;
    38. bullets[k].x = zwX + imgPlant[map[i][j].type - 1][0]->getwidth() - 10;
    39. bullets[k].y = zwY + 5;
    40. }
    41. }
    42. }
    43. }
    44. }
    45. }

    4. 2  更新子弹

    不断的改变加子弹的横坐标,当子弹出游戏界面时,子弹就被置为未被使用。

    以坤坤为例:

    1. void updateBullets_kunkun()
    2. {
    3. int countMax = sizeof(bullets) / sizeof(bullets[0]);
    4. for (int i = 0; i < countMax; i++)
    5. {
    6. if (bullets[i].used)
    7. {
    8. bullets[i].x += bullets[i].speed;
    9. if (bullets[i].x > Wide)
    10. {
    11. bullets[i].used = false;
    12. }
    13. }
    14. }
    15. }

     4.3 检测子弹对僵尸的伤害

    当子弹靠近僵尸时减去僵尸的一定量血量,然后对僵尸造成一定的效果(例如,坤坤子弹的效果是击退僵尸,那么我们只需要更改僵尸的横坐标即可。),最后将子弹置为未被使用。

    以坤坤为例:

    1. void checkBullet2Zm_kunkun()
    2. {
    3. int bCount = sizeof(bullets) / sizeof(bullets[0]);
    4. int zCount = sizeof(zms) / sizeof(zms[0]);
    5. for (int i = 0; i < bCount; i++)
    6. {
    7. {
    8. for (int j = 0; j < zCount; j++)
    9. {
    10. if (zms[j].used == false)continue;
    11. int x1 = zms[j].x + 80;
    12. int x2 = zms[j].x + 110;
    13. int x = bullets[i].x;
    14. if (zms[j].dead == false &&
    15. bullets[i].row == zms[j].row && x > x1 && x < x2 && bullets[i].used) {
    16. zms[j].blood -= 20;
    17. zms[j].x += 1;
    18. bullets[i].blast = true;
    19. bullets[i].speed = 0;
    20. //bullets[i].x = 0;
    21. if (zms[j].blood <= 0)
    22. {
    23. killCount++;
    24. zms[j].dead = true;
    25. zms[j].speed = 0;
    26. zms[j].frameIndex = 0;
    27. }
    28. break;
    29. }
    30. }
    31. }
    32. }
    33. }

     5. 爆炸性植物

    爆炸性植物是一次性的,当植物的动作帧执行完最后一帧后植物就置为死亡,在爆炸范围内的僵尸也死亡。

    以火爆辣椒为例:

    1. void checkBoom2Zm()
    2. {
    3. int zCount = sizeof(zms) / sizeof(zms[0]);
    4. for (int i = 0; i < 5; i++)
    5. {
    6. for (int j = 0; j < 9; j++)
    7. {
    8. //火爆辣椒
    9. else if (map[i][j].type == LA_JIAO + 1)
    10. {
    11. if (map[i][j].frameIndex > 7)
    12. {
    13. for (int k = 0; k < zCount; k++)
    14. {
    15. if (zms[k].used == false)continue;
    16. if (zms[k].row == i && zms[k].x < Wide - 80 - 70 && zms[k].dead == false)
    17. {
    18. killCount++;
    19. zms[k].boom = true;
    20. zms[k].dead = true;
    21. zms[k].speed = 0;
    22. zms[k].frameIndex = 0;
    23. zms[k].blood = 0;
    24. }
    25. }
    26. if (map[i][j].frameIndex > 14)
    27. {
    28. map[i][j].type = 0;
    29. map[i][j].frameIndex = 0;
    30. }
    31. }
    32. }
    33. }
    34. }
    35. }

    6. 小推车

     创建存放小车信息的结构体数组,小推车一条路一辆共5辆,所以我们只需写一个大小为5的结构体数组即可。

    1. //小推车
    2. struct car
    3. {
    4. bool move;//是否处于移动状态
    5. int x, y;//位置
    6. bool used;//是否被使用
    7. };
    8. struct car cars[5];

    放置小推车 

    1. for (int i = 0; i < 5; i++)
    2. {
    3. cars[i].x = 50;
    4. cars[i].y = 100 + i * 100 - 15;
    5. cars[i].used = true;
    6. cars[i].move = false;
    7. }

    检测小推车对小车的伤害 

    当僵尸的横坐标小于等于小推车最左端的坐标时,小车置为移动状态,处于小推车左边的僵尸死亡。

    1. void checkcars2Zm()
    2. {
    3. for (int i = 0; i < 5; i++)
    4. {
    5. int carsX = cars[i].x + 70;
    6. for (int j = 0; j < ZM_MAX; j++)
    7. {
    8. if (zms[j].used && zms[j].dead == false && zms[j].row == i)
    9. {
    10. int zmX = zms[j].x + 80;
    11. if (carsX > zmX && cars[i].used)
    12. {
    13. if (cars[i].move == false)
    14. cars[i].move = true;
    15. else
    16. {
    17. killCount++;
    18. zms[j].dead = true;
    19. zms[j].speed = 0;
    20. zms[j].frameIndex = 0;
    21. }
    22. }
    23. }
    24. }
    25. }
    26. }

    更新小推车的位置

    当小车被置为移动时,小推车开始移动。

    1. void updatecar()
    2. {
    3. for (int i = 0; i < 5; i++)
    4. {
    5. if (cars[i].move)
    6. {
    7. cars[i].x += 20;
    8. }
    9. if (cars[i].x > Wide)
    10. {
    11. cars[i].move = false;
    12. cars[i].used = false;
    13. }
    14. }
    15. }

    源码:

    test.cpp文件: 

    1. #include"game.h"
    2. //判断文件是否存在
    3. bool fileExist(const char* name)
    4. {
    5. FILE* pf = fopen(name, "r");
    6. if (pf == NULL)
    7. {
    8. return false;
    9. }
    10. else
    11. {
    12. fclose(pf);
    13. return true;
    14. }
    15. }
    16. //初始化豌豆子弹的帧图片数组
    17. void bulletsInit()
    18. {
    19. //坤坤篮球
    20. loadimage(&imgBulletNormal, "res/bullets/basketball.png", 40, 40);
    21. memset(bullets, 0, sizeof(bullets));
    22. //初始化豌豆子弹的帧图片数组
    23. loadimage(&imgBallBlast[3], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png");
    24. for (int i = 0; i < 3; i++)
    25. {
    26. float k = (i + 1) * 0.2;
    27. loadimage(&imgBallBlast[i], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png",
    28. imgBallBlast[3].getwidth() * k,
    29. imgBallBlast[3].getheight() * k, true);
    30. }
    31. //豌豆子弹
    32. loadimage(&imgBulletNormal_wandou, "res/bullets/bullet_normal.png");
    33. memset(bullets_wandou, 0, sizeof(bullets_wandou));
    34. //初始化豌豆子弹的帧图片数组
    35. loadimage(&imgBallBlast_wandou[3], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png");
    36. for (int i = 0; i < 3; i++)
    37. {
    38. float k = (i + 1) * 0.2;
    39. loadimage(&imgBallBlast_wandou[i], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png",
    40. imgBallBlast_wandou[3].getwidth() * k,
    41. imgBallBlast_wandou[3].getheight() * k, true);
    42. }
    43. //寒冰豌豆子弹
    44. loadimage(&imgBulletNormal_hanbing, "res/bullets/PeaIce/PeaIce_0.png");
    45. memset(bullets_hanbing, 0, sizeof(bullets_hanbing));
    46. //初始化豌豆子弹的帧图片数组
    47. loadimage(&imgBallBlast_hanbing[3], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png");
    48. for (int i = 0; i < 3; i++)
    49. {
    50. float k = (i + 1) * 0.2;
    51. loadimage(&imgBallBlast_hanbing[i], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png",
    52. imgBallBlast_hanbing[3].getwidth() * k,
    53. imgBallBlast_hanbing[3].getheight() * k, true);
    54. }
    55. //三头豌豆子弹
    56. loadimage(&imgBulletNormal_santou, "res/bullets/bullet_normal.png");
    57. memset(bullets_santou, 0, sizeof(bullets_santou));
    58. //初始化豌豆子弹的帧图片数组
    59. loadimage(&imgBallBlast_santou[3], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png");
    60. for (int i = 0; i < 3; i++)
    61. {
    62. float k = (i + 1) * 0.2;
    63. loadimage(&imgBallBlast_santou[i], "res/bullets/PeaNormalExplode/PeaNormalExplode_0.png",
    64. imgBallBlast_santou[3].getwidth() * k,
    65. imgBallBlast_santou[3].getheight() * k, true);
    66. }
    67. }
    68. void gameInit()
    69. {
    70. char name[64];
    71. //音效
    72. mciSendString("open res/bg.mp3 alias BGM", NULL, NULL, NULL);
    73. mciSendString("open res/audio/UraniwaNi.mp3 alias BGM2", NULL, NULL, NULL);
    74. mciSendString("open res/audio/WateryGraves.mp3 alias BGM3", NULL, NULL, NULL);
    75. mciSendString("open res/audio/readysetplant.mp3 alias BGM4", NULL, NULL, NULL);
    76. mciSendString("open res/audio/chomp.mp3 alias ZM_BGM", NULL, NULL, NULL);
    77. loadimage(&img, "res/map/map0.jpg");
    78. loadimage(&imgBar, "res/bar5.png");
    79. //loadimage(&imgnotify, "res/screen/PanelBackground.png");
    80. memset(imgPlant, 0, sizeof(imgPlant));
    81. memset(map, 0, sizeof(map));
    82. memset(cars, 0, sizeof(cars));
    83. //开场动画
    84. for (int i = 0; i < 29; i++)
    85. {
    86. sprintf_s(name, sizeof(name), "res/yuanshen/%d.png", i + 1);
    87. loadimage(&imgopena[i], name, 1196, 670);
    88. }
    89. //植物卡牌
    90. for (int i = 0; i < PLANT_COUNT + 2; i++)
    91. {
    92. sprintf_s(name, sizeof(name), "res/Cards/card_%d.png", i + 1);
    93. loadimage(&imgCards[i], name,64,89);
    94. for (int j = 0; j < 20; j++)
    95. {
    96. sprintf_s(name, sizeof(name), "res/zhiwu/%d/%d.png",i , j + 1);
    97. //先判断文件是否存在
    98. if (fileExist(name))
    99. {
    100. imgPlant[i][j] = new IMAGE;
    101. if (i != 3)
    102. {
    103. loadimage(imgPlant[i][j], name);
    104. }
    105. else
    106. {
    107. loadimage(imgPlant[i][j], name,65,100);
    108. }
    109. }
    110. else
    111. {
    112. break;
    113. }
    114. }
    115. }
    116. memset(balls, 0, sizeof(balls));
    117. for (int i = 0; i < 29; i++)
    118. {
    119. sprintf_s(name, sizeof(name), "res/sunshine/%d.png", i + 1);
    120. loadimage(&imgSunshineBall[i], name);
    121. }
    122. curPlant = 0;
    123. sunshine = 50;
    124. initgraph(Wide, Hight);
    125. //设置字体
    126. LOGFONT f;
    127. gettextstyle(&f);
    128. f.lfHeight = 30;
    129. f.lfWeight = 15;
    130. strcpy(f.lfFaceName, "Segoe UI Black");
    131. f.lfQuality = ANTIALIASED_QUALITY;//抗锯齿效果
    132. settextstyle(&f);
    133. setbkmode(TRANSPARENT);//字体透明
    134. setcolor(BLACK);
    135. //初始化子弹的帧图片数组
    136. bulletsInit();
    137. //初始化僵尸数据
    138. memset(zms, 0, sizeof(zms));
    139. for (int i = 0; i < 22; i++)
    140. {
    141. sprintf_s(name, sizeof(name), "res/zm/%d.png", i + 1);
    142. loadimage(&imgZm[i], name);
    143. }
    144. killCount = 0;
    145. zmCount = 0;
    146. gameStatus = GOING;
    147. //初始化僵尸
    148. for (int i = 0; i < 38; i++)
    149. {
    150. sprintf_s(name, sizeof(name), "res/zm_dead/%d.png",i + 1);
    151. loadimage(&imgZMDead[i], name);
    152. }
    153. for (int i = 0; i < 21; i++)
    154. {
    155. sprintf_s(name, sizeof(name), "res/zm_eat/%d.png", i + 1);
    156. loadimage(&imgZMEat[i], name);
    157. }
    158. for (int i = 0; i < 11; i++)
    159. {
    160. sprintf_s(name, sizeof(name), "res/zm_stand/%d.png", i + 1);
    161. loadimage(&imgZmStand[i], name);
    162. }
    163. for (int i = 0; i < 20; i++)
    164. {
    165. sprintf_s(name, sizeof(name), "res/zm_dead2/%d.png", i + 1);
    166. loadimage(&imgzmboom[i], name);
    167. }
    168. //小推车
    169. loadimage(&imgcar, "res/Screen/car.png");
    170. for (int i = 0; i < 5; i++)
    171. {
    172. cars[i].x = 50;
    173. cars[i].y = 100 + i * 100 - 15;
    174. cars[i].used = true;
    175. cars[i].move = false;
    176. }
    177. //StartButton
    178. loadimage(&imgready, "res/Screen/Boom.png");
    179. }
    180. void drawZm()
    181. {
    182. int zmCount = sizeof(zms) / sizeof(zms[0]);
    183. for (int i = 0; i < zmCount; i++)
    184. {
    185. if (zms[i].used)
    186. {//IMAGE* img = (zms[i].dead) ? &imgZMDead[zms[i].frameIndex] : &imgZm[zms[i].frameIndex];
    187. IMAGE* img = NULL;
    188. if (zms[i].dead)
    189. {
    190. if (zms[i].boom == true)
    191. img = &imgzmboom[zms[i].frameIndex];
    192. else
    193. img = &imgZMDead[zms[i].frameIndex];
    194. }
    195. else if (zms[i].eating) img = &imgZMEat[zms[i].frameIndex];
    196. else img = &imgZm[zms[i].frameIndex];
    197. putimagePNG(zms[i].x, zms[i].y - img->getheight(), img);
    198. }
    199. }
    200. }
    201. void drawSunshine()
    202. {
    203. int ballMax = sizeof(balls) / sizeof(balls[0]);
    204. for (int i = 0; i < ballMax; i++)
    205. {
    206. //if (balls[i].used || balls[i].xoff)
    207. if(balls[i].used)
    208. {
    209. IMAGE* img = &imgSunshineBall[balls->frameIndex];
    210. //putimagePNG(balls[i].x, balls[i].y, img);
    211. putimagePNG(balls[i].pCur.x, balls[i].pCur.y, img);
    212. }
    213. }
    214. }
    215. void drawBullets_kunkun()
    216. {
    217. int bulletsMax = sizeof(bullets) / sizeof(bullets[0]);
    218. for (int i = 0; i < bulletsMax; i++)
    219. {
    220. if (bullets[i].used) {
    221. if (bullets[i].blast) {
    222. IMAGE* img = &imgBallBlast[bullets[i].frameIndex];
    223. putimagePNG(bullets[i].x, bullets[i].y - 10, img);
    224. }
    225. else {
    226. putimagePNG(bullets[i].x, bullets[i].y, &imgBulletNormal);
    227. }
    228. }
    229. }
    230. }
    231. void drawBullets_wandou()
    232. {
    233. int bulletsMax = sizeof(bullets_wandou) / sizeof(bullets_wandou[0]);
    234. for (int i = 0; i < bulletsMax; i++)
    235. {
    236. if (bullets_wandou[i].used) {
    237. if (bullets_wandou[i].blast) {
    238. IMAGE* img = &imgBallBlast_wandou[bullets_wandou[i].frameIndex];
    239. putimagePNG(bullets_wandou[i].x, bullets_wandou[i].y, img);
    240. }
    241. else {
    242. putimagePNG(bullets_wandou[i].x, bullets_wandou[i].y, &imgBulletNormal_wandou);
    243. }
    244. }
    245. }
    246. }
    247. void drawBullets_hanbing()
    248. {
    249. int bulletsMax = sizeof(bullets_hanbing) / sizeof(bullets_hanbing[0]);
    250. for (int i = 0; i < bulletsMax; i++)
    251. {
    252. if (bullets_hanbing[i].used) {
    253. if (bullets_hanbing[i].blast) {
    254. IMAGE* img = &imgBallBlast_hanbing[bullets_hanbing[i].frameIndex];
    255. putimagePNG(bullets_hanbing[i].x, bullets_hanbing[i].y, img);
    256. }
    257. else {
    258. putimagePNG(bullets_hanbing[i].x, bullets_hanbing[i].y, &imgBulletNormal_hanbing);
    259. }
    260. }
    261. }
    262. }
    263. void drawBullets_santou()
    264. {
    265. int bulletsMax = sizeof(bullets_santou) / sizeof(bullets_santou[0]);
    266. for (int i = 0; i < bulletsMax; i++)
    267. {
    268. if (bullets_santou[i].used) {
    269. if (bullets_santou[i].blast) {
    270. IMAGE* img = &imgBallBlast_santou[bullets_santou[i].frameIndex];
    271. putimagePNG(bullets_santou[i].x, bullets_santou[i].y, img);
    272. }
    273. else {
    274. putimagePNG(bullets_santou[i].x, bullets_santou[i].y, &imgBulletNormal_santou);
    275. }
    276. }
    277. }
    278. }
    279. void drawBullets()
    280. {
    281. //坤坤
    282. drawBullets_kunkun();
    283. //豌豆
    284. drawBullets_wandou();
    285. //寒冰豌豆
    286. drawBullets_hanbing();
    287. //三头豌豆
    288. drawBullets_santou();
    289. }
    290. void show()//渲染游戏画面
    291. {
    292. BeginBatchDraw();
    293. putimage(-150, 0, &img);
    294. putimagePNG(80, -10, &imgBar);
    295. char scoreText[8];
    296. char scoreText1[16];
    297. sprintf_s(scoreText, sizeof(scoreText), "%d", sunshine);
    298. sprintf_s(scoreText1, sizeof(scoreText1), "Wave %d zombies", wava_count);
    299. //sprintf_s(name, sizeof(name), "res/yuanshen/%d.png", i + 1);
    300. outtextxy(105, 60, scoreText);
    301. outtextxy(700, 570, scoreText1);
    302. //outtextxy(700, 570, "s");
    303. //小推车
    304. for (int i = 0; i < 5; i++)
    305. {
    306. if(cars[i].used)
    307. putimagePNG(cars[i].x, cars[i].y, &imgcar);
    308. }
    309. //植物卡牌
    310. for (int i = 0; i < PLANT_COUNT + 2; i++)
    311. {
    312. if(i==PLANT_COUNT)
    313. putimagePNG(163 + i * 65 + 8, -5, &imgCards[i]);
    314. else
    315. putimagePNG(163 + i * 65, 0, &imgCards[i]);
    316. }
    317. //植物
    318. for (int i = 0; i < 5; i++)
    319. {
    320. for (int j = 0; j < 9; j++)
    321. {
    322. if (map[i][j].type > 0)
    323. {
    324. /*int x = 256 - 150 + j * 81;
    325. int y = 100 + i * 100 - 15;*/
    326. int PlantType = map[i][j].type - 1;
    327. int index = map[i][j].frameIndex;
    328. if (map[i][j].type != 4 && map[i][j].type != YING_TAO + 1 && map[i][j].type != LA_JIAO + 1)
    329. {
    330. putimagePNG(map[i][j].x, map[i][j].y, imgPlant[PlantType][index]);
    331. }
    332. else if (map[i][j].type == YING_TAO + 1)
    333. {
    334. if (index == 8)
    335. putimagePNG(map[i][j].x - 75, map[i][j].y-35, imgPlant[PlantType][index]);
    336. else
    337. putimagePNG(map[i][j].x - 22, map[i][j].y, imgPlant[PlantType][index]);
    338. }
    339. else if (map[i][j].type == LA_JIAO + 1)
    340. {
    341. if (index > 7)
    342. putimagePNG(100, map[i][j].y - 35, imgPlant[PlantType][index]);
    343. else
    344. putimagePNG(map[i][j].x, map[i][j].y, imgPlant[PlantType][index]);
    345. }
    346. else
    347. {
    348. putimagePNG(map[i][j].x + 5, map[i][j].y - 20, imgPlant[PlantType][index]);
    349. }
    350. }
    351. }
    352. }
    353. //渲染子弹
    354. drawBullets();
    355. //铲子
    356. if (curPlant != PLANT_COUNT + 1)
    357. {
    358. IMAGE* img = imgPlant[8][0];
    359. putimagePNG(163 + 8 * 65 + 8, 0, img);
    360. }
    361. //僵尸
    362. drawZm();
    363. //渲染拖动中的植物
    364. if (curPlant > 0)
    365. {
    366. IMAGE* img = imgPlant[curPlant - 1][0];
    367. putimagePNG(curX - img->getwidth() / 2, curY - img->getheight() / 2, img);
    368. }
    369. //渲染阳光
    370. drawSunshine();
    371. EndBatchDraw();
    372. }
    373. void collectSunshine(ExMessage* msg)
    374. {
    375. int count = sizeof(balls) / sizeof(balls[0]);
    376. int w = imgSunshineBall[0].getwidth();
    377. int h = imgSunshineBall[0].getheight();
    378. for (int i = 0; i < count; i++)
    379. {
    380. if (balls[i].used)
    381. {
    382. //int x = balls[i].x;
    383. //int y = balls[i].y;
    384. int x = balls[i].pCur.x;
    385. int y = balls[i].pCur.y;
    386. if (msg->x > x && msg->x
    387. && msg->y>y && msg->y < y + h)
    388. {
    389. sunshine += 25;
    390. //balls[i].used = false;
    391. balls[i].status = SUNSHINE_COLLECT;
    392. //音效
    393. //mciSendString("play res/sunshine.mp3", 0, 0, 0);
    394. //不支持MP3格式
    395. PlaySound("res/sunshine.wav", NULL, SND_FILENAME | SND_ASYNC);
    396. balls[i].p1 = balls[i].pCur;
    397. balls[i].p4 = vector2(100, 0);
    398. balls[i].t = 0;
    399. float distance = dis(balls[i].p1 - balls[i].p4);
    400. float off = 8;
    401. balls[i].speed = 1.0 / (distance / off);
    402. break;
    403. /*float destX = 0;
    404. float destY = 262;
    405. float angle = atan((y - destY) / (x - destX));
    406. balls[i].xoff = 4 * cos(angle);
    407. balls[i].yoff = 4 * sin(angle);*/
    408. }
    409. }
    410. }
    411. }
    412. void userClick()
    413. {
    414. ExMessage msg;
    415. static int status = 0;
    416. if (peekmessage(&msg))//判断有没有消息
    417. {
    418. if (msg.message == WM_LBUTTONDOWN)//左键按下
    419. {
    420. if (msg.x > 163 && msg.x < 163 + 65 * (PLANT_COUNT+2) && msg.y < 96)
    421. {
    422. //mciSendString("play res/audio/bleep.mp3 alias BGM4", NULL, NULL, NULL);
    423. PlaySound("res/audio/bleep.wav", NULL, SND_FILENAME | SND_ASYNC);
    424. //PlaySound("res/sunshine.wav", NULL, SND_FILENAME | SND_ASYNC);
    425. int index = (msg.x - 163) / 65;
    426. //坤坤
    427. /* if (index + 1 == KUN_KUN && sunshine >= 100)
    428. {
    429. curPlant = index + 1;
    430. status = 1;
    431. curX = msg.x;
    432. curY = msg.y;
    433. sunshine -= 100;
    434. }*/
    435. curPlant = index + 1;
    436. status = 1;
    437. curX = msg.x;
    438. curY = msg.y;
    439. }
    440. else
    441. {
    442. collectSunshine(&msg);
    443. }
    444. }
    445. else if (msg.message == WM_MOUSEMOVE && status == 1)//鼠标移动
    446. {
    447. curX = msg.x;
    448. curY = msg.y;
    449. }
    450. else if (msg.message == WM_LBUTTONUP)//鼠标放下
    451. {
    452. if (msg.x > 256 - 150 && msg.x < Wide - 70 && msg.y > 100 && msg.y < 590)
    453. {
    454. int row = (msg.y - 100) / 102;
    455. int col = (msg.x - 256 + 150 ) / 81;
    456. if (map[row][col].type == 0 && curPlant != PLANT_COUNT + 1 && curPlant != PLANT_COUNT + 2)
    457. {
    458. //printf("%d\n", map[col][row].type);
    459. map[row][col].type = curPlant;
    460. map[row][col].frameIndex = 0;
    461. if(curPlant!=0)
    462. PlaySound("res/audio/coffee.wav", NULL, SND_FILENAME | SND_ASYNC);
    463. if (curPlant == 5)
    464. map[row][col].blood = KUNKUN_BLOOD * 50;
    465. else
    466. map[row][col].blood = KUNKUN_BLOOD;
    467. map[row][col].shootTime = 0;
    468. map[row][col].shoot = false;
    469. map[row][col].x = 256 - 150 + col * 81;
    470. map[row][col].y = 100 + row * 100 - 15;
    471. }
    472. else if (map[row][col].type != 0 && curPlant == PLANT_COUNT + 1)
    473. {
    474. PlaySound("res/audio/coffee.wav", NULL, SND_FILENAME | SND_ASYNC);
    475. map[row][col].type = 0;
    476. map[row][col].blood = 0;
    477. }
    478. else if (curPlant == PLANT_COUNT + 2)
    479. {
    480. if (zmCount >= ZM_MAX)
    481. return;
    482. int i = 0;
    483. int zmMax = sizeof(zms) / sizeof(zms[0]);
    484. for (i = 0; i < zmMax && zms[i].used; i++);
    485. if (i < zmMax)
    486. {
    487. PlaySound("res/audio/coffee.wav", NULL, SND_FILENAME | SND_ASYNC);
    488. memset(&zms[i], 0, sizeof(zms[i]));
    489. zms[i].used = true;
    490. zms[i].speed = 2;
    491. zms[i].row = row;
    492. zms[i].y = 100 + (zms[i].row) * 100 + 70;
    493. zms[i].x = 256 - 150 + (col - 1) * 81;
    494. zms[i].blood = ORDINARY_ZM_BLOOD;
    495. zms[i].dead = false;
    496. zms[i].boom = false;
    497. zms[i].zmSpeed = 4;
    498. zmCount++;
    499. }
    500. }
    501. }
    502. }
    503. else if (msg.message == WM_RBUTTONDOWN)
    504. {
    505. curPlant = 0;
    506. status = 0;
    507. }
    508. }
    509. }
    510. void createSunshine()
    511. {
    512. static int count = 0;
    513. static int fre = 200;
    514. count++;
    515. if (count >= fre)
    516. {
    517. fre = 200 + rand() % 200;
    518. count = 0;
    519. //从阳光池取一个可以使用的
    520. int ballMax = sizeof(balls) / sizeof(balls[0]);
    521. int i;
    522. for (i = 0; i < ballMax && balls[i].used; i++);
    523. if (i >= ballMax)return;
    524. balls[i].used = true;
    525. balls[i].frameIndex = 0;
    526. /* balls[i].x = 160 + rand() % 600;
    527. balls[i].y = 60;
    528. balls[i].destY = (rand() % 4) * 90 + 160;*/
    529. balls[i].timer = 0;
    530. /* balls[i].xoff = 0;
    531. balls[i].yoff = 0;*/
    532. balls[i].status = SUNSHINE_DOWN;
    533. balls[i].t = 0;
    534. balls[i].p1 = vector2(160 + rand() % 600, 60);
    535. balls[i].p4 = vector2(balls[i].p1.x, (rand() % 4) * 90 + 160);
    536. int off = 2;
    537. float distance = balls[i].p4.y - balls[i].p1.y;
    538. balls[i].speed = 1.0 / (distance / off);
    539. }
    540. int ballMax = sizeof(balls) / sizeof(balls[0]);
    541. //向日葵生产阳光
    542. for (int i = 0; i < 5; i++)
    543. {
    544. for (int j = 0; j < 9; j++)
    545. {
    546. if (map[i][j].type == TAI_YANG + 1)
    547. {
    548. map[i][j].timer++;
    549. if (map[i][j].timer > 100)
    550. {
    551. map[i][j].timer = 0;
    552. int k;
    553. for (k = 0; k < ballMax && balls[k].used; k++);
    554. if (k >= ballMax)return;
    555. balls[k].used = true;
    556. balls[k].p1 = vector2(map[i][j].x, map[i][j].y);
    557. int w = (40 + rand() % 50) * (rand() % 2 ? 1 : -1);
    558. balls[k].p4 = vector2(map[i][j].x + w,
    559. map[i][j].y + imgPlant[TAI_YANG][0]->getheight() - imgSunshineBall[0].getheight());
    560. balls[k].p2 = vector2(balls[k].p1.x + w * 0.3, balls[k].p1.y - 100);
    561. balls[k].p3 = vector2(balls[k].p1.x + w * 0.7, balls[k].p1.y - 100);
    562. balls[k].status = SUNSHINE_RPODUCT;
    563. balls[k].speed = 0.05;
    564. balls[k].t = 0;
    565. }
    566. }
    567. }
    568. }
    569. }
    570. void updatSunshine()
    571. {
    572. int ballMax = sizeof(balls) / sizeof(balls[0]);
    573. for (int i = 0; i < ballMax; i++)
    574. {
    575. if (balls[i].used)
    576. {
    577. balls[i].frameIndex = (balls[i].frameIndex + 1) % 29;
    578. if (balls[i].status == SUNSHINE_DOWN)
    579. {
    580. struct sunshineBall* sun = &balls[i];
    581. sun->t += sun->speed;
    582. sun->pCur = sun->p1 + sun->t * (sun->p4 - sun->p1);
    583. if (sun->t >= 1)
    584. {
    585. sun->status = SUNSHINE_GROUND;
    586. sun->timer = 0;
    587. }
    588. }
    589. else if (balls[i].status == SUNSHINE_GROUND)
    590. {
    591. balls[i].timer++;
    592. if (balls[i].timer > 100)
    593. {
    594. balls[i].used = false;
    595. balls[i].timer = 0;
    596. }
    597. }
    598. else if (balls[i].status == SUNSHINE_COLLECT)
    599. {
    600. struct sunshineBall* sun = &balls[i];
    601. sun->t += sun->speed;
    602. sun->pCur = sun->p1 + sun->t * (sun->p4 - sun->p1);
    603. if (sun->t > 1)
    604. {
    605. sun->used = false;
    606. sunshine += 25;
    607. }
    608. }
    609. else if (balls[i].status == SUNSHINE_RPODUCT)
    610. {
    611. struct sunshineBall* sun = &balls[i];
    612. sun->t += sun->speed;
    613. sun->pCur = calcBezierPoint(sun->t,sun->p1, sun->p2, sun->p3, sun->p4);
    614. if (sun->t > 1)
    615. {
    616. sun->status = SUNSHINE_GROUND;
    617. sun->timer = 0;
    618. }
    619. }
    620. }
    621. }
    622. }
    623. int mciZmTime = 0;
    624. void createZM()
    625. {
    626. if (zmCount >= zmCount_max)
    627. return;
    628. static int zmFre = 5000000;
    629. static int count = 0;
    630. count++;
    631. if (count > zmFre)
    632. {
    633. if (mciZmTime == 0)
    634. {
    635. mciSendString("play res/audio/awooga.mp3", 0, 0, 0);
    636. mciZmTime++;
    637. }
    638. count = 0;
    639. zmFre = 202 - 20 * wava_count;
    640. int i = 0;
    641. int zmMax = sizeof(zms) / sizeof(zms[0]);
    642. for (i = 0; i < zmMax && zms[i].used && zms[i].dead == false; i++);
    643. if (i < zmMax)
    644. {
    645. memset(&zms[i], 0, sizeof(zms[i]));
    646. zms[i].used = true;
    647. zms[i].speed = 2;
    648. zms[i].row = rand() % 5;
    649. zms[i].y = 100 + (zms[i].row) * 100 + 70;
    650. zms[i].x = Wide;
    651. zms[i].blood = ORDINARY_ZM_BLOOD;
    652. zms[i].dead = false;
    653. zms[i].boom = false;
    654. zms[i].zmSpeed = 4;
    655. zmCount++;
    656. }
    657. }
    658. }
    659. int zmSpeed = 6;
    660. void updateZM()
    661. {
    662. int zmMax = sizeof(zms) / sizeof(zms[0]);
    663. static int count[ZM_MAX] = { 0 };
    664. //更新僵尸的位置
    665. for (int i = 0; i < zmMax; i++)
    666. {
    667. count[i]++;
    668. if (count[i] >= (gameStatus == GOING ? zms[i].zmSpeed : zmSpeed))
    669. {
    670. //printf("%d ", (gameStatus == GOING ? zms[i].zmSpeed : zmSpeed));
    671. count[i] = 0;
    672. if (zms[i].used)
    673. {
    674. if (zms[i].dead)
    675. {
    676. zms[i].frameIndex++;
    677. if (zms[i].boom == true)
    678. {
    679. if (zms[i].frameIndex >= 20)
    680. {
    681. //printf("%d ", killCount);
    682. zms[i].used = false;
    683. zms[i].row = 0;
    684. //killCount++;
    685. if (killCount >= ZM_MAX)
    686. gameStatus = WIN;
    687. else if (killCount >= zmCount_max)
    688. {
    689. wava_count++;
    690. zmCount_max *= 2;
    691. killCount = 0;
    692. zmCount = 0;
    693. }
    694. }
    695. }
    696. else
    697. {
    698. if (zms[i].frameIndex >= 38)
    699. {
    700. //printf("%d ", killCount);
    701. zms[i].used = false;
    702. zms[i].row = 0;
    703. if (killCount >= ZM_MAX)
    704. gameStatus = WIN;
    705. else if (killCount >= zmCount_max)
    706. {
    707. wava_count++;
    708. zmCount_max *= 2;
    709. killCount = 0;
    710. zmCount = 0;
    711. }
    712. }
    713. }
    714. }
    715. else if (zms[i].eating)
    716. {
    717. //mciSendString("play res/audio/chomp.mp3", 0, 0, 0);
    718. //mciSendString("play res/audio/chompsoft.mp3", 0, 0, 0);
    719. zms[i].frameIndex = (zms[i].frameIndex + 1) % 21;
    720. }
    721. else
    722. {
    723. zms[i].frameIndex++;
    724. if (zms[i].frameIndex >= 22)
    725. {
    726. zms[i].frameIndex = 0;
    727. }
    728. }
    729. zms[i].x -= zms[i].speed;
    730. if (zms[i].x < 0)
    731. {
    732. //printf("GAME OVER\n");
    733. //MessageBox(NULL, "over", "over", 0);//待优化
    734. //exit(0);//待优化
    735. gameStatus = FAIL;
    736. }
    737. }
    738. }
    739. }
    740. }
    741. void shoot()
    742. {
    743. int lines[5] = { 0 };
    744. int bulletMax = sizeof(bullets) / sizeof(bullets[0]);
    745. int bulletMax_wandou = sizeof(bullets_wandou) / sizeof(bullets_wandou[0]);
    746. int bulletMax_hanbing = sizeof(bullets_hanbing) / sizeof(bullets_hanbing[0]);
    747. int bulletMax_santou = sizeof(bullets_santou) / sizeof(bullets_santou[0]);
    748. int zmCount = sizeof(zms) / sizeof(zms[0]);
    749. int dangerX = Wide - 80;
    750. for (int i = 0; i < zmCount; i++)
    751. {
    752. if (zms[i].dead == false && zms[i].x < dangerX && zms[i].x>100)
    753. {
    754. lines[zms[i].row] = 1;
    755. }
    756. }
    757. for (int i = 0; i < 5; i++)
    758. {
    759. for (int j = 0; j < 9; j++)
    760. {
    761. //坤坤
    762. if (map[i][j].type == KUN_KUN + 1 && lines[i])
    763. {
    764. map[i][j].shootTime++;
    765. if (map[i][j].shootTime > 20)
    766. {
    767. map[i][j].shootTime = 0;
    768. int k;
    769. for (k = 0; k < bulletMax && bullets[k].used; k++);
    770. if (k < bulletMax)
    771. {
    772. map[i][j].frameIndex = 3;
    773. bullets[k].used = true;
    774. bullets[k].row = i;
    775. bullets[k].speed = 10;
    776. bullets[k].blast = false;
    777. bullets[k].frameIndex = 0;
    778. int zwX = 256 - 150 + j * 81;
    779. int zwY = 100 + i * 100 - 15;
    780. bullets[k].x = zwX + imgPlant[map[i][j].type - 1][0]->getwidth() - 10;
    781. bullets[k].y = zwY + 5;
    782. }
    783. }
    784. }
    785. //豌豆
    786. else if (map[i][j].type == WAN_DOU + 1 && lines[i])
    787. {
    788. map[i][j].shootTime++;
    789. if (map[i][j].shootTime > 35)
    790. {
    791. map[i][j].shootTime = 0;
    792. int k;
    793. for (k = 0; k < bulletMax_wandou && bullets_wandou[k].used; k++);
    794. if (k < bulletMax_wandou)
    795. {
    796. //map[i][j].shoot = true;
    797. //if(map[i][j].frameIndex > 1)
    798. map[i][j].frameIndex = 2;
    799. bullets_wandou[k].used = true;
    800. bullets_wandou[k].row = i;
    801. bullets_wandou[k].speed = 8;
    802. bullets_wandou[k].blast = false;
    803. bullets_wandou[k].frameIndex = 0;
    804. int zwX = 256 - 150 + j * 81;
    805. int zwY = 100 + i * 100 - 15;
    806. bullets_wandou[k].x = zwX + imgPlant[map[i][j].type - 1][0]->getwidth() - 10;
    807. bullets_wandou[k].y = zwY + 5;
    808. }
    809. }
    810. }
    811. //寒冰豌豆
    812. else if (map[i][j].type == HAN_BING_WAN_DOU + 1 && lines[i])
    813. {
    814. map[i][j].shootTime++;
    815. if (map[i][j].shootTime > 35)
    816. {
    817. map[i][j].shootTime = 0;
    818. int k;
    819. for (k = 0; k < bulletMax_hanbing && bullets_hanbing[k].used; k++);
    820. if (k < bulletMax_hanbing)
    821. {
    822. //map[i][j].shoot = true;
    823. //if(map[i][j].frameIndex > 1)
    824. map[i][j].frameIndex = 4;
    825. bullets_hanbing[k].used = true;
    826. bullets_hanbing[k].row = i;
    827. bullets_hanbing[k].speed = 10;
    828. bullets_hanbing[k].blast = false;
    829. bullets_hanbing[k].frameIndex = 0;
    830. int zwX = 256 - 150 + j * 81;
    831. int zwY = 100 + i * 100 - 15;
    832. bullets_hanbing[k].x = zwX + imgPlant[map[i][j].type - 1][0]->getwidth() - 10;
    833. bullets_hanbing[k].y = zwY + 5;
    834. }
    835. }
    836. }
    837. //三头豌豆
    838. else if (map[i][j].type == SAN_TOU_WAN_DOU + 1 && lines[i])
    839. {
    840. map[i][j].shootTime++;
    841. if (map[i][j].shootTime > 35)
    842. {
    843. map[i][j].shootTime = 0;
    844. int k;
    845. for (int b = 0; b < 3; b++)
    846. {
    847. for (k = 0; k < bulletMax_santou && bullets_santou[k].used; k++);
    848. if (k < bulletMax_santou)
    849. {
    850. //map[i][j].shoot = true;
    851. //if(map[i][j].frameIndex > 1)
    852. //map[i][j].frameIndex = 2;
    853. bullets_santou[k].used = true;
    854. bullets_santou[k].row = i;
    855. bullets_santou[k].speed = 8;
    856. bullets_santou[k].blast = false;
    857. bullets_santou[k].frameIndex = 0;
    858. int zwX = 256 - 150 + j * 81;
    859. int zwY = 100 + i * 100 - 15;
    860. bullets_santou[k].x = zwX + imgPlant[map[i][j].type - 1][0]->getwidth() - 30;
    861. bullets_santou[k].y = zwY + 16;
    862. direction_santou[k] = b;
    863. row_santou[k] = i;
    864. }
    865. }
    866. }
    867. }
    868. }
    869. }
    870. }
    871. void updateBullets_kunkun()
    872. {
    873. int countMax = sizeof(bullets) / sizeof(bullets[0]);
    874. for (int i = 0; i < countMax; i++)
    875. {
    876. if (bullets[i].used)
    877. {
    878. //static double angle = 0;
    879. bullets[i].x += bullets[i].speed;
    880. //angle += bullets[i].speed;
    881. //bullets[i].y += 10;
    882. //bullets[i].x += bullets[i].speed;
    883. if (bullets[i].x > Wide)
    884. {
    885. bullets[i].used = false;
    886. }
    887. //待完善
    888. if (bullets[i].blast)
    889. {
    890. bullets[i].frameIndex++;
    891. if (bullets[i].frameIndex >= 4)
    892. {
    893. bullets[i].used = false;
    894. }
    895. }
    896. }
    897. }
    898. }
    899. void updateBullets_wandou()
    900. {
    901. int countMax_wandou = sizeof(bullets_wandou) / sizeof(bullets_wandou[0]);
    902. for (int i = 0; i < countMax_wandou; i++)
    903. {
    904. if (bullets_wandou[i].used)
    905. {
    906. //static double angle = 0;
    907. bullets_wandou[i].x += bullets_wandou[i].speed;
    908. //angle += bullets[i].speed;
    909. //bullets[i].y += 10;
    910. //bullets[i].x += bullets[i].speed;
    911. if (bullets_wandou[i].x > Wide)
    912. {
    913. bullets_wandou[i].used = false;
    914. }
    915. //待完善
    916. if (bullets_wandou[i].blast)
    917. {
    918. bullets_wandou[i].frameIndex++;
    919. if (bullets_wandou[i].frameIndex >= 4)
    920. {
    921. bullets_wandou[i].used = false;
    922. }
    923. }
    924. }
    925. }
    926. }
    927. void updateBullets_hanbing()
    928. {
    929. int countMax_hanbing = sizeof(bullets_hanbing) / sizeof(bullets_hanbing[0]);
    930. for (int i = 0; i < countMax_hanbing; i++)
    931. {
    932. if (bullets_hanbing[i].used)
    933. {
    934. //static double angle = 0;
    935. bullets_hanbing[i].x += bullets_hanbing[i].speed;
    936. //angle += bullets[i].speed;
    937. //bullets[i].y += 10;
    938. //bullets[i].x += bullets[i].speed;
    939. if (bullets_hanbing[i].x > Wide)
    940. {
    941. bullets_hanbing[i].used = false;
    942. }
    943. //待完善
    944. if (bullets_hanbing[i].blast)
    945. {
    946. bullets_hanbing[i].frameIndex++;
    947. if (bullets_hanbing[i].frameIndex >= 4)
    948. {
    949. bullets_hanbing[i].used = false;
    950. }
    951. }
    952. }
    953. }
    954. }
    955. void updateBullets_santou()
    956. {
    957. int countMax_santou = sizeof(bullets_santou) / sizeof(bullets_santou[0]);
    958. for (int i = 0; i < countMax_santou; i++)
    959. {
    960. if (bullets_santou[i].used)
    961. {
    962. if (direction_santou[i] == MIDDLE)
    963. {//static double angle = 0;
    964. bullets_santou[i].x += bullets_santou[i].speed;
    965. //bullets[i].x += bullets[i].speed;
    966. if (bullets_santou[i].x > Wide)
    967. {
    968. bullets_santou[i].used = false;
    969. }
    970. }
    971. else if (direction_santou[i] == UP)
    972. {
    973. int destY = 85 + (row_santou[i] - 1) * 100;
    974. //int zwX = 256 - 150 + j * 81;
    975. float angle = atan(0.6);
    976. bullets_santou[i].x += bullets_santou[i].speed;
    977. bullets_santou[i].y -= bullets_santou[i].speed * tan(angle);
    978. //printf("%d\n", row_santou[i]);
    979. //printf("destY = %d\n", destY);
    980. //printf("bullets[i].y = %lf\n", bullets[i].y);
    981. if (bullets_santou[i].y <= destY + 16)
    982. {
    983. direction_santou[i] = MIDDLE;
    984. }
    985. }
    986. else if (direction_santou[i] == DOWN)
    987. {
    988. int destY = 85 + (row_santou[i] + 1) * 100;
    989. float angle = atan(0.6);
    990. bullets_santou[i].x += bullets_santou[i].speed;
    991. bullets_santou[i].y += bullets_santou[i].speed * tan(angle);
    992. if (bullets_santou[i].y >= destY + 16)
    993. {
    994. direction_santou[i] = MIDDLE;
    995. }
    996. }
    997. //待完善
    998. if (bullets_santou[i].blast)
    999. {
    1000. bullets_santou[i].frameIndex++;
    1001. if (bullets_santou[i].frameIndex >= 4)
    1002. {
    1003. bullets_santou[i].used = false;
    1004. }
    1005. }
    1006. }
    1007. }
    1008. }
    1009. void updateBullets()
    1010. {
    1011. //坤坤
    1012. updateBullets_kunkun();
    1013. //豌豆射手
    1014. updateBullets_wandou();
    1015. //寒冰豌豆
    1016. updateBullets_hanbing();
    1017. //三头豌豆
    1018. updateBullets_santou();
    1019. }
    1020. void checkBullet2Zm_kunkun()
    1021. {
    1022. int bCount = sizeof(bullets) / sizeof(bullets[0]);
    1023. int zCount = sizeof(zms) / sizeof(zms[0]);
    1024. for (int i = 0; i < bCount; i++)
    1025. {
    1026. //if (bullets[i].used || bullets[i].blast == false)
    1027. {
    1028. for (int j = 0; j < zCount; j++)
    1029. {
    1030. if (zms[j].used == false)continue;
    1031. int x1 = zms[j].x + 80;
    1032. int x2 = zms[j].x + 110;
    1033. int x = bullets[i].x;
    1034. if (zms[j].dead == false &&
    1035. bullets[i].row == zms[j].row && x > x1 && x < x2 && bullets[i].used) {
    1036. zms[j].blood -= 20;
    1037. zms[j].x += 1;
    1038. bullets[i].blast = true;
    1039. bullets[i].speed = 0;
    1040. //bullets[i].x = 0;
    1041. if (zms[j].blood <= 0)
    1042. {
    1043. killCount++;
    1044. zms[j].dead = true;
    1045. zms[j].speed = 0;
    1046. zms[j].frameIndex = 0;
    1047. }
    1048. break;
    1049. }
    1050. }
    1051. }
    1052. }
    1053. }
    1054. void checkBullet2Zm_wandou()
    1055. {
    1056. int bCount = sizeof(bullets_wandou) / sizeof(bullets_wandou[0]);
    1057. int zCount = sizeof(zms) / sizeof(zms[0]);
    1058. for (int i = 0; i < bCount; i++)
    1059. {
    1060. //if (bullets[i].used || bullets[i].blast == false)
    1061. for (int j = 0; j < zCount; j++)
    1062. {
    1063. if (zms[j].used == false)continue;
    1064. int x1 = zms[j].x + 80;
    1065. int x2 = zms[j].x + 110;
    1066. int x = bullets_wandou[i].x;
    1067. if (zms[j].dead == false &&
    1068. bullets_wandou[i].row == zms[j].row && x > x1 && x < x2 && bullets_wandou[i].used) {
    1069. zms[j].blood -= 20;
    1070. bullets_wandou[i].blast = true;
    1071. bullets_wandou[i].speed = 0;
    1072. //bullets_wandou[i].x = 0;
    1073. if (zms[j].blood <= 0)
    1074. {
    1075. killCount++;
    1076. zms[j].dead = true;
    1077. zms[j].speed = 0;
    1078. zms[j].frameIndex = 0;
    1079. }
    1080. break;
    1081. }
    1082. }
    1083. }
    1084. }
    1085. void checkBullet2Zm_hanbing()
    1086. {
    1087. int bCount = sizeof(bullets_hanbing) / sizeof(bullets_hanbing[0]);
    1088. int zCount = sizeof(zms) / sizeof(zms[0]);
    1089. for (int i = 0; i < bCount; i++)
    1090. {
    1091. //if (bullets[i].used || bullets[i].blast == false)
    1092. for (int j = 0; j < zCount; j++)
    1093. {
    1094. if (zms[j].used == false)continue;
    1095. int x1 = zms[j].x + 80;
    1096. int x2 = zms[j].x + 110;
    1097. int x = bullets_hanbing[i].x;
    1098. if (zms[j].dead == false &&
    1099. bullets_hanbing[i].row == zms[j].row && x > x1 && x < x2 && bullets_hanbing[i].used) {
    1100. zms[j].blood -= 20;
    1101. zms[j].zmSpeed = 7;
    1102. bullets_hanbing[i].blast = true;
    1103. bullets_hanbing[i].speed = 0;
    1104. //bullets_hanbing[i].x = 0;
    1105. if (zms[j].blood <= 0)
    1106. {
    1107. killCount++;
    1108. zms[j].dead = true;
    1109. zms[j].speed = 0;
    1110. zms[j].frameIndex = 0;
    1111. zms[j].zmSpeed = 4;
    1112. }
    1113. break;
    1114. }
    1115. }
    1116. }
    1117. }
    1118. void checkBullet2Zm_santou()
    1119. {
    1120. int bCount = sizeof(bullets_santou) / sizeof(bullets_santou[0]);
    1121. int zCount = sizeof(zms) / sizeof(zms[0]);
    1122. for (int i = 0; i < bCount; i++)
    1123. {
    1124. bullets_santou[i].row = (bullets_santou[i].y - 85+5) / 100;
    1125. //if (bullets[i].used || bullets[i].blast == false)
    1126. for (int j = 0; j < zCount; j++)
    1127. {
    1128. //100 + i * 100 - 15
    1129. if (zms[j].used == false)continue;
    1130. int x1 = zms[j].x + 80;
    1131. int x2 = zms[j].x + 110;
    1132. int x = bullets_santou[i].x;
    1133. if (zms[j].dead == false &&
    1134. bullets_santou[i].row == zms[j].row && x > x1 && x < x2 && bullets_santou[i].used) {
    1135. zms[j].blood -= 20;
    1136. bullets_santou[i].blast = true;
    1137. bullets_santou[i].speed = 0;
    1138. //bullets_santou[i].x = 0;
    1139. if (zms[j].blood <= 0)
    1140. {
    1141. killCount++;
    1142. zms[j].dead = true;
    1143. zms[j].speed = 0;
    1144. zms[j].frameIndex = 0;
    1145. zms[j].zmSpeed = 4;
    1146. }
    1147. break;
    1148. }
    1149. }
    1150. }
    1151. }
    1152. void checkBullet2Zm()
    1153. {
    1154. //坤坤
    1155. checkBullet2Zm_kunkun();
    1156. //豌豆
    1157. checkBullet2Zm_wandou();
    1158. //寒冰豌豆
    1159. checkBullet2Zm_hanbing();
    1160. //三头豌豆
    1161. checkBullet2Zm_santou();
    1162. }
    1163. void checkBoom2Zm()
    1164. {
    1165. int zCount = sizeof(zms) / sizeof(zms[0]);
    1166. for (int i = 0; i < 5; i++)
    1167. {
    1168. for (int j = 0; j < 9; j++)
    1169. {
    1170. //樱桃
    1171. if (map[i][j].type == YING_TAO + 1)
    1172. {
    1173. if (map[i][j].frameIndex > 8)
    1174. {
    1175. PlaySound("res/audio/cherrybomb.wav", NULL, SND_FILENAME | SND_ASYNC);
    1176. //map[row][col].x = 256 - 150 + col * 81;
    1177. //map[row][col].y = 100 + row * 100 - 15;
    1178. map[i][j].type = 0;
    1179. map[i][j].frameIndex = 0;
    1180. int x1 = 100 + 81 * (j - 1);
    1181. int x2 = 100 + 81 * (j + 2);
    1182. int y1 = 85 + (i - 1) * 100;
    1183. int y2 = 85 + (i + 2) * 100;
    1184. for (int k = 0; k < zCount; k++)
    1185. {
    1186. if (zms[k].used == false)continue;
    1187. int zmX = zms[k].x + imgZm[0].getwidth() / 2;
    1188. int zmY = zms[k].y;
    1189. if (zmX <= x2 && zmX >= x1 && zmY >= y1 && zmY <= y2 && zms[k].dead == false)
    1190. {
    1191. killCount++;
    1192. zms[k].boom = true;
    1193. zms[k].dead = true;
    1194. zms[k].speed = 0;
    1195. zms[k].frameIndex = 0;
    1196. zms[k].blood = 0;
    1197. }
    1198. }
    1199. }
    1200. }
    1201. //火爆辣椒
    1202. else if (map[i][j].type == LA_JIAO + 1)
    1203. {
    1204. if (map[i][j].frameIndex > 7)
    1205. {
    1206. if (map[i][j].frameIndex == 8)
    1207. PlaySound("res/audio/firepea.wav", NULL, SND_FILENAME | SND_ASYNC);
    1208. for (int k = 0; k < zCount; k++)
    1209. {
    1210. if (zms[k].used == false)continue;
    1211. if (zms[k].row == i && zms[k].x < Wide - 80 - 70 && zms[k].dead == false)
    1212. {
    1213. killCount++;
    1214. zms[k].boom = true;
    1215. zms[k].dead = true;
    1216. zms[k].speed = 0;
    1217. zms[k].frameIndex = 0;
    1218. zms[k].blood = 0;
    1219. }
    1220. }
    1221. if (map[i][j].frameIndex > 14)
    1222. {
    1223. map[i][j].type = 0;
    1224. map[i][j].frameIndex = 0;
    1225. }
    1226. }
    1227. }
    1228. }
    1229. }
    1230. }
    1231. void checkZM2Zhiwu()
    1232. {
    1233. int chomp = 0;
    1234. //mciSendString("play ZM_BGM repeat", NULL, NULL, NULL);
    1235. char name[64];
    1236. int bCount = sizeof(bullets) / sizeof(bullets[0]);
    1237. int zCount = sizeof(zms) / sizeof(zms[0]);
    1238. for (int i = 0; i < zCount; i++)
    1239. {
    1240. //killCount = 0;
    1241. if (zms[i].dead)continue;
    1242. //zms[i].chomptime = 0;
    1243. int row = zms[i].row;
    1244. for (int j = 0; j < 9; j++)
    1245. {
    1246. //if (map[row][j].type == 0)continue;
    1247. //
    1248. int zhiwuX = 101 + j * 81;
    1249. int x1 = zhiwuX;
    1250. int x2 = zhiwuX + 81;
    1251. int x3 = zms[i].x + 100;
    1252. if (x3 >= x1 && x3 <= x2)
    1253. {
    1254. if (map[row][j].blood <= 0 || (map[row][j].type == 0 && zms[i].eating != false))
    1255. {
    1256. map[row][j].blood = 0;
    1257. map[row][j].type = 0;
    1258. zms[i].eating = false;
    1259. //zms[i].frameIndex = 0;
    1260. zms[i].speed = 3;
    1261. }
    1262. else if (map[row][j].type != 0)
    1263. {
    1264. //mciSendString("play ZM_BGM repeat", NULL, NULL, NULL);
    1265. //mciSendString("play name repeat", NULL, 0, NULL);
    1266. zms[i].eating = true;
    1267. zms[i].speed = 0;
    1268. if (map[row][j].type != 3 && map[row][j].type != 7)
    1269. map[row][j].blood--;
    1270. //zms[i].frameIndex = 0;
    1271. }
    1272. if (zms[i].eating && chomp == 0)
    1273. chomp = 1;
    1274. }
    1275. else if (x3 > 830)
    1276. {
    1277. zms[i].eating = false;
    1278. zms[i].speed = 3;
    1279. }
    1280. }
    1281. }
    1282. static int chomp_time = 0;
    1283. chomp_time++;
    1284. if (chomp&&chomp_time>20)
    1285. {
    1286. chomp_time = 0;
    1287. PlaySound("res/audio/chomp.wav", NULL, SND_FILENAME | SND_ASYNC);
    1288. //mciSendString("play ZM_BGM", NULL, NULL, NULL);
    1289. //printf("1 ");
    1290. }
    1291. }
    1292. void checkcars2Zm()
    1293. {
    1294. for (int i = 0; i < 5; i++)
    1295. {
    1296. int carsX = cars[i].x + 70;
    1297. for (int j = 0; j < ZM_MAX; j++)
    1298. {
    1299. if (zms[j].used && zms[j].dead == false && zms[j].row == i)
    1300. {
    1301. int zmX = zms[j].x + 80;
    1302. if (carsX > zmX && cars[i].used)
    1303. {
    1304. if (cars[i].move == false)
    1305. cars[i].move = true;
    1306. else
    1307. {
    1308. killCount++;
    1309. zms[j].dead = true;
    1310. zms[j].speed = 0;
    1311. zms[j].frameIndex = 0;
    1312. }
    1313. }
    1314. }
    1315. }
    1316. }
    1317. }
    1318. void collistionCheck()
    1319. {
    1320. //子弹对僵尸的检测
    1321. checkBullet2Zm();
    1322. //僵尸对植物的检测
    1323. checkZM2Zhiwu();
    1324. //爆炸对植物的检测
    1325. checkBoom2Zm();
    1326. //小推车对僵尸的检测
    1327. checkcars2Zm();
    1328. }
    1329. void updatecar()
    1330. {
    1331. for (int i = 0; i < 5; i++)
    1332. {
    1333. if (cars[i].move)
    1334. {
    1335. cars[i].x += 20;
    1336. }
    1337. if (cars[i].x > Wide)
    1338. {
    1339. cars[i].move = false;
    1340. cars[i].used = false;
    1341. }
    1342. }
    1343. }
    1344. void updateGame()
    1345. {
    1346. srand((unsigned)time(NULL));
    1347. static int count = 0;
    1348. count++;
    1349. if (count > 4)
    1350. {
    1351. count = 0;
    1352. for (int i = 0; i < 5; i++)
    1353. {
    1354. for (int j = 0; j < 9; j++)
    1355. {
    1356. if (map[i][j].type > 0)
    1357. {
    1358. map[i][j].frameIndex++;
    1359. int PlantType = map[i][j].type - 1;
    1360. int index = map[i][j].frameIndex;
    1361. if (map[i][j].shoot)
    1362. {
    1363. if (map[i][j].frameIndex > 1)
    1364. {
    1365. map[i][j].shoot = false;
    1366. }
    1367. }
    1368. else
    1369. {
    1370. if (imgPlant[PlantType][index] == NULL)
    1371. {
    1372. map[i][j].frameIndex = 0;
    1373. }
    1374. }
    1375. }
    1376. }
    1377. }
    1378. }
    1379. createSunshine();//创建阳光
    1380. updatSunshine();//更新阳光状态
    1381. createZM();//创建僵尸
    1382. updateZM();//更新僵尸状态
    1383. shoot();//发射豌豆子弹
    1384. updateBullets();//更新子弹
    1385. collistionCheck();//实现豌豆子弹的碰撞检测
    1386. updatecar();//更新小推车
    1387. }
    1388. void menu()
    1389. {
    1390. mciSendString("play BGM", NULL, NULL, NULL);
    1391. IMAGE imgBg, imgMenu1, imgMenu2;
    1392. loadimage(&imgBg, "res/menu.png");
    1393. loadimage(&imgMenu1, "res/menu2.png");
    1394. loadimage(&imgMenu2, "res/menu1.png");
    1395. int flag = 0;
    1396. while (1)
    1397. {
    1398. BeginBatchDraw();
    1399. putimage(0, 0, &imgBg);
    1400. putimagePNG(474, 75, flag ? &imgMenu1 : &imgMenu2);
    1401. ExMessage msg;
    1402. if (peekmessage(&msg))
    1403. {
    1404. if (msg.message == WM_LBUTTONDOWN &&
    1405. msg.x > 474 && msg.x < 474 + 300 &&
    1406. msg.y>75 && msg.y < 75 + 140)
    1407. {
    1408. flag = 1;
    1409. PlaySound("res/audio/bleep.wav", NULL, SND_FILENAME | SND_ASYNC);
    1410. }
    1411. else if (msg.message == WM_LBUTTONUP && flag == 1)
    1412. {
    1413. EndBatchDraw();
    1414. break;
    1415. }
    1416. }
    1417. EndBatchDraw();
    1418. }
    1419. }
    1420. void viewScence()
    1421. {
    1422. mciSendString("play BGM3", NULL, NULL, NULL);
    1423. //开头场景时僵尸的位置
    1424. vector2 points[9] = {
    1425. {550,80},{530,160},{630,170},{530,200},{515,270},
    1426. {565,370},{605,340},{705,280},{690,340}
    1427. };
    1428. int index[9];
    1429. for (int i = 0; i < 9; i++)
    1430. {
    1431. index[i] = rand() % 11;
    1432. }
    1433. int count = 0;
    1434. for (int i = 0; i >= -500; i-=3)
    1435. {
    1436. BeginBatchDraw();
    1437. putimage(i, 0, &img);
    1438. count++;
    1439. for (int k = 0; k < 9; k++)
    1440. {
    1441. putimagePNG(points[k].x + 500 + i,
    1442. points[k].y, &imgZmStand[index[k]]);
    1443. if (count >= 10)
    1444. {
    1445. index[k] = (index[k] + 1) % 11;
    1446. }
    1447. }
    1448. if (count >= 10)count = 0;
    1449. EndBatchDraw();
    1450. Sleep(10);
    1451. }
    1452. for (int i = 0; i < 60; i++)
    1453. {
    1454. BeginBatchDraw();
    1455. putimage(-500, 0, &img);
    1456. for (int k = 0; k < 9; k++)
    1457. {
    1458. putimagePNG(points[k].x, points[k].y, &imgZmStand[index[k]]);
    1459. index[k] = (index[k] + 1) % 11;
    1460. }
    1461. EndBatchDraw();
    1462. Sleep(50);
    1463. }
    1464. for (int i = -500; i <= -150; i += 2)
    1465. {
    1466. BeginBatchDraw();
    1467. putimage(i, 0, &img);
    1468. count++;
    1469. for (int k = 0; k < 9; k++)
    1470. {
    1471. putimagePNG(points[k].x + 500 + i,
    1472. points[k].y, &imgZmStand[index[k]]);
    1473. if (count >= 10)
    1474. {
    1475. index[k] = (index[k] + 1) % 11;
    1476. }
    1477. if (count >= 10) count = 0;
    1478. }
    1479. EndBatchDraw();
    1480. Sleep(10);
    1481. }
    1482. }
    1483. void barsDown()
    1484. {
    1485. int height = imgBar.getheight();
    1486. for (int y = -height; y <= -10; y++)
    1487. {
    1488. BeginBatchDraw();
    1489. putimagePNG(80, y, &imgBar);
    1490. for (int i = 0; i < PLANT_COUNT + 2; i++)
    1491. {
    1492. putimagePNG(163 + i * 65, y + 10, &imgCards[i]);
    1493. }
    1494. EndBatchDraw();
    1495. Sleep(10);
    1496. }
    1497. for (int i = 0; i < 5; i++)
    1498. {
    1499. putimagePNG(50, 100 + i * 100 - 15, &imgcar);
    1500. }
    1501. mciSendString("close BGM3", NULL, 0, NULL);
    1502. mciSendString("play BGM4", NULL, NULL, NULL);
    1503. Sleep(1000);
    1504. putimagePNG(450 - imgready.getwidth()/2, 300 - imgready.getheight()/2, &imgready);
    1505. Sleep(200);
    1506. }
    1507. void failScence()
    1508. {
    1509. for (int i = -150; i <= -100; i += 1)
    1510. {
    1511. BeginBatchDraw();
    1512. //zmSpeed = 6;
    1513. putimage(i, 0, &img);
    1514. //show();
    1515. drawZm();
    1516. //updateGame();
    1517. createZM();//创建僵尸
    1518. updateZM();//更新僵尸状态
    1519. EndBatchDraw();
    1520. Sleep(50);
    1521. }
    1522. }
    1523. bool checkOver()
    1524. {
    1525. int ret = false;
    1526. if (gameStatus == WIN)
    1527. {
    1528. mciSendString("close BGM2", NULL, NULL, NULL);
    1529. loadimage(0, "res/win2.png");
    1530. mciSendString("play res/win.mp3", 0, 0, 0);
    1531. ret = true;
    1532. }
    1533. else if (gameStatus == FAIL)
    1534. {
    1535. mciSendString("close BGM2", NULL, NULL, NULL);
    1536. mciSendString("play res/lose.mp3", 0, 0, 0);
    1537. failScence();
    1538. Sleep(500);
    1539. loadimage(0, "res/fail2.png");
    1540. ret = true;
    1541. }
    1542. return ret;
    1543. }
    1544. void OpeningAnimation()
    1545. {
    1546. mciSendString("play res/audio/yuanshen.mp3", 0, 0, 0);
    1547. for (int i = 0; i < 29; i++)
    1548. {
    1549. BeginBatchDraw();
    1550. putimage(-148, -35, &imgopena[i]);
    1551. EndBatchDraw();
    1552. Sleep(50);
    1553. }
    1554. Sleep(4000);
    1555. }
    1556. int main()
    1557. {
    1558. //加载游戏画面
    1559. gameInit();
    1560. //开场动画
    1561. OpeningAnimation();
    1562. menu();
    1563. mciSendString("close BGM", NULL, 0, NULL);
    1564. //游戏开始时的场景切换
    1565. viewScence();
    1566. //游戏开始时卡牌和卡牌槽的下落
    1567. barsDown();
    1568. int timer = 0;
    1569. bool flag = true;
    1570. mciSendString("play BGM2 repeat", NULL, NULL, NULL);
    1571. while (1)
    1572. {
    1573. //用户操作
    1574. userClick();
    1575. //游戏更新时间
    1576. timer += getDelay();
    1577. if (timer > 20)
    1578. {
    1579. flag = true;
    1580. timer = 0;
    1581. }
    1582. if (flag)
    1583. {
    1584. flag = false;
    1585. //绘制游戏画面
    1586. show();
    1587. //更新游戏画面
    1588. updateGame();
    1589. if(checkOver()) break;
    1590. }
    1591. }
    1592. closegraph;
    1593. system("pause");
    1594. return 0;
    1595. }

    game.h文件

    1. #pragma once
    2. #define _CRT_SECURE_NO_WARNINGS 1
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include"tools.h"
    8. #include
    9. #include"vector2.h"
    10. #pragma comment(lib,"winmm.lib")
    11. #define Wide 900
    12. #define Hight 600
    13. #define KUNKUN_BLOOD 100//非坚果植物的血量
    14. #define ORDINARY_ZM_BLOOD 1270*3//僵尸血量
    15. #define ZM_MAX 1024//创建僵尸的最大数量
    16. enum {
    17. WAN_DOU, TAI_YANG, LA_JIAO, KUN_KUN, JIAN_GUO,
    18. HAN_BING_WAN_DOU, YING_TAO, SAN_TOU_WAN_DOU, PLANT_COUNT
    19. };
    20. IMAGE img;//地图
    21. IMAGE imgBar;//卡牌槽
    22. IMAGE imgCards[PLANT_COUNT + 2];//卡牌
    23. IMAGE* imgPlant[PLANT_COUNT + 2][20];//植物动作
    24. IMAGE imgZmStand[11];//开场僵尸的站立
    25. IMAGE imgcar;//小推车
    26. IMAGE imgopena[29];//开场动画
    27. IMAGE imgready;
    28. IMAGE imgnotify;
    29. int curX, curY;//当前选中植物,在移动过程中植物的坐标
    30. int curPlant;// 0:没有选中,1:选中了第一种种植物
    31. int sunshine;
    32. enum { GOING, WIN, FAIL };
    33. int killCount;//已经杀掉的僵尸个数
    34. int zmCount;//已经出现的僵尸个数
    35. int zmCount_max = 1;//每波出现的僵尸数量
    36. int gameStatus;//游戏的状态
    37. int wava_count = 1;//第wava_count波僵尸
    38. struct plant
    39. {
    40. int type;//植物类型
    41. int frameIndex;//植物动作帧
    42. //bool catched;//是否被吃
    43. int blood;//血量
    44. int shootTime;//植物子弹的射速
    45. int timer;//阳光生产的时间
    46. int x, y;//植物坐标
    47. bool shoot;//判断植物是否处于发射状态
    48. };
    49. struct plant map[5][9];
    50. enum { SUNSHINE_DOWN, SUNSHINE_GROUND, SUNSHINE_COLLECT, SUNSHINE_RPODUCT };
    51. struct sunshineBall
    52. {
    53. int x, y;
    54. int frameIndex;//当前显示的图片帧序号
    55. int destY;//飘落的目标位置的y坐标
    56. bool used;//是否在使用
    57. int timer;
    58. float xoff;
    59. float yoff;
    60. float t;//贝塞尔曲线的时间点
    61. vector2 p1, p2, p3, p4;
    62. vector2 pCur;//当前时刻阳光球的位置
    63. float speed;
    64. int status;
    65. };
    66. //10个阳光球
    67. struct sunshineBall balls[10];
    68. IMAGE imgSunshineBall[29];
    69. struct zm
    70. {
    71. int x, y;//僵尸的坐标
    72. int frameIndex;//僵尸动作帧
    73. bool used;//僵尸是否被使用
    74. int speed;//僵尸每一次移动的位移
    75. int row;//僵尸所在行
    76. int blood;//僵尸血量
    77. bool dead;//僵尸是否死亡
    78. bool eating;//僵尸是否在吃植物
    79. bool boom;//僵尸是否被炸死
    80. int zmSpeed;//僵尸的移动快慢
    81. };
    82. struct zm zms[ZM_MAX];
    83. IMAGE imgZm[22];
    84. IMAGE imgZMDead[38];
    85. IMAGE imgzmboom[20];
    86. IMAGE imgZMEat[21];
    87. //子弹
    88. struct bullet
    89. {
    90. double x, y;//子弹的坐标
    91. bool used;//子弹是否被使用
    92. int row;//子弹所在行
    93. int speed;//子弹速度
    94. bool blast;//是否发生爆炸
    95. int frameIndex;//帧序号
    96. };
    97. //坤坤
    98. struct bullet bullets[10000];
    99. IMAGE imgBulletNormal;
    100. IMAGE imgBallBlast[4];
    101. //豌豆
    102. struct bullet bullets_wandou[200];
    103. IMAGE imgBallBlast_wandou[4];
    104. IMAGE imgBulletNormal_wandou;
    105. //寒冰豌豆
    106. struct bullet bullets_hanbing[200];
    107. IMAGE imgBallBlast_hanbing[4];
    108. IMAGE imgBulletNormal_hanbing;
    109. //三头豌豆
    110. struct bullet bullets_santou[200];
    111. IMAGE imgBallBlast_santou[4];
    112. IMAGE imgBulletNormal_santou;
    113. int direction_santou[200];
    114. int row_santou[200];//三头豌豆发射子弹时所在的行数
    115. enum { MIDDLE, UP, DOWN };
    116. //小推车
    117. struct car
    118. {
    119. bool move;//是否处于移动状态
    120. int x, y;//位置
    121. bool used;//是否被使用
    122. };
    123. struct car cars[5];
    124. /*
    125. * 增加植物的步骤:
    126. * 1. 创建子弹的相关变量
    127. * 2. 加载植物子弹图片
    128. * 3. 渲染植物子弹
    129. * 4. 发射植物子弹
    130. * 5. 检查植物子弹与僵尸的碰撞
    131. * 6. 更新植物子弹
    132. */

    vector2.cpp文件(贝塞尔曲线)

    1. //头文件要求
    2. #include
    3. #include "vector2.h"
    4. //加法
    5. vector2 operator +(vector2 x, vector2 y) {
    6. return vector2(x.x + y.x, x.y + y.y );
    7. }
    8. //减法
    9. vector2 operator -(vector2 x, vector2 y) {
    10. return vector2(x.x - y.x, x.y - y.y);
    11. }
    12. // 乘法
    13. vector2 operator *(vector2 x, vector2 y) {
    14. return vector2(x.x * y.x - x.y * y.y, x.y * y.x + x.x * y.y);
    15. }
    16. // 乘法
    17. vector2 operator *(vector2 y, float x) {
    18. return vector2(x*y.x, x*y.y);
    19. }
    20. vector2 operator *(float x, vector2 y) {
    21. return vector2(x * y.x, x * y.y);
    22. }
    23. //叉积
    24. long long cross(vector2 x, vector2 y) { return x.y * y.x - x.x * y.y; }
    25. //数量积 点积
    26. long long dot(vector2 x, vector2 y) { return x.x * y.x + x.y * y.y; }
    27. //四舍五入除法
    28. long long dv(long long a, long long b) {//注意重名!!!
    29. return b < 0 ? dv(-a, -b)
    30. : (a < 0 ? -dv(-a, b)
    31. : (a + b / 2) / b);
    32. }
    33. //模长平方
    34. long long len(vector2 x) { return x.x * x.x + x.y * x.y; }
    35. //模长
    36. long long dis(vector2 x) { return sqrt(x.x * x.x + x.y * x.y); }
    37. //向量除法
    38. vector2 operator /(vector2 x, vector2 y) {
    39. long long l = len(y);
    40. return vector2(dv(dot(x, y), l), dv(cross(x, y), l));
    41. }
    42. //向量膜
    43. vector2 operator %(vector2 x, vector2 y) { return x - ((x / y) * y); }
    44. //向量GCD
    45. vector2 gcd(vector2 x, vector2 y) { return len(y) ? gcd(y, x % y) : x; }
    46. vector2 calcBezierPoint(float t, vector2 p0, vector2 p1, vector2 p2, vector2 p3) {
    47. float u = 1 - t;
    48. float tt = t * t;
    49. float uu = u * u;
    50. float uuu = uu * u;
    51. float ttt = tt * t;
    52. vector2 p = uuu * p0;
    53. p = p + 3 * uu * t * p1;
    54. p = p + 3 * u * tt * p2;
    55. p = p + ttt * p3;
    56. return p;
    57. }

    vector2.h文件

    1. #pragma once
    2. //头文件要求
    3. #include
    4. struct vector2 {
    5. vector2(int _x=0, int _y=0) :x(_x), y(_y) {}
    6. vector2(int* data) :x(data[0]), y(data[1]){}
    7. long long x, y;
    8. };
    9. //加法
    10. vector2 operator +(vector2 x, vector2 y);
    11. //减法
    12. vector2 operator -(vector2 x, vector2 y);
    13. // 乘法
    14. vector2 operator *(vector2 x, vector2 y);
    15. vector2 operator *(vector2, float);
    16. vector2 operator *(float, vector2);
    17. //叉积
    18. long long cross(vector2 x, vector2 y);
    19. //数量积 点积
    20. long long dot(vector2 x, vector2 y);
    21. //四舍五入除法
    22. long long dv(long long a, long long b);
    23. //模长平方
    24. long long len(vector2 x);
    25. //模长
    26. long long dis(vector2 x);
    27. //向量除法
    28. vector2 operator /(vector2 x, vector2 y);
    29. //向量膜
    30. vector2 operator %(vector2 x, vector2 y);
    31. //向量GCD
    32. vector2 gcd(vector2 x, vector2 y);
    33. vector2 calcBezierPoint(float t, vector2 p0, vector2 p1, vector2 p2, vector2 p3);

    tools.cpp文件(透明贴图)

    1. #include "tools.h"
    2. // 载入PNG图并去透明部分
    3. void _putimagePNG(int picture_x, int picture_y, IMAGE* picture) //x为载入图片的X坐标,y为Y坐标
    4. {
    5. DWORD* dst = GetImageBuffer(); // GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带
    6. DWORD* draw = GetImageBuffer();
    7. DWORD* src = GetImageBuffer(picture); //获取picture的显存指针
    8. int picture_width = picture->getwidth(); //获取picture的宽度,EASYX自带
    9. int picture_height = picture->getheight(); //获取picture的高度,EASYX自带
    10. int graphWidth = getwidth(); //获取绘图区的宽度,EASYX自带
    11. int graphHeight = getheight(); //获取绘图区的高度,EASYX自带
    12. int dstX = 0; //在显存里像素的角标
    13. // 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算
    14. for (int iy = 0; iy < picture_height; iy++)
    15. {
    16. for (int ix = 0; ix < picture_width; ix++)
    17. {
    18. int srcX = ix + iy * picture_width; //在显存里像素的角标
    19. int sa = ((src[srcX] & 0xff000000) >> 24); //0xAArrggbb;AA是透明度
    20. int sr = ((src[srcX] & 0xff0000) >> 16); //获取RGB里的R
    21. int sg = ((src[srcX] & 0xff00) >> 8); //G
    22. int sb = src[srcX] & 0xff; //B
    23. if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight)
    24. {
    25. dstX = (ix + picture_x) + (iy + picture_y) * graphWidth; //在显存里像素的角标
    26. int dr = ((dst[dstX] & 0xff0000) >> 16);
    27. int dg = ((dst[dstX] & 0xff00) >> 8);
    28. int db = dst[dstX] & 0xff;
    29. draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16)
    30. | ((sg * sa / 255 + dg * (255 - sa) / 255) << 8)
    31. | (sb * sa / 255 + db * (255 - sa) / 255);
    32. }
    33. }
    34. }
    35. }
    36. // 适用于 y <0 以及x<0的任何情况
    37. void putimagePNG(int x, int y, IMAGE* picture) {
    38. IMAGE imgTmp, imgTmp2, imgTmp3;
    39. int winWidth = getwidth();
    40. int winHeight = getheight();
    41. if (y < 0) {
    42. SetWorkingImage(picture);
    43. getimage(&imgTmp, 0, -y,
    44. picture->getwidth(), picture->getheight() + y);
    45. SetWorkingImage();
    46. y = 0;
    47. picture = &imgTmp;
    48. }
    49. else if (y >= getheight() || x >= getwidth()) {
    50. return;
    51. }
    52. else if (y + picture->getheight() > winHeight) {
    53. SetWorkingImage(picture);
    54. getimage(&imgTmp, x, y, picture->getwidth(), winHeight - y);
    55. SetWorkingImage();
    56. picture = &imgTmp;
    57. }
    58. if (x < 0) {
    59. SetWorkingImage(picture);
    60. getimage(&imgTmp2, -x, 0, picture->getwidth() + x, picture->getheight());
    61. SetWorkingImage();
    62. x = 0;
    63. picture = &imgTmp2;
    64. }
    65. if (x > winWidth - picture->getwidth()) {
    66. SetWorkingImage(picture);
    67. getimage(&imgTmp3, 0, 0, winWidth - x, picture->getheight());
    68. SetWorkingImage();
    69. picture = &imgTmp3;
    70. }
    71. _putimagePNG(x, y, picture);
    72. }
    73. int getDelay() {
    74. static unsigned long long lastTime = 0;
    75. unsigned long long currentTime = GetTickCount();
    76. if (lastTime == 0) {
    77. lastTime = currentTime;
    78. return 0;
    79. }
    80. else {
    81. int ret = currentTime - lastTime;
    82. lastTime = currentTime;
    83. return ret;
    84. }
    85. }

    tools.h文件 

    1. #pragma once
    2. #include
    3. void putimagePNG(int picture_x, int picture_y, IMAGE* picture);
    4. int getDelay();
  • 相关阅读:
    使用Spring+Postman实现数据交互
    Python 中 key 参数的含义及用法
    NBU计算机大三下期末考
    计算机视觉:驾驶员疲劳检测
    6-羧基四甲基罗丹明,CAS号: 91809-67-5
    JAVA 读取写入文件
    融云「百幄」之数字人,升级交互体验的「新同事」
    【uni-app】总结uni-app订单支付和打包发布
    Docker-07:Docker网络管理
    DockerFile的使用
  • 原文地址:https://blog.csdn.net/weixin_58252863/article/details/138923241