用慧编程做植物大战僵尸详细步骤(java植物大战僵尸项目源码)

  • 植物大战僵尸,是一个非常经典的小游戏,初学者从零开始,开发一个自己的植物大战僵尸,还是非常值得期待的!可以作为自己的课设,也可以用来快速提升自己的项目开发能力。

    项目效果(详细视频教程>「链接」)

    说明:因为完整动图提交后提示违规,所以这里仅截图示意。如果需要演示视频,在评论中回复即可。

    用慧编程做植物大战僵尸详细步骤(java植物大战僵尸项目源码)

    项目准备

  • 安装Visual Studio的任意版本(推荐VS2019社区版、VS2022社区版)
  • 安装easyx图形库
  • 领取项目素材(回复“植物大战僵尸”,即可领取)

    创建项目

    使用VS创建项目,使用空项目模板:

    用慧编程做植物大战僵尸详细步骤(java植物大战僵尸项目源码)

    导入素材:在项目目录下,创建res文件夹,把解压后的素材拷贝到res目录下。

    用慧编程做植物大战僵尸详细步骤(java植物大战僵尸项目源码)

    用慧编程做植物大战僵尸详细步骤(java植物大战僵尸项目源码)

    用慧编程做植物大战僵尸详细步骤(java植物大战僵尸项目源码)

    实现游戏初始场景

    代码如下(需要逐行代码视频讲解,可回复“代码讲解“)。

    #include <stdio.h>#include <graphics.h>#include "tools.h"#include <mmsystem.h>#pragma comment(lib, "winmm.lib") #define WIN_WIDTH    900#define WIN_HEIGHT    600 enum { WAN_DOU, XIANG_RI_KUI, ZHI_WU_COUT };IMAGE imgBg;IMAGE imgBar;IMAGE imgCards[ZHI_WU_COUT];IMAGE* imgZhiWu[ZHI_WU_COUT][20];int curZhiWu;int curX, curY; //当前选中植物在移动过程中的坐标 struct zhiWu {    int type;   // >=1  0:没有植物    int frameIndex;};struct zhiWu  map[3][9];int sunshine;int sunshineTable[ZHI_WU_COUT] = { 100, 50 }; void gameInit() {    loadimage(&imgBg, "res/bg.jpg");    loadimage(&imgBar, "res/bar.png");    sunshine = 150;    curZhiWu = 0;    memset(imgZhiWu, 0, sizeof(imgZhiWu));    memset(map, 0, sizeof(map));     char name[64];    for (int i = 0; i < ZHI_WU_COUT; i++) {        sprintf_s(name, sizeof(name), "res/Cards/card_%d.png", i + 1);        loadimage(&imgCards[i], name);         for (int j = 0; j < 20; j++) {            sprintf_s(name, sizeof(name), "res/zhiwu/%d/%d.png", i, j + 1);            imgZhiWu[i][j] = new IMAGE;            loadimage(imgZhiWu[i][j], name);            if (imgZhiWu[i][j]->getwidth() == 0) {                delete imgZhiWu[i][j];                imgZhiWu[i][j] = NULL;            }        }    }     initgraph(WIN_WIDTH, WIN_HEIGHT, 1);    // 设置字体:    LOGFONT f;    gettextstyle(&f);                     // 获取当前字体设置    f.lfHeight = 30;                      // 设置字体高度为 48    f.lfWidth = 15;    strcpy(f.lfFaceName, "Segoe UI Black");    f.lfQuality = ANTIALIASED_QUALITY;    // 设置输出效果为抗锯齿      settextstyle(&f);                     // 设置字体样式    setbkmode(TRANSPARENT);    setcolor(BLACK);     mciSendString("play res/bg.mp3 repeat", 0, 0, 0);} void updateWindow() {    BeginBatchDraw();     putimage(0, 0, &imgBg);    putimagePNG(250, 0, &imgBar);     for (int i = 0; i < ZHI_WU_COUT; i++) {        int x = 338 + i * 64;        int y = 6;        putimage(x, y, &imgCards[i]);    }     if (curZhiWu > 0) {  // 绘制正在移动的植物        IMAGE* img = imgZhiWu[curZhiWu - 1][0];        putimagePNG(curX - img->getwidth() * 0.5, curY - img->getheight() * 0.5, img);    }     for (int i = 0; i < 3; i++) {        for (int j = 0; j < 9; j++) {            if (map[i][j].type > 0) {                int x = 260 + j * 81.6;    // (msg.x - 260) / 81.6;                int y = 180 + i * 103.6 + 14; // (msg.y - 210) / 103.6;                int zhiWuIndex = map[i][j].type;                int frameIndex = map[i][j].frameIndex;                putimagePNG(x, y, imgZhiWu[zhiWuIndex - 1][frameIndex]);            }        }    }     char scoreText[8];    sprintf_s(scoreText, sizeof(scoreText), "%d", sunshine);    outtextxy(282 - 10 + 4, 50 + 15 + 2, scoreText);    EndBatchDraw();} void userClick() {    ExMessage msg;    static int status = 0;    if (peekmessage(&msg)) {        if (msg.message == WM_LBUTTONDOWN) {            if (msg.x > 338 && msg.x < 338 + 64 * ZHI_WU_COUT && msg.y>6 && msg.y < 96) {                int index = (msg.x - 338) / 64;                printf("%d\n", index);                status = 1;                curZhiWu = index + 1; // 1, 2                 curX = msg.x;                curY = msg.y;            }        }        else if (msg.message == WM_MOUSEMOVE && status == 1) {            curX = msg.x;            curY = msg.y;        }        else if (msg.message == WM_LBUTTONUP && status == 1) {            printf("up\n");            if (msg.x > 260 && msg.y < 995 && msg.y > 180 && msg.y < 491) {                if (sunshine >= sunshineTable[curZhiWu - 1]) {                    sunshine -= sunshineTable[curZhiWu - 1];                    int col = (msg.x - 260) / 81.6;                    int row = (msg.y - 210) / 103.6;                    printf("[%d,%d]\n", row, col);                    if (map[row][col].type == 0) {                        map[row][col].type = curZhiWu;                        map[row][col].frameIndex = 0;                    }                }            }            status = 0;            curZhiWu = 0;        }    }} void updateGame() {    for (int i = 0; i < 3; i++) {        for (int j = 0; j < 9; j++) {            if (map[i][j].type > 0) {                map[i][j].frameIndex++;                if (imgZhiWu[map[i][j].type - 1][map[i][j].frameIndex] == NULL) {                    map[i][j].frameIndex = 0;                }            }        }    }} int main(void) {    gameInit();     int timer = 0;    bool flag = true;    while (1) {        userClick();        timer += getDelay();        if (timer > 20) {            timer = 0;            flag = true;        }        if (flag) {            flag = false;            updateWindow();            updateGame();        }    }     return 0;}

    添加启动菜单

    创建菜单界面,代码如下:

    void startUI() {    IMAGE imgBg, imgMenu1, imgMenu2;    loadimage(&imgBg, "res/menu.png");    loadimage(&imgMenu1, "res/menu1.png");    loadimage(&imgMenu2, "res/menu2.png");    int flag = 0;    while (1) {        BeginBatchDraw();        putimage(0, 0, &imgBg);        putimagePNG(474, 75, flag ? &imgMenu2 : &imgMenu1);         ExMessage msg;        if (peekmessage(&msg)) {            if (msg.message == WM_LBUTTONDOWN &&                msg.x > 474 && msg.x < 474 + 300 && msg.y > 75 && msg.y < 75 + 140) {                flag = 1;                EndBatchDraw();            }            else if (msg.message == WM_LBUTTONUP && flag) {                return;            }        }        EndBatchDraw();    }}

    在main函数中调用菜单,代码如下:

    int main(void) {    gameInit();    startUI();    int timer = 0;    bool flag = true;    while (1) {        userClick();        timer += getDelay();        if (timer > 20) {            timer = 0;            flag = true;        }        if (flag) {            flag = false;            updateWindow();            updateGame();        }    }     return 0;}

    生产阳光

    熟悉植物大战僵尸的同学都知道,种植植物才能消灭僵尸,但是种植植物,需要先具备一定数量的阳光值。初始的阳光值很小。有两种方式生成阳光:第一种,随机降落少量的阳光;第二种,通过种植向日葵,让向日葵自动生产阳光。我们先实现第一种方式。

    定义一个结构体,来表示阳光球。因为阳光是以旋转的方式运动的,所以定义一个图片帧数组,通过循环播放图片帧来实现旋转效果。

    IMAGE imgSunshineBall[29]; struct sunshineBall {     int x, y;    int frameIndex;    bool used;    int destY;    int timer = 0;};struct sunshineBall balls[10];

    在gameInit函数中,初始化阳光帧数组。

        memset(balls, 0, sizeof(balls));    for (int i = 0; i < 29; i++) {        sprintf_s(name, sizeof(name), "res/sunshine/%d.png", i + 1);        loadimage(&imgSunshineBall[i], name);    }

    创建阳光,代码如下。

    void createSunshine() {    int ballMax = sizeof(balls) / sizeof(balls[0]);     static int frameCount = 0;    static int fre = 400;    frameCount++;    if (frameCount >= fre) {        fre = 200 + rand() % 200;          frameCount = 0;        int i;        for (i = 0; i < ballMax && balls[i].used; i++);        if (i >= ballMax) return;         balls[i].used = true;        balls[i].frameIndex = 0;        balls[i].x = 260 + rand() % (905 - 260);        balls[i].y = 60;        balls[i].destY = 180 + (rand() % 4) * 90 + 20;        balls[i].timer = 0;    }}

    修改阳光的位置和帧序号,代码如下。

    void updateSunshine() {    int ballMax = sizeof(balls) / sizeof(balls[0]);     for (int i = 0; i < ballMax; i++) {        if (balls[i].used) {            balls[i].frameIndex = (balls[i].frameIndex + 1) % 29;            if(balls[i].timer == 0) balls[i].y += 2;            if (balls[i].y >= balls[i].destY) {                balls[i].timer++;                if (balls[i].timer > 100) balls[i].used = false;            }        }    }}

    在updateGame函数中调用以上两个函数 ,以创建阳光并更新阳光的状态。

    createSunshine();updateSunshine();

    在updateWindow函数中,渲染阳光。

    for (int i = 0; i < 10; i++) {    if (balls[i].used) {        putimagePNG(balls[i].x, balls[i].y, &imgSunshineBall[balls[i].frameIndex]);    }}

    收集阳光

    当“阳光球”出现的时候,用户点击阳光球,就可以“收集”这个阳光,当前总的阳光值就会增加25点。在原版的植物大战僵尸游戏中,阳光球被收集后,会慢慢移动到顶部的“工具栏”的左侧。这个阳光球的“移动过程”,我们后续再实现。

    定义一个全局变量,表示当前总的阳光值。

    int sunshine;

    在初始化gameInit中,设置一个初始值。

    sunshine = 150;

    创建收集阳光的函数,如下:

    void collectSunshine(ExMessage* msg) {    int count = sizeof(balls) / sizeof(balls[0]);    int w = imgSunshineBall[0].getwidth();    int h = imgSunshineBall[0].getheight();    for (int i = 0; i < count; i++) {        if (balls[i].used) {            int x = balls[i].x;            int y = balls[i].y;            if (msg->x > x && msg->x < x + w && msg->y > y && msg->y < y + h) {                balls[i].used = false;                sunshine += 25;                mciSendString("play res/sunshine.mp3", 0, 0, 0);            }        }    }}

    在用户点击处理中,调用收集阳光的函数。

    #include <mmsystem.h>#pragma comment(lib, "winmm.lib") void userClick() {    ExMessage msg;    static int status = 0;    if (peekmessage(&msg)) {        if (msg.message == WM_LBUTTONDOWN) {            if (msg.x > 338 && msg.x < 338 + 65 * ZHI_WU_COUNT && msg.y < 96) {                int index = (msg.x - 338) / 65;                status = 1;                curZhiWu = index + 1;            } else {                collectSunshine(&msg);            }        }        // ......     }}

    显示当前总的阳光值

    在gameInit初始化中,设置字体。

    LOGFONT f;gettextstyle(&f);                     // 获取当前字体设置f.lfHeight = 30;                      // 设置字体高度为 48f.lfWidth = 15;strcpy(f.lfFaceName, "Segoe UI Black");f.lfQuality = ANTIALIASED_QUALITY;    // 设置输出效果为抗锯齿  settextstyle(&f);                     // 设置字体样式setbkmode(TRANSPARENT);setcolor(BLACK);

    在updateWindow中绘制阳光值。

    char scoreText[8];sprintf_s(scoreText, sizeof(scoreText), "%d", sunshine);outtextxy(276, 67, scoreText);

    创建僵尸

    创建僵尸的数据模型。这里一共创建了10个僵尸,这10个僵尸全部被消灭后,这个关卡就胜利了。

     struct zm {    int x, y;     int frameIndex;    bool used;    int speed;};struct zm zms[10];IMAGE imgZM[22];

    僵尸数组,以及僵尸序列帧图片数组,在gameInit函数中进行初始化,如下。(注意:把僵尸的素材图片保存到src/zm目录下。)

    memset(zms, 0, sizeof(zms));srand(time(NULL)); for (int i = 0; i < 22; i++) {    sprintf_s(name, sizeof(name), "res/zm/%d.png", i + 1);    loadimage(&imgZM[i], name);}

    创建僵尸,代码如下:

    void createZM() {    static int zmFre = 500;    static int count = 0;    count++;    if (count > zmFre) {        zmFre = rand() % 200 + 300;        count = 0;         int i;        int zmMax = sizeof(zms) / sizeof(zms[0]);        for (i = 0; i < zmMax && zms[i].used; i++);        if (i < zmMax) {            zms[i].used = true;            zms[i].x = WIN_WIDTH;            zms[i].y = 180 + (1 + rand() % 3) * 100 - 8;            zms[i].speed = 1;        }    }}

    更新僵尸的数据(僵尸的图片帧序号、僵尸的位置),代码如下:

    void updateZM() {    int zmMax = sizeof(zms) / sizeof(zms[0]);     static int count1 = 0;    count1++;    if (count1 > 2) {        count1 = 0;        for (int i = 0; i < zmMax; i++) {            if (zms[i].used) {                zms[i].x -= zms[i].speed;                if (zms->x < 236 - 66) {                    printf("GAME OVER!\n");                    MessageBox(NULL, "over", "over", 0); //TO DO                    break;                }            }        }    }        static int count2 = 0;    count2++;    if (count2 > 4) {        count2 = 0;        for (int i = 0; i < zmMax; i++) {            if (zms[i].used) {                zms[i].frameIndex = (zms[i].frameIndex + 1) % 22;            }        }    }}

    在updateGame函数中,创建僵尸并更新僵尸数据,如下:

    createZM();updateZM();

    创建绘制僵尸的接口, 如下:

    void drawZM() {    int zmCount = sizeof(zms) / sizeof(zms[0]);    for (int i = 0; i < zmCount; i++) {        if (zms[i].used) {            IMAGE* img = &imgZM[zms[i].frameIndex];            int x = zms[i].x;            int y = zms[i].y - img->getheight();            putimagePNG(x, y, img);        }    }}

    在updateWindow函数中,绘制僵尸,如下:

    drawZM();

    实现阳光球的飞跃

    现在的实现效果是,阳光被点击后,阳光球直接消失了!而原版的植物大战僵尸中,阳光被点击后,阳光会自动飞向左上角的位置,飞到终点后,阳光值才增加25点。我们的实现方式是,阳光球每次飞跃4个点,直到飞到终点,

    如下图:

    用慧编程做植物大战僵尸详细步骤(java植物大战僵尸项目源码)

    给阳光的结构体添加两个成员,表示飞跃过程中的偏移量:

    struct sunshineBall {     int x, y;    int frameIndex;    bool used;    int destY;    int timer;     //添加以下两个成员    float xOff;    float yOff;};

    在阳光被创建时,把变异量设置为0, 如下:

    void createSunshine() {    int ballMax = sizeof(balls) / sizeof(balls[0]);    static int frameCount = 0;    static int fre = 200;    frameCount++;    if (frameCount >= fre) {        //...略        balls[i].xOff = 0;        balls[i].yOff = 0;    } }

    阳光被点击后,马上修改阳光球的xoff和yoff:

    #include <math.h> void collectSunshine(ExMessage* msg) {    int count = sizeof(balls) / sizeof(balls[0]);    int w = imgSunshineBall[0].getwidth();    int h = imgSunshineBall[0].getheight();    for (int i = 0; i < count; i++) {        if (balls[i].used) {            int x = balls[i].x;            int y = balls[i].y;            if (msg->x > x && msg->x < x + w &&                msg->y >y && msg->y < y + h) {                balls[i].used = false;                sunshine += 25;                mciSendString("play res/sunshine.mp3", 0, 0, 0);                                // 设置初始偏移量                float destX = 262;                float destY = 0;                float angle = atan((y - destY) / (x - destX));                balls[i].xOff = 4 * cos(angle);                balls[i].yOff = 4 * sin(angle);            }        }    }}

    在阳光飞跃过程中更新阳光的位置,如下:(注意是在飞跃过程中,不断计算偏移量,效果更好。)

    void updateSunshine() {    int ballMax = sizeof(balls) / sizeof(balls[0]);    for (int i = 0; i < ballMax; i++) {        if (balls[i].used) {           //略...        }        else if (balls[i].xOff) {            float destX = 263;            float destY = 0;            float angle = atan((balls[i].y - destY) / (balls[i].x - destX));            balls[i].xOff = 4 * cos(angle);            balls[i].yOff = 4 * sin(angle);             balls[i].x -= balls[i].xOff;            balls[i].y -= balls[i].yOff;            if (balls[i].y < 0 || balls[i].x < 262) {                balls[i].xOff = 0;                balls[i].yOff = 0;                sunshine += 25;             }        }    }}

    删除原来被点击后,立即更新阳光值的代码。

    //sunshine += 25;

    修改渲染阳光的判断条件,如下:

    for (int i = 0; i < ballMax; i++) {    if (balls[i].used             || balls[i].xOff) { //添加这个条件        IMAGE* img = &imgSunshineBall[balls[i].frameIndex];        putimagePNG(balls[i].x, balls[i].y, img);    }}

    此时已经能够实现阳光的飞跃了,但是飞跃动作太慢了,后期我们再优化。

    发射豌豆

    僵尸靠近时,已经种植的植物豌豆就会自动发射“子弹”,我们先为子弹定义数据类型,如下:

    struct bullet {    int x, y;    int row;    bool used;    int speed;};struct bullet bullets[30];IMAGE imgBulletNormal;

    在gameInit函数中,初始化“豌豆子弹池”和子弹的图片,如下:

    loadimage(&imgBulletNormal, "res/bullets/bullet_normal.png");memset(bullets, 0, sizeof(bullets));

    在僵尸结构体中,添加成员row, 表示该僵尸所在的“行”,方便后续的判断。也可以不加,直接根据僵尸的y坐标来计算。

    struct zm {    int x, y;     int frameIndex;    bool used;    int speed;     int row; //0..2};

    在createZM函数中,创建僵尸的时候,设置row成员的值,如下:

    ......if (i < zmMax) {    zms[i].used = true;    zms[i].x = WIN_WIDTH;     zms[i].row = rand() % 3; // 0..2;    zms[i].y = 172 + (1 + zms[i].row) * 100;     zms[i].speed = 1;}......  

    创建shoot函数,实现豌豆发射子弹,如下:

    void shoot() {    int zmCount = sizeof(zms) / sizeof(zms[0]);    int directions[3] = { 0 };     int dangerX = WIN_WIDTH - imgZM[0].getwidth();    for (int i = 0; i < zmCount; i++) {        if (zms[i].used && zms[i].x < dangerX) {            directions[zms[i].row] = 1;        }    }     for (int i = 0; i < 3; i++) {        for (int j = 0; j < 9; j++) {            if (map[i][j].type == WAN_DOU+1 && directions[i]) {                static int count = 0;                count++;                if (count > 20) {                    count = 0;                    int k;                    int maxCount = sizeof(bullets) / sizeof(bullets[0]);                    for (k = 0; k < maxCount && bullets[k].used; k++);                    if (k < maxCount) {                        bullets[k].row = i;                        bullets[k].speed = 4;                        bullets[k].used = true;                         int zwX = 260 + j * 81.6;    // (msg.x - 260) / 81.6;                        int zwY = 180 + i * 103.6 + 14; // (msg.y - 210) / 103.6;                         bullets[k].x = zwX + imgZhiWu[map[i][j].type - 1][0]->getwidth()-10;                        bullets[k].y = zwY + 5;                    }                }            }        }    }}

    更新子弹的位置,如下:

    void updateBullets() {    int countMax = sizeof(bullets) / sizeof(bullets[0]);    for (int i = 0; i < countMax; i++) {        if (bullets[i].used) {            bullets[i].x += bullets[i].speed;            if (bullets[i].x > WIN_WIDTH) {                bullets[i].used = false;            }        }    }}

    在updateGame函数中,发射子弹并更新子弹的位置,如下:

    shoot();updateBullets();

    在updateWindow中绘制子弹,如下:

    int bulletMax = sizeof(bullets) / sizeof(bullets[0]);for (int i = 0; i < bulletMax; i++) {    if (bullets[i].used) {        putimagePNG(bullets[i].x, bullets[i].y, &imgBulletNormal);    }}

    子弹和僵尸的碰撞

    子弹碰到僵尸之后,子弹会“爆炸”,同时僵尸会“掉血”。我们先给僵尸添加血量成员。

    struct zm {     //略...    int blood;};

    并在创建僵尸的时候,把血量初始化为100,如下:

    //...zms[i].speed = 1;zms[i].blood = 100;

    子弹在碰到僵尸之后才会爆炸,并显示爆炸图片:

    用慧编程做植物大战僵尸详细步骤(java植物大战僵尸项目源码)

    所以,我们在子弹的结构体中添加两个成员,分别表示当前是否已经爆炸,以及爆炸的帧图片序号,如下:

    struct bullet {    //...    bool blast;    int frameIndex; };IMAGE imgBulletBlast[4];

    在gameInit函数中对子弹帧图片数组,进行初始化,如下:

    loadimage(&imgBulletBlast[3], "res/bullets/bullet_blast.png");for (int i = 0; i < 3; i++) {    float k = (i + 1) * 0.2;    loadimage(&imgBulletBlast[i], "res/bullets/bullet_blast.png",         imgBulletBlast[3].getwidth()*k,        imgBulletBlast[3].getheight()*k, true);}

    在发射子弹shoot函数中,对子弹的blast和帧序号frameIndex进行初始化,如下:

    bullets[k].row = i;bullets[k].speed = 4;bullets[k].used = true; bullets[k].blast = false;bullets[k].blastTime = 0;

    在更新子弹的updateBullets函数中,更新子弹爆炸的帧序号,如下:

    bullets[i].x += bullets[i].speed;if (bullets[i].x > WIN_WIDTH) {    bullets[i].used = false;} if (bullets[i].blast) {    bullets[i].blastTime++;    if (bullets[i].blastTime >= 4) {        bullets[i].used = false;    }}

    进行碰撞检测,检查子弹和僵尸是否发生碰撞,如下:

    void collisionCheck() {    int bCount = sizeof(bullets) / sizeof(bullets[0]);    int zCount = sizeof(zms) / sizeof(zms[0]);    for (int i = 0; i < bCount; i++) {        if (bullets[i].used == false || bullets[i].blast)continue;        for (int k = 0; k < zCount; k++) {            int x1 = zms[k].x + 80;            int x2 = zms[k].x + 110;            if (bullets[i].row == zms[k].row && bullets[i].x > x1 && bullets[i].x < x2) {                zms[i].blood -= 20;                bullets[i].blast = true;                bullets[i].speed = 0;            }        }            }}

    在updateGame函数中,调用碰撞检测函数,如下:

    collisionCheck();

    渲染子弹的爆炸效果,如下:

    int bulletMax = sizeof(bullets) / sizeof(bullets[0]);for (int i = 0; i < bulletMax; i++) {    if (bullets[i].used) {        if (bullets[i].blast) {            IMAGE* img = &imgBulletBlast[bullets[i].blastTime];            int x = bullets[i].x + 12 - img->getwidth() / 2;            int y = bullets[i].y + 12 - img->getheight() / 2;            putimagePNG(x, y, img);             /*bullets[i].used = false;*/        }        else {            putimagePNG(bullets[i].x, bullets[i].y, &imgBulletNormal);        }            }}

    僵尸死亡

    僵尸被豌豆子弹击中后,会“掉血”,血量掉光了,就直接KO了,同时变成一堆“黑沙”。

    给僵尸结构体添加dead成员,表示是否已经死亡,另外添加一个图片帧数组,用来表示变成成黑沙的过程。

    struct zm {    ......    bool dead;};IMAGE imgZmDead[20];

    在gameInit中对这个图片帧数组进行初始化。

    for (int i = 0; i < 20; i++) {    sprintf_s(name, sizeof(name), "res/zm_dead/%d.png", i + 1);    loadimage(&imgZmDead[i], name);}

    在碰撞检测中对僵尸的血量做检测,如果血量降到0,就设置为死亡状态。如下:

    void collisionCheck() {    int bCount = sizeof(bullets) / sizeof(bullets[0]);    int zCount = sizeof(zms) / sizeof(zms[0]);    for (int i = 0; i < bCount; i++) {        if (bullets[i].used == false || bullets[i].blast)continue;        for (int k = 0; k < zCount; k++) {            int x1 = zms[k].x + 80;            int x2 = zms[k].x + 110;            if (zms[k].dead==false &&  //添加这个条件                    bullets[i].row == zms[k].row && bullets[i].x > x1 && bullets[i].x < x2) {                zms[k].blood -= 20;                bullets[i].blast = true;                bullets[i].speed = 0;                                //对血量进行检测                if (zms[k].blood <= 0) {                    zms[k].dead = true;                    zms[k].speed = 0;                    zms[k].frameIndex = 0;                }                break;            }        }    }}

    僵尸死亡后,在updateZM中,更新僵尸的状态(变成黑沙发)。如下:

    static int count2 = 0;count2++;if (count2 > 4) {    count2 = 0;    for (int i = 0; i < zmMax; i++) {        if (zms[i].used) {            //判断是否已经死亡            if (zms[i].dead) {                zms[i].frameIndex++;                if (zms[i].frameIndex >= 20) {                    zms[i].used = false;                }            }            else {                zms[i].frameIndex = (zms[i].frameIndex + 1) % 22;            }        }    }}

    绘制僵尸的黑沙状态,如下:

    void drawZM() {    int zmCount = sizeof(zms) / sizeof(zms[0]);    for (int i = 0; i < zmCount; i++) {        if (zms[i].used) {            //选择对应的渲染图片            IMAGE* img = (zms[i].dead) ? imgZmDead : imgZM;            img += zms[i].frameIndex;             int x = zms[i].x;            int y = zms[i].y - img->getheight();            putimagePNG(x, y, img);        }    }}

    C语言项目更新中……

  • 声明:版权归原创所有,转载此文是出于传递更多信息之目的。若有来源标注错误或侵犯了您的合法权益,请与本网联系,我们将及时更正、删除,谢谢。
    上上吉
    创业项目

    美国商会大战FTC

    ·经济观察报陈永伟/文自从拜登政府任命莉娜·可汗(LinaKhan)为联邦贸易委员会(Fed-eralTradeCommission,简称FTC)的主席之后,FTC就被打上了深深的“新布兰代斯主义”烙...
    创业项目

    牙科暴利是真实的吗(妇幼和牙科哪个暴利)

    今天闲来聊一聊牙科暴利这件事情。很多人提到看牙,脑子里或者嘴里总会飘出一句话,牙科太暴利了。牙科到底暴利吗,人们的这个观念到底是怎么样形成的?很多利润比牙科高的行业没太多人说暴利,为什么单单牙科就这么...
    匿名

    发表评论

    匿名网友 填写信息

    :?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: