2026-02-12 21:50:21 +08:00
|
|
|
|
// ============================================================================
|
|
|
|
|
|
// Bird.cpp - 小鸟类实现
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
#include "Bird.h"
|
|
|
|
|
|
#include "ResLoader.h"
|
|
|
|
|
|
|
|
|
|
|
|
namespace flappybird {
|
|
|
|
|
|
|
|
|
|
|
|
Bird::Bird() {
|
|
|
|
|
|
setStatus(Status::Idle);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 21:22:35 +08:00
|
|
|
|
Bird::~Bird() = default;
|
|
|
|
|
|
|
2026-02-12 21:50:21 +08:00
|
|
|
|
void Bird::onEnter() {
|
|
|
|
|
|
Node::onEnter();
|
2026-02-25 21:22:35 +08:00
|
|
|
|
if (!sprite_) {
|
2026-02-12 21:50:21 +08:00
|
|
|
|
initAnimations();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Bird::initAnimations() {
|
|
|
|
|
|
// 随机选择小鸟颜色(0-2)
|
|
|
|
|
|
int colorMode = extra2d::randomInt(0, 2);
|
|
|
|
|
|
std::string prefix = "bird" + std::to_string(colorMode) + "_";
|
|
|
|
|
|
|
2026-02-25 21:22:35 +08:00
|
|
|
|
// 加载动画帧序列: 0 -> 1 -> 2 -> 1
|
2026-02-12 21:50:21 +08:00
|
|
|
|
int frameSequence[] = {0, 1, 2, 1};
|
|
|
|
|
|
for (int frameIndex : frameSequence) {
|
|
|
|
|
|
auto frameSprite = ResLoader::getKeyFrame(prefix + std::to_string(frameIndex));
|
|
|
|
|
|
if (frameSprite) {
|
2026-02-25 21:22:35 +08:00
|
|
|
|
frames_.push_back(frameSprite);
|
2026-02-12 21:50:21 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
E2D_LOG_WARN("无法加载动画帧: {}{}", prefix, frameIndex);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 21:22:35 +08:00
|
|
|
|
// 创建精灵
|
|
|
|
|
|
if (!frames_.empty()) {
|
|
|
|
|
|
sprite_ = extra2d::Sprite::create();
|
|
|
|
|
|
setCurrentFrame(0);
|
|
|
|
|
|
addChild(sprite_);
|
|
|
|
|
|
E2D_LOG_INFO("小鸟动画创建成功: 颜色={}, 帧数={}", colorMode, frames_.size());
|
2026-02-12 21:50:21 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
E2D_LOG_ERROR("小鸟动画创建失败: 没有找到任何动画帧");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-25 21:22:35 +08:00
|
|
|
|
void Bird::setCurrentFrame(int frameIndex) {
|
|
|
|
|
|
if (frames_.empty() || !sprite_) return;
|
|
|
|
|
|
|
|
|
|
|
|
frameIndex = frameIndex % static_cast<int>(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<int>(frames_.size()));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-12 21:50:21 +08:00
|
|
|
|
void Bird::onUpdate(float dt) {
|
|
|
|
|
|
extra2d::Node::onUpdate(dt);
|
|
|
|
|
|
|
2026-02-25 21:22:35 +08:00
|
|
|
|
// 更新帧动画
|
|
|
|
|
|
updateFrameAnimation(dt);
|
|
|
|
|
|
|
2026-02-12 21:50:21 +08:00
|
|
|
|
// 处理闲置动画(上下浮动)
|
|
|
|
|
|
if (status_ == Status::Idle) {
|
|
|
|
|
|
idleTimer_ += dt;
|
|
|
|
|
|
idleOffset_ = std::sin(idleTimer_ * 5.0f) * 4.0f;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Bird::onRender(extra2d::RenderBackend& renderer) {
|
2026-02-25 21:22:35 +08:00
|
|
|
|
// 精灵会自动渲染,这里只需要处理旋转和偏移
|
|
|
|
|
|
if (sprite_) {
|
|
|
|
|
|
sprite_->setRotation(rotation_);
|
2026-02-12 21:50:21 +08:00
|
|
|
|
|
|
|
|
|
|
// 应用闲置偏移
|
|
|
|
|
|
if (status_ == Status::Idle) {
|
2026-02-25 21:22:35 +08:00
|
|
|
|
sprite_->setPosition(extra2d::Vec2(0.0f, idleOffset_));
|
2026-02-12 21:50:21 +08:00
|
|
|
|
} else {
|
2026-02-25 21:22:35 +08:00
|
|
|
|
sprite_->setPosition(extra2d::Vec2(0.0f, 0.0f));
|
2026-02-12 21:50:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 调用父类的 onRender 来渲染子节点
|
|
|
|
|
|
Node::onRender(renderer);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Bird::fall(float dt) {
|
|
|
|
|
|
if (!living_) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 更新垂直位置
|
2026-02-26 00:38:31 +08:00
|
|
|
|
extra2d::Vec2 position = pos();
|
|
|
|
|
|
position.y += speed_ * dt;
|
|
|
|
|
|
setPosition(position);
|
2026-02-12 21:50:21 +08:00
|
|
|
|
|
|
|
|
|
|
// 应用重力
|
|
|
|
|
|
speed_ += gravity * dt;
|
|
|
|
|
|
|
|
|
|
|
|
// 限制顶部边界
|
2026-02-26 00:38:31 +08:00
|
|
|
|
if (position.y < 0) {
|
|
|
|
|
|
position.y = 0;
|
|
|
|
|
|
setPosition(position);
|
2026-02-12 21:50:21 +08:00
|
|
|
|
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:
|
|
|
|
|
|
// 停止所有动画
|
2026-02-25 21:22:35 +08:00
|
|
|
|
frameTimer_ = 0.0f;
|
2026-02-12 21:50:21 +08:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case Status::Idle:
|
|
|
|
|
|
// 开始闲置动画
|
2026-02-25 21:22:35 +08:00
|
|
|
|
frameInterval_ = 0.1f; // 正常速度
|
2026-02-12 21:50:21 +08:00
|
|
|
|
idleTimer_ = 0.0f;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case Status::StartToFly:
|
|
|
|
|
|
// 停止闲置动画,加速翅膀扇动
|
|
|
|
|
|
idleOffset_ = 0.0f;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case Status::Fly:
|
|
|
|
|
|
// 飞行状态
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
extra2d::Rect Bird::getBoundingBox() const {
|
2026-02-26 00:38:31 +08:00
|
|
|
|
extra2d::Vec2 position = pos();
|
2026-02-12 21:50:21 +08:00
|
|
|
|
// 小鸟碰撞框大小约为 24x24
|
|
|
|
|
|
float halfSize = 12.0f;
|
|
|
|
|
|
return extra2d::Rect(
|
2026-02-26 00:38:31 +08:00
|
|
|
|
position.x - halfSize,
|
|
|
|
|
|
position.y - halfSize,
|
2026-02-12 21:50:21 +08:00
|
|
|
|
halfSize * 2.0f,
|
|
|
|
|
|
halfSize * 2.0f
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace flappybird
|