// ============================================================================ // 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(config.width), static_cast(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(app.getConfig().width); float screenHeight = static_cast(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.get(); pipes->setVisible(false); addChild(pipes); // 添加小鸟(在屏幕中间偏左位置) auto bird = extra2d::makePtr(); bird->setPosition( extra2d::Vec2(screenWidth / 2.0f - 50.0f, screenHeight / 2.0f)); bird_ = bird.get(); addChild(bird); // 添加地面 auto ground = extra2d::makePtr(); ground_ = ground.get(); addChild(ground); // 添加得分(屏幕顶部中央) auto scoreNumber = extra2d::makePtr(); 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(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(score_); addChild(gameOverLayer); } } // namespace flappybird