Extra2D/examples/flappy_bird/GameScene.cpp

252 lines
6.4 KiB
C++
Raw Normal View History

// ============================================================================
// GameScene.cpp - 游戏主场景实现
// ============================================================================
#include "GameScene.h"
#include "GameOverLayer.h"
#include "ResLoader.h"
#include "input.h"
namespace flappybird {
GameScene::GameScene() {
auto &app = extra2d::Application::instance();
auto &config = app.getConfig();
setViewportSize(static_cast<float>(config.width),
static_cast<float>(config.height));
// 设置背景颜色为黑色
setBackgroundColor(extra2d::Color(0.0f, 0.0f, 0.0f, 1.0f));
}
void GameScene::onEnter() {
extra2d::Scene::onEnter();
auto &app = extra2d::Application::instance();
float screenWidth = static_cast<float>(app.getConfig().width);
float screenHeight = static_cast<float>(app.getConfig().height);
// 添加背景(使用左上角锚点,与原游戏一致)
auto bgFrame = ResLoader::getKeyFrame("bg_day");
if (bgFrame) {
auto background =
extra2d::Sprite::create(bgFrame->getTexture(), bgFrame->getRect());
background->setAnchor(extra2d::Vec2(0.0f, 0.0f));
background->setPosition(extra2d::Vec2(0.0f, 0.0f));
addChild(background);
}
// 添加水管(初始时隐藏,游戏开始后才显示)
auto pipes = extra2d::makePtr<Pipes>();
pipes_ = pipes.get();
pipes->setVisible(false);
addChild(pipes);
// 添加小鸟(在屏幕中间偏左位置)
auto bird = extra2d::makePtr<Bird>();
bird->setPosition(
extra2d::Vec2(screenWidth / 2.0f - 50.0f, screenHeight / 2.0f));
bird_ = bird.get();
addChild(bird);
// 添加地面
auto ground = extra2d::makePtr<Ground>();
ground_ = ground.get();
addChild(ground);
// 添加得分(屏幕顶部中央)
auto scoreNumber = extra2d::makePtr<Number>();
scoreNumber->setPosition(extra2d::Vec2(screenWidth / 2.0f, 50.0f));
scoreNumber->setNumber(0);
scoreNumber_ = scoreNumber.get();
addChild(scoreNumber);
// 添加 ready 图片(屏幕中央偏上)
auto readyFrame = ResLoader::getKeyFrame("text_ready");
if (readyFrame) {
readySprite_ = extra2d::Sprite::create(readyFrame->getTexture(),
readyFrame->getRect());
readySprite_->setAnchor(extra2d::Vec2(0.5f, 0.5f));
readySprite_->setPosition(
extra2d::Vec2(screenWidth / 2.0f, screenHeight / 2.0f - 70.0f));
addChild(readySprite_);
}
// 添加教程图片(屏幕中央偏下)
auto tutorialFrame = ResLoader::getKeyFrame("tutorial");
if (tutorialFrame) {
tutorialSprite_ = extra2d::Sprite::create(tutorialFrame->getTexture(),
tutorialFrame->getRect());
tutorialSprite_->setAnchor(extra2d::Vec2(0.5f, 0.5f));
tutorialSprite_->setPosition(
extra2d::Vec2(screenWidth / 2.0f, screenHeight / 2.0f + 30.0f));
addChild(tutorialSprite_);
}
// 播放转场音效
ResLoader::playMusic(MusicType::Swoosh);
// 初始化状态
started_ = false;
score_ = 0;
}
void GameScene::onUpdate(float dt) {
// 注意:这里要先调用父类的 onUpdate以确保 GameOverLayer 的动画能播放
extra2d::Scene::onUpdate(dt);
// 游戏结束后不再更新游戏逻辑(但子节点的动画继续)
if (gameOver_)
return;
if (!bird_)
return;
auto &input = extra2d::Application::instance().input();
// 检测跳跃按键A键或空格
if (input.isButtonPressed(extra2d::GamepadButton::A) ||
input.isMousePressed(extra2d::MouseButton::Left)) {
if (!started_) {
// 游戏还没开始,开始游戏
started_ = true;
startGame();
}
bird_->jump();
}
// 游戏已经开始
if (started_) {
// 模拟小鸟下落
bird_->fall(dt);
// 检查得分(小鸟飞过水管)
if (pipes_) {
Pipe *firstPipe = pipes_->getPipe(0);
if (firstPipe && !firstPipe->scored) {
float birdX = bird_->getPosition().x;
float pipeX = firstPipe->getPosition().x;
if (pipeX <= birdX) {
// 小鸟飞过了水管
score_++;
scoreNumber_->setNumber(score_);
firstPipe->scored = true;
ResLoader::playMusic(MusicType::Point);
}
}
}
// 检查碰撞
if (bird_->isLiving() && checkCollision()) {
onHit();
}
// 检查是否撞到地面(原游戏使用 123 作为地面高度)
auto &app = extra2d::Application::instance();
float screenHeight = static_cast<float>(app.getConfig().height);
if (screenHeight - bird_->getPosition().y <= 123.0f) {
// 小鸟撞到地面
bird_->setPosition(
extra2d::Vec2(bird_->getPosition().x, screenHeight - 123.0f));
bird_->setStatus(Bird::Status::Still);
onHit();
gameOver();
}
}
}
void GameScene::startGame() {
// 隐藏 ready 和 tutorial 图片
if (readySprite_) {
readySprite_->setVisible(false);
}
if (tutorialSprite_) {
tutorialSprite_->setVisible(false);
}
// 显示并开始移动水管
if (pipes_) {
pipes_->setVisible(true);
pipes_->start();
}
// 设置小鸟状态
if (bird_) {
bird_->setStatus(Bird::Status::StartToFly);
}
}
bool GameScene::checkCollision() {
if (!bird_ || !pipes_)
return false;
extra2d::Rect birdBox = bird_->getBoundingBox();
// 检查与每个水管的碰撞
for (int i = 0; i < 3; ++i) {
Pipe *pipe = pipes_->getPipe(i);
if (!pipe)
continue;
// 检查与上水管的碰撞
extra2d::Rect topBox = pipe->getTopPipeBox();
if (birdBox.intersects(topBox)) {
return true;
}
// 检查与下水管的碰撞
extra2d::Rect bottomBox = pipe->getBottomPipeBox();
if (birdBox.intersects(bottomBox)) {
return true;
}
}
return false;
}
void GameScene::onHit() {
if (!bird_->isLiving())
return;
// 小鸟死亡
bird_->die();
// 停止地面滚动
if (ground_) {
ground_->stop();
}
// 停止水管移动
if (pipes_) {
pipes_->stop();
}
// 停止小鸟动画
if (bird_) {
bird_->setStatus(Bird::Status::Still);
}
// 隐藏得分
if (scoreNumber_) {
scoreNumber_->setVisible(false);
}
// 设置游戏结束标志
gameOver_ = true;
// 延迟显示游戏结束界面
gameOver();
}
void GameScene::gameOver() {
started_ = false;
gameOver_ = true;
// 显示游戏结束层
auto gameOverLayer = extra2d::makePtr<GameOverLayer>(score_);
addChild(gameOverLayer);
}
} // namespace flappybird