C++实现黑板模式操作

本文介绍了一个基于C++的黑板系统实现,用于游戏开发中的数据处理。系统采用多态设计,通过模板类BlackboardData封装不同类型的数据,核心类Blackboard提供键值存储功能,支持安全类型检查、异常处理和多种数据访问方式。文章还定义了4种游戏常用数据结构:Position(三维坐标)、Health(生命值)、Weapon(武器属性,包含嵌套的Ammo结构)和Perception(感知系统,包含可见实体数组)。该系统通过动态类型转换确保类型安全,使用智能指针管理内存,适合作为游戏AI的数据共享中心。

#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <vector>
#include <stdexcept>
#include <typeinfo>
#include <cmath>
#include <iomanip>

// ------------------------
// 黑板系统实现 (修复了变量名错误)
// ------------------------

// 基类:黑板数据接口
class BlackboardDataBase {
public:
    virtual ~BlackboardDataBase() = default;
    virtual const std::type_info& type() const = 0;
    virtual std::unique_ptr<BlackboardDataBase> clone() const = 0;
    virtual void print(std::ostream& os) const = 0;
};

// 模板数据包装器
template <typename T>
class BlackboardData : public BlackboardDataBase {
public:
    explicit BlackboardData(const T& data) : data_(data) {}
    explicit BlackboardData(T&& data) : data_(std::move(data)) {}

    const std::type_info& type() const override {
        return typeid(T);
    }

    std::unique_ptr<BlackboardDataBase> clone() const override {
        return std::make_unique<BlackboardData>(data_);
    }

    void print(std::ostream& os) const override {
        os << data_;
    }

    T data_;
};

// 黑板核心存储类 (修复了变量名错误)
class Blackboard {
private:
    std::unordered_map<std::string, std::unique_ptr<BlackboardDataBase>> data_map_;

public:
    Blackboard() = default;

    // 禁止复制(确保唯一所有权)
    Blackboard(const Blackboard&) = delete;

    Blackboard& operator=(const Blackboard&) = delete;

    // 设置数据
    template <typename T>
    void set(const std::string& key, const T& value) {
        data_map_[key] = std::make_unique<BlackboardData<T>>(value);
    }

    template <typename T>
    void set(const std::string& key, T&& value) {
        data_map_[key] = std::make_unique<BlackboardData<T>>(std::move(value));
    }

    // 获取数据(安全版本)
    template <typename T>
    bool get(const std::string& key, T& out) const {
        auto it = data_map_.find(key);
        if (it == data_map_.end()) return false;

        auto* derived = dynamic_cast<const BlackboardData<T>*>(it->second.get());
        if (!derived) return false;

        out = derived->data_;
        return true;
    }

    // 获取数据(引用版本)
    template <typename T>
    T& get_ref(const std::string& key) {
        auto it = data_map_.find(key);
        if (it == data_map_.end()) {
            throw std::runtime_error("Key not found: " + key);
        }

        auto* derived = dynamic_cast<BlackboardData<T>*>(it->second.get());
        if (!derived) {
            throw std::runtime_error("Type mismatch for key: " + key);
        }

        return derived->data_;
    }

    // 获取数据(常量引用版本)
    template <typename T>
    const T& get_cref(const std::string& key) const {
        auto it = data_map_.find(key);
        if (it == data_map_.end()) {
            throw std::runtime_error("Key not found: " + key);
        }

        auto* derived = dynamic_cast<const BlackboardData<T>*>(it->second.get());
        if (!derived) {
            throw std::runtime_error("Type mismatch for key: " + key);
        }

        return derived->data_;
    }

    // 检查数据是否存在
    bool contains(const std::string& key) const {
        return data_map_.find(key) != data_map_.end();
    }

    // 清除数据
    void clear() {
        data_map_.clear();
    }
};

// ------------------------
// 复杂结构体定义
// ------------------------

// 1. 基本位置结构体
struct Position {
    double x, y, z;

    Position(double x = 0.0, double y = 0.0, double z = 0.0)
        : x(x), y(y), z(z) {}

    friend std::ostream& operator<<(std::ostream& os, const Position& p) {
        os << "(" << p.x << ", " << p.y << ", " << p.z << ")";
        return os;
    }
};

