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;
}