Bootstrap

【C语言课设】经典植物大战僵尸丨完整开发教程+笔记+源码

前言

植物对抗僵尸是一款经典小游戏,初学者可以从零开始开发自己的版本,这将是一次令人期待的经历!它可以作为课程设计的一部分,也可以用来快速提升项目开发技能。

视频教程+素材资源

点击进入B站:(视频教程+素材资源
说明:项目演示视频,在上面链接里的第一个视频,下面只展示项目截图..

项目准备

  • 安装Visual Studio的任意版本(推荐VS2019社区版、VS2022社区版)

  • 领取项目素材(回复“植物大战僵尸”,即可领取)

创建项目

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

导入素材 :

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

实现游戏初始场景

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

#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 >= sunshineTabl
;