// 2. 健康状态结构体
struct Health {
    int current;
    int max;

    Health(int cur = 100, int max = 100) : current(cur), max(max) {}

    friend std::ostream& operator<<(std::ostream& os, const Health& h) {
        os << h.current << "/" << h.max;
        return os;
    }
};

// 3. 武器状态结构体(包含嵌套结构体)
struct Ammo {
    int current;
    int max;
    std::string type;

    Ammo(int cur = 30, int max = 30, std::string type = "5.56mm")
        : current(cur), max(max), type(std::move(type)) {}
};

struct Weapon {
    std::string name;
    double damage;
    double accuracy;
    Ammo ammo;

    Weapon(std::string name = "Rifle", double dmg = 25.0, double acc = 0.75)
        : name(std::move(name)), damage(dmg), accuracy(acc) {}

    friend std::ostream& operator<<(std::ostream& os, const Weapon& w) {
        os << w.name << " [Dmg: " << w.damage << ", Acc: "
            << std::fixed << std::setprecision(2) << w.accuracy * 100 << "%, Ammo: "
            << w.ammo.current << "/" << w.ammo.max << " " << w.ammo.type << "]";
        return os;
    }
};

// 4. 感知结构体(包含数组)
struct Perception {
    struct VisibleEntity {
        int id;
        Position position;
        double distance;
    };

    std::vector<VisibleEntity> visible_enemies;
    std::vector<VisibleEntity> visible_allies;

    void add_enemy(int id, const Position& pos, double dist) {
        visible_enemies.push_back({ id, pos, dist });
    }

    void add_ally(int id, const Position& pos, double dist) {
        visible_allies.push_back({ id, pos, dist });
    }
};

// 5. 命令结构体(包含联合体)
struct Command {
    enum class Type { MOVE, ATTACK, DEFEND, HOLD } type;

    union {
        Position target_position;
        int target_id;
    };

    Command(Type t = Type::HOLD) : type(t) {}

    friend std::ostream& operator<<(std::ostream& os, const Command& cmd) {
        switch (cmd.type) {
        case Type::MOVE:
            os << "MOVE to " << cmd.target_position;
            break;
        case Type::ATTACK:
            os << "ATTACK target #" << cmd.target_id;
            break;
        case Type::DEFEND:
            os << "DEFEND position " << cmd.target_position;
            break;
        case Type::HOLD:
            os << "HOLD position";
            break;
        }
        return os;
    }
};

// 重载<<操作符用于Perception
std::ostream& operator<<(std::ostream& os, const Perception::VisibleEntity& e) {
    os << "#" << e.id << " at " << e.position << " (" << e.distance << "m)";
    return os;
}

std::ostream& operator<<(std::ostream& os, const Perception& p) {
    os << "Perception:\n";
    os << "  Enemies: ";
    for (const auto& e : p.visible_enemies) {
        os << e << "; ";
    }
    os << "\n  Allies: ";
    for (const auto& a : p.visible_allies) {
        os << a << "; ";
    }
    return os;
}

// ------------------------
// 组件系统实现
// ------------------------

// 组件基类
class Component {
protected:
    Blackboard* blackboard_;

public:
    explicit Component(Blackboard* bb) : blackboard_(bb) {}
    virtual ~Component() = default;

    virtual void update() = 0;
    virtual void print(std::ostream& os) const = 0;
};

// 具体组件实现
class MovementComponent : public Component {
public:
    using Component::Component;

    void update() override {
        Position& pos = blackboard_->get_ref<Position>("position");

        // 模拟移动逻辑
        pos.x += 0.5;
        pos.y += 0.2;
        pos.z = std::sin(pos.x * 0.1) * 2.0;
    }

    void print(std::ostream& os) const override {
        os << "MovementComponent\n";
    }
};

class HealthComponent : public Component {
public:
    using Component::Component;

    void update() override {
        Health& health = blackboard_->get_ref<Health>("health");

        // 模拟健康恢复
        health.current = std::min(health.current + 1, health.max);
    }

    void print(std::ostream& os) const override {
        os << "HealthComponent\n";
    }
};

class WeaponComponent : public Component {
public:
    using Component::Component;

