- 分享
飞船
- 2025-5-17 19:21:04 @
#include <SFML/Graphics.hpp> #include <SFML/Audio.hpp> #include #include #include #include
// 道具类型枚举 enum class PowerupType { HEALTH, // 生命恢复 DAMAGE, // 子弹伤害提升 SPEED, // 飞船速度提升 RATE, // 射击速率提升 MULTISHOT // 多重射击 };
// 游戏实体基类 class Entity { public: sf::Sprite sprite; float x, y; float dx, dy; int health; bool alive;
Entity(float x, float y, float dx, float dy, int health)
: x(x), y(y), dx(dx), dy(dy), health(health), alive(true) {}
virtual void update() {
x += dx;
y += dy;
sprite.setPosition(x, y);
}
virtual void draw(sf::RenderWindow& window) {
window.draw(sprite);
}
virtual void onCollision(Entity* other) {}
};
// 玩家类 class Player : public Entity { private: sf::Texture texture; sf::Clock shootClock; float shootCooldown; int score; float baseSpeed; float currentSpeed; int bulletDamage; bool multishot; sf::Clock powerupClock; PowerupType activePowerup; bool powerupActive;
public: Player() : Entity(400, 500, 0, 0, 3), shootCooldown(0.3f), score(0), baseSpeed(5.0f), currentSpeed(baseSpeed), bulletDamage(1), multishot(false), powerupActive(false) { if (!texture.loadFromFile("player.png")) { texture.create(50, 50); sf::Image img; img.create(50, 50, sf::Color::Blue); texture.update(img); } sprite.setTexture(texture); sprite.setOrigin(texture.getSize().x / 2, texture.getSize().y / 2); }
void update() override {
// 处理输入
dx = 0; dy = 0;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) dx = -currentSpeed;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) dx = currentSpeed;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) dy = -currentSpeed;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) dy = currentSpeed;
// 边界检查
if (x + dx < 0) dx = 0;
if (x + dx > 800) dx = 0;
if (y + dy < 0) dy = 0;
if (y + dy > 600) dy = 0;
// 检查增益效果是否过期
if (powerupActive && powerupClock.getElapsedTime().asSeconds() > 10.0f) {
resetPowerups();
}
Entity::update();
}
bool canShoot() {
return shootClock.getElapsedTime().asSeconds() > shootCooldown;
}
void resetShootClock() {
shootClock.restart();
}
void addScore(int points) {
score += points;
}
int getScore() const {
return score;
}
int getBulletDamage() const {
return bulletDamage;
}
bool hasMultishot() const {
return multishot;
}
void applyPowerup(PowerupType type) {
// 如果已有增益效果,先重置
if (powerupActive) {
resetPowerups();
}
powerupActive = true;
activePowerup = type;
powerupClock.restart();
switch (type) {
case PowerupType::HEALTH:
if (health < 3) health++;
break;
case PowerupType::DAMAGE:
bulletDamage = 2;
break;
case PowerupType::SPEED:
currentSpeed = baseSpeed * 1.5f;
break;
case PowerupType::RATE:
shootCooldown = 0.15f;
break;
case PowerupType::MULTISHOT:
multishot = true;
break;
}
}
void resetPowerups() {
powerupActive = false;
bulletDamage = 1;
currentSpeed = baseSpeed;
shootCooldown = 0.3f;
multishot = false;
}
bool isPowerupActive() const {
return powerupActive;
}
PowerupType getActivePowerup() const {
return activePowerup;
}
};
// 子弹类 class Bullet : public Entity { private: sf::Texture texture; int damage;
public: Bullet(float x, float y, int damage = 1) : Entity(x, y, 0, -8, 1), damage(damage) { if (!texture.loadFromFile("bullet.png")) { texture.create(5, 15); sf::Image img; img.create(5, 15, sf::Color::Yellow); texture.update(img); } sprite.setTexture(texture); sprite.setOrigin(texture.getSize().x / 2, texture.getSize().y / 2); }
void update() override {
Entity::update();
if (y < 0) alive = false;
}
int getDamage() const {
return damage;
}
};
// 敌人类 class Enemy : public Entity { private: sf::Texture texture;
public: Enemy(float x, float y) : Entity(x, y, 0, 2, 1) { if (!texture.loadFromFile("enemy.png")) { texture.create(40, 40); sf::Image img; img.create(40, 40, sf::Color::Red); texture.update(img); } sprite.setTexture(texture); sprite.setOrigin(texture.getSize().x / 2, texture.getSize().y / 2); }
void update() override {
Entity::update();
if (y > 600) alive = false;
}
void onCollision(Entity* other) override {
if (Bullet* bullet = dynamic_cast<Bullet*>(other)) {
health -= bullet->getDamage();
if (health <= 0) alive = false;
}
}
};
// 爆炸效果类 class Explosion : public Entity { private: sf::Texture texture; sf::Clock lifeClock; float lifetime;
public: Explosion(float x, float y) : Entity(x, y, 0, 0, 1), lifetime(0.5f) { if (!texture.loadFromFile("explosion.png")) { texture.create(60, 60); sf::Image img; img.create(60, 60, sf::Color::Orange); texture.update(img); } sprite.setTexture(texture); sprite.setOrigin(texture.getSize().x / 2, texture.getSize().y / 2); }
void update() override {
if (lifeClock.getElapsedTime().asSeconds() > lifetime) {
alive = false;
}
}
};
// 道具类 class Powerup : public Entity { private: sf::Texture texture; PowerupType type;
public: Powerup(float x, float y, PowerupType type) : Entity(x, y, 0, 1.5f, 1), type(type) { if (!texture.loadFromFile(getTextureFilename())) { texture.create(30, 30); sf::Image img; img.create(30, 30, getColor()); texture.update(img); } sprite.setTexture(texture); sprite.setOrigin(texture.getSize().x / 2, texture.getSize().y / 2); }
PowerupType getType() const {
return type;
}
void update() override {
Entity::update();
if (y > 600) alive = false;
}
private: std::string getTextureFilename() const { switch (type) { case PowerupType::HEALTH: return "powerup_health.png"; case PowerupType::DAMAGE: return "powerup_damage.png"; case PowerupType::SPEED: return "powerup_speed.png"; case PowerupType::RATE: return "powerup_rate.png"; case PowerupType::MULTISHOT: return "powerup_multishot.png"; default: return ""; } }
sf::Color getColor() const {
switch (type) {
case PowerupType::HEALTH: return sf::Color::Green;
case PowerupType::DAMAGE: return sf::Color::Red;
case PowerupType::SPEED: return sf::Color::Blue;
case PowerupType::RATE: return sf::Color::Yellow;
case PowerupType::MULTISHOT: return sf::Color::Magenta;
default: return sf::Color::White;
}
}
};
// 将道具类型转换为字符串显示 std::string powerupTypeToString(PowerupType type) { switch (type) { case PowerupType::HEALTH: return "生命恢复"; case PowerupType::DAMAGE: return "伤害提升"; case PowerupType::SPEED: return "速度提升"; case PowerupType::RATE: return "射速提升"; case PowerupType::MULTISHOT: return "多重射击"; default: return ""; } }
int main() { // 初始化随机数生成器 std::srand(static_cast(std::time(nullptr)));
// 创建游戏窗口
sf::RenderWindow window(sf::VideoMode(800, 600), "太空射击游戏");
window.setFramerateLimit(60);
// 加载背景
sf::Texture backgroundTexture;
if (!backgroundTexture.loadFromFile("background.png")) {
backgroundTexture.create(800, 600);
sf::Image img;
img.create(800, 600, sf::Color(10, 10, 50));
backgroundTexture.update(img);
}
sf::Sprite background(backgroundTexture);
// 创建玩家
Player player;
// 创建实体容器
std::vector<Entity*> entities;
std::vector<Bullet*> bullets;
std::vector<Enemy*> enemies;
std::vector<Explosion*> explosions;
std::vector<Powerup*> powerups;
// 添加玩家到实体容器
entities.push_back(&player);
// 创建字体
sf::Font font;
if (!font.loadFromFile("arial.ttf")) {
// 使用默认字体
}
// 创建文本对象
sf::Text scoreText;
scoreText.setFont(font);
scoreText.setCharacterSize(24);
scoreText.setFillColor(sf::Color::White);
scoreText.setPosition(10, 10);
sf::Text healthText;
healthText.setFont(font);
healthText.setCharacterSize(24);
healthText.setFillColor(sf::Color::White);
healthText.setPosition(10, 40);
sf::Text powerupText;
powerupText.setFont(font);
powerupText.setCharacterSize(24);
powerupText.setFillColor(sf::Color::Yellow);
powerupText.setPosition(10, 70);
sf::Text gameOverText;
gameOverText.setFont(font);
gameOverText.setCharacterSize(72);
gameOverText.setFillColor(sf::Color::Red);
gameOverText.setString("游戏结束!");
gameOverText.setPosition(250, 250);
gameOverText.setStyle(sf::Text::Bold);
sf::Text restartText;
restartText.setFont(font);
restartText.setCharacterSize(24);
restartText.setFillColor(sf::Color::White);
restartText.setString("按R键重新开始");
restartText.setPosition(330, 350);
// 游戏时钟
sf::Clock clock;
sf::Clock enemySpawnClock;
sf::Clock powerupSpawnClock;
float enemySpawnRate = 1.0f;
float powerupSpawnRate = 10.0f;
// 游戏循环
bool gameOver = false;
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
// 游戏结束后按R键重新开始
if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::R && gameOver) {
gameOver = false;
player.health = 3;
player.resetPowerups();
player.score = 0;
player.x = 400;
player.y = 500;
// 清空所有实体
for (auto e : entities) {
if (e != &player) delete e;
}
entities.clear();
bullets.clear();
enemies.clear();
explosions.clear();
powerups.clear();
entities.push_back(&player);
// 重置生成速率
enemySpawnRate = 1.0f;
powerupSpawnRate = 10.0f;
}
}
if (!gameOver) {
// 更新游戏状态
float deltaTime = clock.restart().asSeconds();
// 更新玩家
player.update();
// 发射子弹
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space) && player.canShoot()) {
if (player.hasMultishot()) {
// 多重射击
Bullet* bullet1 = new Bullet(player.x - 15, player.y - 30, player.getBulletDamage());
Bullet* bullet2 = new Bullet(player.x, player.y - 30, player.getBulletDamage());
Bullet* bullet3 = new Bullet(player.x + 15, player.y - 30, player.getBulletDamage());
bullets.push_back(bullet1);
bullets.push_back(bullet2);
bullets.push_back(bullet3);
entities.push_back(bullet1);
entities.push_back(bullet2);
entities.push_back(bullet3);
} else {
// 普通射击
Bullet* bullet = new Bullet(player.x, player.y - 30, player.getBulletDamage());
bullets.push_back(bullet);
entities.push_back(bullet);
}
player.resetShootClock();
}
// 生成敌人
if (enemySpawnClock.getElapsedTime().asSeconds() > enemySpawnRate) {
float enemyX = static_cast<float>(std::rand() % 700 + 50);
Enemy* enemy = new Enemy(enemyX, -50);
enemies.push_back(enemy);
entities.push_back(enemy);
enemySpawnClock.restart();
// 随时间增加敌人生成速度
if (enemySpawnRate > 0.3f) {
enemySpawnRate -= 0.01f;
}
}
// 生成道具
if (powerupSpawnClock.getElapsedTime().asSeconds() > powerupSpawnRate) {
float powerupX = static_cast<float>(std::rand() % 700 + 50);
int type = std::rand() % 5;
PowerupType powerupType = static_cast<PowerupType>(type);
Powerup* powerup = new Powerup(powerupX, -50, powerupType);
powerups.push_back(powerup);
entities.push_back(powerup);
powerupSpawnClock.restart();
}
// 更新所有子弹
for (auto bullet : bullets) {
bullet->update();
}
// 更新所有敌人
for (auto enemy : enemies) {
enemy->update();
}
// 更新所有爆炸效果
for (auto explosion : explosions) {
explosion->update();
}
// 更新所有道具
for (auto powerup : powerups) {
powerup->update();
}
// 碰撞检测
for (auto enemy : enemies) {
// 子弹与敌人碰撞
for (auto bullet : bullets) {
if (bullet->alive && enemy->alive &&
bullet->sprite.getGlobalBounds().intersects(enemy->sprite.getGlobalBounds())) {
enemy->onCollision(bullet);
bullet->alive = false;
if (!enemy->alive) {
player.addScore(10);
Explosion* explosion = new Explosion(enemy->x, enemy->y);
explosions.push_back(explosion);
entities.push_back(explosion);
}
}
}
// 玩家与敌人碰撞
if (enemy->alive && player.alive &&
enemy->sprite.getGlobalBounds().intersects(player.sprite.getGlobalBounds())) {
enemy->alive = false;
player.health--;
if (player.health <= 0) {
player.alive = false;
gameOver = true;
}
Explosion* explosion = new Explosion(enemy->x, enemy->y);
explosions.push_back(explosion);
entities.push_back(explosion);
}
}
// 玩家与道具碰撞
for (auto powerup : powerups) {
if (powerup->alive && player.alive &&
powerup->sprite.getGlobalBounds().intersects(player.sprite.getGlobalBounds())) {
player.applyPowerup(powerup->getType());
powerup->alive = false;
// 添加获得道具的特效
Explosion* explosion = new Explosion(powerup->x, powerup->y);
explosions.push_back(explosion);
entities.push_back(explosion);
}
}
// 移除死亡实体
entities.erase(
std::remove_if(entities.begin(), entities.end(),
[](Entity* e) {
if (!e->alive) {
delete e;
return true;
}
return false;
}),
entities.end()
);
bullets.erase(
std::remove_if(bullets.begin(), bullets.end(),
[](Bullet* b) { return !b->alive; }),
bullets.end()
);
enemies.erase(
std::remove_if(enemies.begin(), enemies.end(),
[](Enemy* e) { return !e->alive; }),
enemies.end()
);
explosions.erase(
std::remove_if(explosions.begin(), explosions.end(),
[](Explosion* e) {
if (!e->alive) {
delete e;
return true;
}
return false;
}),
explosions.end()
);
powerups.erase(
std::remove_if(powerups.begin(), powerups.end(),
[](Powerup* p) {
if (!p->alive) {
delete p;
return true;
}
return false;
}),
powerups.end()
);
// 更新文本
scoreText.setString("分数: " + std::to_string(player.getScore()));
healthText.setString("生命: " + std::to_string(player.health));
if (player.isPowerupActive()) {
float remainingTime = 10.0f - powerupClock.getElapsedTime().asSeconds();
powerupText.setString("增益: " + powerupTypeToString(player.getActivePowerup()) +
" (剩余: " + std::to_string(static_cast<int>(remainingTime + 1)) + "s)");
} else {
powerupText.setString("");
}
}
// 绘制游戏
window.clear();
window.draw(background);
// 绘制所有实体
for (auto entity : entities) {
entity->draw(window);
}
// 绘制文本
window.draw(scoreText);
window.draw(healthText);
window.draw(powerupText);
// 游戏结束画面
if (gameOver) {
window.draw(gameOverText);
window.draw(restartText);
}
window.display();
}
// 清理内存
for (auto entity : entities) {
if (entity != &player) delete entity;
}
return 0;
}