C语言手写-植物大战僵尸

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

项目准备
安装Visual Studio的任意版本(推荐VS2019社区版、VS2022社区版)
安装easyx图形库(官网下载地址)
领取项目素材(回复“植物大战僵尸”,即可领取)
创建项目
使用VS创建项目,使用空项目模板:

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



实现游戏初始场景
代码如下(需要逐行代码视频讲解,可回复“代码讲解“)。






添加启动菜单
创建菜单界面,代码如下:

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

生产阳光
熟悉植物大战僵尸的同学都知道,种植植物才能消灭僵尸,但是种植植物,需要先具备一定数量的阳光值。初始的阳光值很小。有两种方式生成阳光:第一种,随机降落少量的阳光;第二种,通过种植向日葵,让向日葵自动生产阳光。我们先实现第一种方式。
定义一个结构体,来表示阳光球。因为阳光是以旋转的方式运动的,所以定义一个图片帧数组,通过循环播放图片帧来实现旋转效果。

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

创建阳光,代码如下。

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

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

在updateWindow函数中,渲染阳光。

收集阳光
当“阳光球”出现的时候,用户点击阳光球,就可以“收集”这个阳光,当前总的阳光值就会增加25点。在原版的植物大战僵尸游戏中,阳光球被收集后,会慢慢移动到顶部的“工具栏”的左侧。这个阳光球的“移动过程”,我们后续再实现。
定义一个全局变量,表示当前总的阳光值。
int sunshine;
在初始化gameInit中,设置一个初始值。
sunshine = 150;
创建收集阳光的函数,如下:

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

显示当前总的阳光值
在gameInit初始化中,设置字体。

在updateWindow中绘制阳光值。

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

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

创建僵尸,代码如下:

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

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

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

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

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

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

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

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

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

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

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

此时已经能够实现阳光的飞跃了,但是飞跃动作太慢了,后期我们再优化。
发射豌豆
僵尸靠近时,已经种植的植物豌豆就会自动发射“子弹”,我们先为子弹定义数据类型,如下:

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

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

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

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

更新子弹的位置,如下:

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

在updateWindow中绘制子弹,如下:

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

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

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

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

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

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

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

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

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

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

僵尸死亡
僵尸被豌豆子弹击中后,会“掉血”,血量掉光了,就直接KO了,同时变成一堆“黑沙”。
给僵尸结构体添加dead成员,表示是否已经死亡,另外添加一个图片帧数组,用来表示变成成黑沙的过程。

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

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

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

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

后续的内容详情看主页置顶视频