PVZ植物大战僵尸项目精讲-2阳光类和动画类

2.2zanim类

继承zobject,所以重写了act,不过不需要血量,有生存情况alive

动画有一个属性frame控制动画帧数

在这个头文件里面同时我们还实现了豌豆击中动画,火动画,僵尸死掉动画,烧死动画,土豆爆炸动画,僵尸头掉下动画,樱桃炸弹爆炸动画,撑杆跳僵尸死掉动画,新闻僵尸死掉动画,新闻僵尸头掉下动画,这些动画全部继承自zanim,每一个里面有一个Qmovie类型的指针,需要析构,这个指针实现

在每一个子类的act里面实现按照各自动画距离消失的帧数(设置this->alive

frame说明它几帧后消失

构造函数:

把QMovie绑定到QLabel(zAnim继承自QLabel)开启动画

面试题:==这个帧数是怎么确定的?==为什么要有这个帧

防止重复播放动画,动画结束就设置alive为false,在每个scene里面会,然后每20ms发送一次超时信号调用onTimer函数,其中进行act和对于已经不alive的对象的清除

动画类型frame 值持续时间
zPeaHit(豌豆命中)2很短,瞬间消失
zZombieDie(僵尸死亡)50僵尸倒地的过程
zBoom(爆炸)40炸弹爆炸特效
zBurnDie(燃烧死亡)85僵尸被烧死的时间

这些动画通常是 短暂的特效,比如 子弹命中、爆炸、燃烧、僵尸死亡,不会一直存在,所以需要 一个方式控制动画的生命周期。这里的 frame 就是用来控制动画存在时间的

在这里插入图片描述

我在PIL 查看帧数,发现是100ms一帧,所以我这个20ms一次act应该把frame乘以5

frame 作用
  1. 控制动画存活时间,防止动画无限播放。
  2. 确保游戏不会创建太多无用动画,影响性能
  3. 短动画快速消失,长动画缓慢播放后删除

2.3zbonus类

设计奖励类,有zSun和zSunFall两个子类

前者有level,speed,accelerate,x_speed(initialize 0)

后者有level和speed,两者都有一个鼠标pressevent。两个sun类都有一个QMovie指针指向一个Sun.gif动态图

他们的act实现了什么

在act中,和zanim一样每次减去帧数,如果帧数小于0就标记死亡alive=false,如果this->y()<=this->level即没有到达目标终点,则如果是sun修改通过accelerate每一帧修改speed,然后用move函数改变sun对象的x轴y轴位置为

if (this->y() <= this->level)
{
    this->speed += this->accelerate;
    this->move(this->x() + this->x_speed, this->y() + this->speed);
}
点击阳光鼠标事件

点击后alive标记成false,增加25点scene对象的sunPoint,播放获得阳光的音效

这个scene属性是在继承的zObject里面的

其他注意点

他们也有一个frame,这个frame的作用是什么呢?

初始化750帧,15秒后消失动画

析构函数要记得释放QMovie成员对象anim

zbonus中用到的数学原理

zSun和zSunFall分别代表向日葵产生的和掉下来的阳光,后者匀速,前者因为要先上升后下降,我们设置了一个加速度

看看这有多巧妙!

zSun::zSun(QWidget* parent) : zBonus(parent)
{
    this->setGeometry(260, 80, 80, 80);  // ✅ 初始位置(固定)
    this->setMovie(anim);  // ✅ 绑定 GIF 动画
    anim->start();  // ✅ 播放动画
    this->show();  // ✅ 显示阳光

    this->speed = -(qrand() % 5 + 7);  // ✅ 速度为负数,先向上移动
    this->accelerate = 2;  // ✅ 加速度(影响下降)
    this->level = 200;  // ✅ 控制最终下落的 Y 轴高度
    this->x_speed = qrand() % 5 - 2;  // ✅ 随机 X 方向移动速度
    this->frame = 750;  // ✅ 控制阳光生命周期(750 帧 ≈ 25 秒)
}

*每一个向日葵产生的阳光相对位置不一样怎么办?

这里构造函数虽然初始化了位置,但是实际上在向日葵植物类的act函数中我们会按照向日葵的位置调整阳光的位置和阳光最高能达到的下降终点,包括这个level也是相对的

void zSunFlower::act()
{
    if (this->TimerSun <= 0)  // ✅ 当冷却时间归零,生成阳光
    {
        this->TimerSun = this->TimerSun_max;  // ✅ 重置计时器(等待下次生成)
        
        zSun* sun = new zSun(scene);  // ✅ 生成阳光
        sun->setGeometry(this->x(), this->y() + 15 - (qrand() % 5), 80, 80);  // ✅ 让阳光在向日葵附近出现
        sun->level = this->y() + 40;  // ✅ 设定阳光的下降终点
        
        scene->Bonuses.append(sun);  // ✅ 把阳光添加到游戏场景
    }
    else
    {
        this->TimerSun--;  // ✅ 计时器递减
    }
}

随机性的引入

向日葵产生的阳光x轴速度是随机在[-2,2]通过qrand实现,然后初始向上移动速度也是一个随机负数(向下为正方向)。

下落的阳光随机性通过什么实现

这个初始位置的随机性,以及最终这个level的随机性得到一个随机的终点

zSunFall::zSunFall(QWidget* parent) : zBonus(parent)
{
    this->setGeometry(qrand() % 600 + 320, 0, 80, 80);  // ✅ 随机 X 轴生成阳光
    this->setMovie(anim);
    anim->start();
    this->show();
    this->speed = 2;  // ✅ 下落速度
    this->level = qrand() % 400 + 100;  // ✅ 随机终点高度
    this->frame = 750;  // ✅ 750 帧后消失
}

匀速下降

this->move(this->x(), this->y() + this->speed);  // ✅ 让阳光以 `speed` 匀速下降

加微信获取全部源码

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值