本文介绍了一个基于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;
}