问题标题: 飞机大战!!!简略版

0
0
石浩一
石浩一
修练者
修练者

#include <iostream>
#include <vector>
#include <chrono>
#include <thread>
#include <random>
#include <conio.h>
#include <windows.h>
#include <algorithm>
#include <string>
#include <atomic>
#include <mutex>
#include <condition_variable>

using namespace std;

// ====================== 游戏常量 ======================
const int SCREEN_WIDTH = 80;
const int SCREEN_HEIGHT = 24;
const int PLAYER_WIDTH = 3;
const int PLAYER_HEIGHT = 2;
const int ENEMY_WIDTH = 3;
const int ENEMY_HEIGHT = 2;
const int BULLET_SPEED = 2;
const int ENEMY_SPEED = 1;
const int MAX_ENEMIES = 5;  // 减少最大敌人数
const int MAX_BULLETS = 25;  // 减少最大子弹数
const int MAX_POWERUPS = 3;  // 减少最大道具数
const int GAME_TICK_MS = 33;

// ====================== 游戏状态 ======================
atomic<bool> gameRunning(true);
mutex gameMutex;
condition_variable gameCV;

// ====================== 游戏对象 ======================
struct GameObject {
    int x, y;
    int width, height;
    bool active;
    const char* sprite;  // 改为指针减少拷贝
};

struct Player : public GameObject {
    int lives;
    int health;
    int maxHealth;
    int score;
    int powerLevel;
    int powerUpTimer;
    int invincibleTimer;

    Player() {
        x = SCREEN_WIDTH / 2;
        y = SCREEN_HEIGHT - PLAYER_HEIGHT - 1;
        width = PLAYER_WIDTH;
        height = PLAYER_HEIGHT;
        active = true;
        lives = 3;
        health = 10;
        maxHealth = 10;
        score = 0;
        powerLevel = 1;
        powerUpTimer = 0;
        invincibleTimer = 0;
        sprite = " ^ \n/ \\";
    }

    bool isInvincible() const {
        return invincibleTimer > 0;
    }
};

struct Bullet : public GameObject {
    bool isPlayerBullet;
    int damage;

    Bullet(int x, int y, bool playerBullet, int dmg = 1) {
        this->x = x;
        this->y = y;
        width = 1;
        height = 1;
        active = true;
        isPlayerBullet = playerBullet;
        damage = dmg;
        sprite = playerBullet ? "o" : "x";
    }
};

struct Enemy : public GameObject {
    int health;
    int maxHealth;
    int movePattern;
    int moveTimer;
    int scoreValue;

    Enemy() {
        width = ENEMY_WIDTH;
        height = ENEMY_HEIGHT;
        active = true;
        health = 2 + rand() % 4;  // 减少敌人血量
        maxHealth = health;
        movePattern = rand() % 3;
        moveTimer = 0;
        scoreValue = health * 30;  // 调整分数
        sprite = "\\ /\n V ";
    }
};

struct PowerUp : public GameObject {
    int type;

    PowerUp() {
        width = 1;
        height = 1;
        active = true;
        type = rand() % 4 + 1;
        sprite = type == 1 ? "H" : (type == 2 ? "P" : (type == 3 ? "B" : "S"));
    }
};

// ====================== 游戏引擎 ======================
class GameEngine {
private:
    Player player;
    vector<Bullet> bullets;
    vector<Enemy> enemies;
    vector<PowerUp> powerUps;
    vector<string> screenBuffer;
    chrono::time_point<chrono::steady_clock> lastUpdate;
    random_device rd;
    mt19937 gen;
    uniform_int_distribution<> disX;
    uniform_int_distribution<> disY;
    uniform_int_distribution<> disPattern;

    // 预计算UI元素
    string scoreText;
    string livesText;
    string powerText;
    string invincibleText;

public:
    GameEngine() : gen(rd()), disX(0, SCREEN_WIDTH - ENEMY_WIDTH),
                  disY(0, SCREEN_HEIGHT / 3), disPattern(0, 100) {
        screenBuffer.resize(SCREEN_HEIGHT, string(SCREEN_WIDTH, ' '));
        lastUpdate = chrono::steady_clock::now();

        // 预初始化UI文本
        scoreText.reserve(20);
        livesText.reserve(20);
        powerText.reserve(30);
        invincibleText = "INVINCIBLE!";
    }