    void update() override {
        Weapon& weapon = blackboard_->get_ref<Weapon>("weapon");

        // 模拟弹药消耗
        if (weapon.ammo.current > 0) {
            weapon.ammo.current--;
        }
    }

    void print(std::ostream& os) const override {
        os << "WeaponComponent\n";
    }
};

class PerceptionComponent : public Component {
public:
    using Component::Component;

    void update() override {
        Perception& perception = blackboard_->get_ref<Perception>("perception");
        const Position& pos = blackboard_->get_cref<Position>("position");

        // 模拟感知更新
        perception.visible_enemies.clear();
        perception.visible_allies.clear();

        // 添加一些模拟实体
        perception.add_enemy(1001, { pos.x + 10.0, pos.y + 5.0, 0.0 }, 11.2);
        perception.add_ally(2001, { pos.x - 3.0, pos.y + 2.0, 0.0 }, 3.6);
    }

    void print(std::ostream& os) const override {
        os << "PerceptionComponent\n";
    }
};

class AIComponent : public Component {
public:
    using Component::Component;

    void update() override {
        const Perception& perception = blackboard_->get_cref<Perception>("perception");
        const Health& health = blackboard_->get_cref<Health>("health");
        Command& command = blackboard_->get_ref<Command>("command");

        // 简单的AI决策
        if (!perception.visible_enemies.empty()) {
            command.type = Command::Type::ATTACK;
            command.target_id = perception.visible_enemies[0].id;
        }
        else if (health.current < 50) {
            command.type = Command::Type::DEFEND;
            command.target_position = { 0.0, 0.0, 0.0 }; // 回到基地
        }
        else {
            command.type = Command::Type::MOVE;
            command.target_position = { 10.0, 20.0, 0.0 }; // 前进位置
        }
    }

    void print(std::ostream& os) const override {
        os << "AIComponent\n";
    }
};

// ------------------------
// 实体类
// ------------------------

class Entity {
private:
    int id_;
    std::string name_;
    Blackboard blackboard_;
    std::vector<std::unique_ptr<Component>> components_;

public:
    Entity(int id, std::string name)
        : id_(id), name_(std::move(name)) {

        // 初始化黑板数据
        blackboard_.set("position", Position{ 0.0, 0.0, 0.0 });
        blackboard_.set("health", Health{ 75, 100 });
        blackboard_.set("weapon", Weapon{ "M4 Carbine", 28.0, 0.85 });
        blackboard_.set("perception", Perception{});
        blackboard_.set("command", Command{});

        // 添加组件
        components_.push_back(std::make_unique<MovementComponent>(&blackboard_));
        components_.push_back(std::make_unique<HealthComponent>(&blackboard_));
        components_.push_back(std::make_unique<WeaponComponent>(&blackboard_));
        components_.push_back(std::make_unique<PerceptionComponent>(&blackboard_));
        components_.push_back(std::make_unique<AIComponent>(&blackboard_));
    }

    void update() {
        for (auto& comp : components_) {
            comp->update();
        }
    }

    void print_status() const {
        std::cout << "\nEntity #" << id_ << " - " << name_ << "\n";
    }

    const Blackboard& blackboard() const { return blackboard_; }
};

// ------------------------
// 主程序
// ------------------------

int main() {
    std::cout << "作战仿真系统 - 实体模型组件化实现\n";
    std::cout << "========================================\n\n";

    // 创建士兵实体
    Entity soldier(1001, "Infantry Soldier");

    // 初始状态
    std::cout << "初始状态:\n";
    soldier.print_status();

    // 模拟游戏循环
    for (int i = 0; i < 3; ++i) {
        std::cout << "\n=== 更新 #" << i + 1 << " ===\n";

        // 更新实体状态
        soldier.update();

        // 打印更新后状态
        soldier.print_status();
    }

    // 演示获取复杂结构体
    const Blackboard& bb = soldier.blackboard();
    const Perception& perception = bb.get_cref<Perception>("perception");
    const Command& command = bb.get_cref<Command>("command");

    std::cout << "\n最终命令状态: " << command << "\n";

    if (!perception.visible_enemies.empty()) {
        std::cout << "检测到敌人: " << perception.visible_enemies[0] << "\n";
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值