Extra2D/examples/flappy_bird/bird.cpp

196 lines
4.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ============================================================================
// 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<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()));
}
}
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::RenderBackend& 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::getBoundingBox() 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