    void init() {
        player = Player();
        bullets.clear();
        bullets.reserve(MAX_BULLETS);  // 预分配内存
        enemies.clear();
        enemies.reserve(MAX_ENEMIES);
        powerUps.clear();
        powerUps.reserve(MAX_POWERUPS);

        // 初始生成少量敌人
        for (int i = 0; i < 3; ++i) {
            spawnEnemy();
        }
    }

    void spawnEnemy() {
        if (enemies.size() >= MAX_ENEMIES) return;

        Enemy enemy;
        enemy.x = disX(gen);
        enemy.y = disY(gen);
        enemies.push_back(enemy);
    }

    void spawnPowerUp(int x, int y) {
        if (powerUps.size() >= MAX_POWERUPS) return;

        PowerUp pu;
        pu.x = x;
        pu.y = y;
        powerUps.push_back(pu);
    }

    void update() {
        auto now = chrono::steady_clock::now();
        auto elapsed = chrono::duration_cast<chrono::milliseconds>(now - lastUpdate).count();

        if (elapsed < GAME_TICK_MS) {
            this_thread::sleep_for(chrono::milliseconds(1));
            return;
        }

        lastUpdate = now;

        // 处理输入
        handleInput();

        // 更新玩家状态
        updatePlayer();

        // 更新子弹
        updateBullets();

        // 更新敌人
        updateEnemies();

        // 更新道具
        updatePowerUps();

        // 碰撞检测
        checkCollisions();

        // 渲染准备
        prepareRender();
    }

    void updatePlayer() {
        if (player.powerUpTimer > 0) {
            if (--player.powerUpTimer == 0) {
                player.powerLevel = max(1, player.powerLevel - 1);
            }
        }

        if (player.invincibleTimer > 0) {
            player.invincibleTimer--;
        }
    }

    void updateBullets() {
        for (auto it = bullets.begin(); it != bullets.end(); ) {
            if (it->isPlayerBullet) {
                it->y -= BULLET_SPEED;
            } else {
                it->y += BULLET_SPEED;
            }

            if (it->y < 0 || it->y >= SCREEN_HEIGHT) {
                it = bullets.erase(it);  // 原地删除
            } else {
                ++it;
            }
        }
    }

    void updateEnemies() {
        // 敌人移动和生成逻辑
        int activeEnemies = 0;

        for (auto it = enemies.begin(); it != enemies.end(); ) {
            if (!it->active) {
                it = enemies.erase(it);
                continue;
            }

            activeEnemies++;
            it->moveTimer++;

            // 简化移动模式
            switch (it->movePattern) {
                case 0: it->y += ENEMY_SPEED; break;
                case 1:
                    it->y += ENEMY_SPEED / 2;
                    it->x += (it->moveTimer % 20 < 10) ? 1 : -1;
                    break;
                case 2:
                    if (it->moveTimer % 10 == 0) {
                        it->x += rand() % 3 - 1;
                    }
                    it->y += ENEMY_SPEED / 3;
                    break;
            }

            // 边界检查
            it->x = max(0, min(SCREEN_WIDTH - it->width, it->x));

            // 敌人射击 - 降低频率
            if (rand() % 120 < 2) {
                fireBullet(it->x + it->width / 2, it->y + it->height, false, 1);
            }

            // 检查是否到达底部
            if (it->y >= SCREEN_HEIGHT - 1) {
                it->active = false;
                if (!player.isInvincible()) {
                    player.health -= 2;
                }
                it = enemies.erase(it);
            } else {
                ++it;
            }
        }

        // 动态调整敌人生成率
        if (activeEnemies < MAX_ENEMIES / 2 && rand() % 100 < 3) {
            spawnEnemy();
        }
    }

    void updatePowerUps() {
        for (auto it = powerUps.begin(); it != powerUps.end(); ) {
            it->y += 1;
            if (it->y >= SCREEN_HEIGHT || !it->active) {
                it = powerUps.erase(it);
            } else {
                ++it;
            }
        }
    }

    void handleInput() {
        if (_kbhit()) {
            char ch = _getch();

            lock_guard<mutex> lock(gameMutex);

            switch (ch) {
                case 'a': case 'A':
                    player.x = max(0, player.x - 2);
                    break;
                case 'd': case 'D':
                    player.x = min(SCREEN_WIDTH - player.width, player.x + 2);
                    break;
                case ' ':
                    fireBullet(player.x + player.width / 2, player.y, true, player.powerLevel);
                    break;
                case 'q': case 'Q':
                    gameRunning = false;
                    gameCV.notify_all();
                    break;
            }
        }
    }

    void fireBullet(int x, int y, bool isPlayer, int damage = 1) {
        if (isPlayer) {
            if (bullets.size() >= MAX_BULLETS) return;

            bullets.emplace_back(x, y, true, damage);

            // 简化武器升级效果
            if (player.powerLevel > 1) {
                bullets.emplace_back(x - 2, y, true, damage);
                if (player.powerLevel > 2) {
                    bullets.emplace_back(x + 2, y, true, damage);
                }
            }
        } else {
            if (bullets.size() < MAX_BULLETS) {
                bullets.emplace_back(x, y, false, 1);
            }
        }
    }

    void checkCollisions() {
        // 玩家子弹与敌人碰撞
        for (auto& bullet : bullets) {
            if (!bullet.isPlayerBullet || !bullet.active) continue;

            for (auto& enemy : enemies) {
                if (!enemy.active) continue;

                if (checkCollision(bullet, enemy)) {
                    bullet.active = false;
                    enemy.health -= bullet.damage;

                    if (enemy.health <= 0) {
                        enemy.active = false;
                        player.score += enemy.scoreValue;

                        // 降低道具掉落率
                        if (rand() % 100 < 15) {
                            spawnPowerUp(enemy.x + enemy.width / 2, enemy.y + enemy.height);
                        }
                    }
                    break;  // 一颗子弹只能击中一个敌人
                }
            }
        }

        // 敌人子弹与玩家碰撞
        for (auto& bullet : bullets) {
            if (bullet.isPlayerBullet || !bullet.active || player.isInvincible()) continue;

            if (checkCollision(bullet, player)) {
                bullet.active = false;
                player.health -= bullet.damage;
                if (player.health <= 0) {
                    player.lives--;
                    player.health = player.maxHealth;
                    player.invincibleTimer = 50;
                }
                break;
            }
        }

        // 玩家与敌人碰撞
        for (auto& enemy : enemies) {
            if (!enemy.active || player.isInvincible()) continue;

            if (checkCollision(player, enemy)) {
                enemy.active = false;
                player.health -= 2;
                if (player.health <= 0) {
                    player.lives--;
                    player.health = player.maxHealth;
                    player.invincibleTimer = 50;
                }
                break;
            }
        }

        // 玩家与道具碰撞
        for (auto& pu : powerUps) {
            if (!pu.active) continue;

            if (checkCollision(player, pu)) {
                pu.active = false;

                switch (pu.type) {
                    case 1: player.health = min(player.maxHealth, player.health + 3); break;
                    case 2:
                        player.powerLevel = min(3, player.powerLevel + 1);
                        player.powerUpTimer = 300;  // 缩短强化时间
                        break;
                    case 3:
                        for (auto& enemy : enemies) {
                            enemy.active = false;
                            player.score += 30;  // 减少炸弹奖励
                        }
                        break;
                    case 4: player.invincibleTimer = 80; break;  // 缩短无敌时间
                }
            }
        }

        // 检查游戏结束
        if (player.lives <= 0) {
            gameRunning = false;
            gameCV.notify_all();
        }
    }

    bool checkCollision(const GameObject& obj1, const GameObject& obj2) {
        return obj1.x < obj2.x + obj2.width &&
               obj1.x + obj1.width > obj2.x &&
               obj1.y < obj2.y + obj2.height &&
               obj1.y + obj1.height > obj2.y;
    }

    void drawObject(const GameObject& obj) {
        if (!obj.active) return;

        int spriteX = 0;
        int spriteY = 0;

        for (const char* p = obj.sprite; *p != '\0'; ++p) {
            if (*p == '\n') {
                spriteY++;
                spriteX = 0;
                continue;
            }

            int screenX = obj.x + spriteX;
            int screenY = obj.y + spriteY;

            if (screenX >= 0 && screenX < SCREEN_WIDTH &&
                screenY >= 0 && screenY < SCREEN_HEIGHT) {
                screenBuffer[screenY][screenX] = *p;
            }

            spriteX++;
        }
    }

