Extra2D/examples/flappy_bird/GameScene.cpp

252 lines
6.4 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.

// ============================================================================
// 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