当前位置:   article > 正文

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

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

前言:

本游戏使用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<x + w
  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<easyx.h>
  4. #include<stdio.h>
  5. #include<time.h>
  6. #include<math.h>
  7. #include"tools.h"
  8. #include<mmsystem.h>
  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 <cmath>
  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 <cmath>
  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.cpp文件 

  1. #pragma once
  2. #include <graphics.h>
  3. void putimagePNG(int picture_x, int picture_y, IMAGE* picture);
  4. int getDelay();
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/587248
推荐阅读
相关标签
  

闽ICP备14008679号