    void drawHealthBar(int x, int y, int current, int max) {
        float ratio = static_cast<float>(current) / max;
        int bars = static_cast<int>(20 * ratio);

        string bar = "[";
        for (int i = 0; i < 20; ++i) {
            bar += (i < bars) ? "=" : " ";
        }
        bar += "] " + to_string(current) + "/" + to_string(max);

        for (int i = 0; i < bar.size() && x + i < SCREEN_WIDTH; ++i) {
            screenBuffer[y][x + i] = bar[i];
        }
    }

    void prepareRender() {
        // 清空屏幕缓冲区
        for (auto& line : screenBuffer) {
            fill(line.begin(), line.end(), ' ');
        }

        // 绘制游戏对象
        drawObject(player);

        for (const auto& bullet : bullets) {
            drawObject(bullet);
        }

        for (const auto& enemy : enemies) {
            drawObject(enemy);
            drawHealthBar(enemy.x, enemy.y - 1, enemy.health, enemy.maxHealth);
        }

        for (const auto& pu : powerUps) {
            drawObject(pu);
        }

        // 绘制UI
        drawUI();
    }

    void drawUI() {
        // 预生成UI文本减少字符串操作
        scoreText = "Score: " + to_string(player.score);
        copy(scoreText.begin(), scoreText.end(), screenBuffer[0].begin());

        livesText = "Lives: " + to_string(player.lives);
        copy(livesText.rbegin(), livesText.rend(), screenBuffer[0].rbegin());

        // 玩家血条
        drawHealthBar(0, 1, player.health, player.maxHealth);

        // 武器状态
        powerText = "Weapon: Lv." + to_string(player.powerLevel);
        if (player.powerUpTimer > 0) {
            powerText += " (" + to_string(player.powerUpTimer / 20) + ")";
        }
        copy(powerText.begin(), powerText.end(), screenBuffer[2].begin());

        // 无敌状态
        if (player.isInvincible()) {
            int pos = (SCREEN_WIDTH - invincibleText.size()) / 2;
            copy(invincibleText.begin(), invincibleText.end(), screenBuffer[SCREEN_HEIGHT-1].begin() + pos);
        }
    }

    void render() {
        HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD coord = {0, 0};
        SetConsoleCursorPosition(hConsole, coord);

        // 使用单个cout输出提高性能
        string output;
        output.reserve(SCREEN_WIDTH * SCREEN_HEIGHT * 2);

        for (const auto& line : screenBuffer) {
            output += line + "\n";
        }

        cout << output;
    }

    void gameLoop() {
        init();

        while (gameRunning) {
            update();
            render();
        }

        // 游戏结束画面
        system("cls");
        cout << "==================================" << endl;
        cout << "           GAME OVER             " << endl;
        cout << "==================================" << endl;
        cout << " Final Score: " << player.score << endl;
        cout << "==================================" << endl;
        cout << " Press any key to exit..." << endl;
        _getch();
    }
};

void inputThread() {
    while (gameRunning) {
        if (_kbhit()) {
            unique_lock<mutex> lock(gameMutex);
            gameCV.wait(lock, []{ return !gameRunning; });
            break;
        }
        this_thread::sleep_for(chrono::milliseconds(10));
    }
}

int main() {
    // 设置控制台窗口
    HWND console = GetConsoleWindow();
    RECT r;
    GetWindowRect(console, &r);
    MoveWindow(console, r.left, r.top, 800, 600, TRUE);

    // 隐藏光标
    HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO cursorInfo;
    GetConsoleCursorInfo(out, &cursorInfo);
    cursorInfo.bVisible = false;
    SetConsoleCursorInfo(out, &cursorInfo);

    // 设置控制台字体
    CONSOLE_FONT_INFOEX cfi;
    cfi.cbSize = sizeof(cfi);
    cfi.nFont = 0;
    cfi.dwFontSize.X = 8;
    cfi.dwFontSize.Y = 12;
    cfi.FontFamily = FF_DONTCARE;
    cfi.FontWeight = FW_NORMAL;
    wcscpy_s(cfi.FaceName, L"Consolas");
    SetCurrentConsoleFontEx(out, FALSE, &cfi);

    // 启动游戏
    GameEngine game;
    thread input(inputThread);
    game.gameLoop();

    if (input.joinable()) {
        input.join();
    }

    return 0;
}
 


1
石浩一
石浩一
修练者
修练者

规则:

ad移动空格发射,q键退出。

0
0
我要回答