// ============================================================================ // Bird.cpp - 小鸟类实现 // ============================================================================ #include "Bird.h" #include "ResLoader.h" namespace flappybird { Bird::Bird() { setStatus(Status::Idle); } Bird::~Bird() = default; void Bird::onEnter() { Node::onEnter(); if (!sprite_) { initAnimations(); } } void Bird::initAnimations() { // 随机选择小鸟颜色(0-2) int colorMode = extra2d::randomInt(0, 2); std::string prefix = "bird" + std::to_string(colorMode) + "_"; // 加载动画帧序列: 0 -> 1 -> 2 -> 1 int frameSequence[] = {0, 1, 2, 1}; for (int frameIndex : frameSequence) { auto frameSprite = ResLoader::getKeyFrame(prefix + std::to_string(frameIndex)); if (frameSprite) { frames_.push_back(frameSprite); } else { E2D_LOG_WARN("无法加载动画帧: {}{}", prefix, frameIndex); } } // 创建精灵 if (!frames_.empty()) { sprite_ = extra2d::Sprite::create(); setCurrentFrame(0); addChild(sprite_); E2D_LOG_INFO("小鸟动画创建成功: 颜色={}, 帧数={}", colorMode, frames_.size()); } else { E2D_LOG_ERROR("小鸟动画创建失败: 没有找到任何动画帧"); } } void Bird::setCurrentFrame(int frameIndex) { if (frames_.empty() || !sprite_) return; frameIndex = frameIndex % static_cast(frames_.size()); currentFrame_ = frameIndex; auto &frame = frames_[frameIndex]; sprite_->setTexture(frame->getTexture()); sprite_->setTextureRect(frame->getRect()); } void Bird::updateFrameAnimation(float dt) { if (frames_.empty() || status_ == Status::Still) return; frameTimer_ += dt; float interval = frameInterval_; if (status_ == Status::StartToFly) { interval = 0.05f; // 2倍速度 } while (frameTimer_ >= interval) { frameTimer_ -= interval; setCurrentFrame((currentFrame_ + 1) % static_cast(frames_.size())); } } void Bird::onUpdate(float dt) { extra2d::Node::onUpdate(dt); // 更新帧动画 updateFrameAnimation(dt); // 处理闲置动画(上下浮动) if (status_ == Status::Idle) { idleTimer_ += dt; idleOffset_ = std::sin(idleTimer_ * 5.0f) * 4.0f; } } void Bird::onRender(extra2d::Renderer &renderer) { // 精灵会自动渲染,这里只需要处理旋转和偏移 if (sprite_) { sprite_->setRotation(rotation_); // 应用闲置偏移 if (status_ == Status::Idle) { sprite_->setPosition(extra2d::Vec2(0.0f, idleOffset_)); } else { sprite_->setPosition(extra2d::Vec2(0.0f, 0.0f)); } } // 调用父类的 onRender 来渲染子节点 Node::onRender(renderer); } void Bird::fall(float dt) { if (!living_) return; // 更新垂直位置 extra2d::Vec2 position = pos(); position.y += speed_ * dt; setPosition(position); // 应用重力 speed_ += gravity * dt; // 限制顶部边界 if (position.y < 0) { position.y = 0; setPosition(position); speed_ = 0; } // 根据速度计算旋转角度 // 上升时抬头(-15度),下降时低头(最大90度) if (speed_ < 0) { rotation_ = -15.0f; } else { rotation_ = std::min(90.0f, speed_ * 0.15f); } } void Bird::jump() { if (!living_) return; // 给小鸟向上的速度 speed_ = -jumpSpeed; // 设置状态为飞行 setStatus(Status::Fly); // 播放音效 ResLoader::playMusic(MusicType::Fly); } void Bird::die() { living_ = false; // 播放死亡音效 ResLoader::playMusic(MusicType::Hit); } void Bird::setStatus(Status status) { status_ = status; switch (status) { case Status::Still: // 停止所有动画 frameTimer_ = 0.0f; break; case Status::Idle: // 开始闲置动画 frameInterval_ = 0.1f; // 正常速度 idleTimer_ = 0.0f; break; case Status::StartToFly: // 停止闲置动画,加速翅膀扇动 idleOffset_ = 0.0f; break; case Status::Fly: // 飞行状态 break; default: break; } } extra2d::Rect Bird::boundingBox() const { extra2d::Vec2 position = pos(); // 小鸟碰撞框大小约为 24x24 float halfSize = 12.0f; return extra2d::Rect(position.x - halfSize, position.y - halfSize, halfSize * 2.0f, halfSize * 2.0f); } } // namespace flappybird