C++实现Blueprint类:绑定函数参数并批量创建Entity
I’ve worked through your problem and put together a concrete implementation that hits all your requirements. The core idea is using lambdas (cleaner than std::bind here) to capture your Component instances and pre-bound arguments, storing callables that only need an Entity to execute the addTo logic.
Step 1: Refine the Component Class
First, I adjusted the Component class for consistency (fixing the storage type to match your shared_ptr usage) while keeping your original addTo overloads intact:
#include <vector> #include <functional> #include <memory> #include <map> #include <string> // Assume Entity is your UUID type (adjust as needed) using Entity = unsigned int; template <class T> class Component{ private: std::map<Entity, std::shared_ptr<T>> attachedEntities; public: // Constructor, setters/getters omitted for brevity // 1. Create component from arguments and attach to entity template<typename... Args> void addTo(const Entity &en, Args&&...args) { addTo(en, std::make_shared<T>(std::forward<Args>(args)...)); } // 2. Attach a derived component pointer (takes ownership) template <typename U, typename std::enable_if<std::is_base_of<T, U>::value>::type* = nullptr> void addTo(const Entity &en, U* ptr) { addTo(en, std::shared_ptr<T>(ptr)); } // 3. Attach an existing shared_ptr component void addTo(const Entity &en, const std::shared_ptr<T> ptr) { attachedEntities[en] = ptr; // Actual insertion logic } };
Step 2: Implement the Blueprint Class
The Blueprint will store lambdas that capture Component references and pre-bound parameters. Each lambda only needs an Entity to trigger the component attachment:
class Blueprint{ private: std::vector<std::function<void(const Entity&)>> frozenAddFunctions; public: // Case 1: Bind arguments to create a new component template<class T, typename... Args> void addComponent(Component<T>& comp, Args&&...args) { frozenAddFunctions.emplace_back( [&comp, args...](const Entity& en) { comp.addTo(en, std::forward<Args>(args)...); } ); } // Case 2: Bind a derived component pointer template<class T, class U, typename std::enable_if<std::is_base_of<T, U>::value>::type* = nullptr> void addComponent(Component<T>& comp, U* ptr) { frozenAddFunctions.emplace_back( [&comp, ptr](const Entity& en) { comp.addTo(en, ptr); } ); } // Case 3: Bind an existing shared_ptr component template<class T> void addComponent(Component<T>& comp, const std::shared_ptr<T> ptr) { frozenAddFunctions.emplace_back( [&comp, ptr](const Entity& en) { comp.addTo(en, ptr); } ); } // Apply all pre-configured component attachments to an entity void applyOnto(const Entity& en) { for (const auto& func : frozenAddFunctions) { func(en); } } };
Step 3: Usage Example
Here’s how you’d use this to build a bullet blueprint and spawn entities without copying:
// Example component types struct BulletComponent { float speed; int damage; BulletComponent(float s, int d) : speed(s), damage(d) {} }; struct RenderComponent { std::string texturePath; RenderComponent(const std::string& path) : texturePath(path) {} }; int main() { // Component instances (usually singletons per type in ECS) Component<BulletComponent> bulletComp; Component<RenderComponent> renderComp; // Build a bullet blueprint Blueprint bulletBlueprint; bulletBlueprint.addComponent(bulletComp, 500.0f, 10); // Pre-set speed and damage bulletBlueprint.addComponent(renderComp, "textures/bullet.png"); // Pre-set texture // Spawn new bullet entities (generate unique UUIDs as needed) Entity bullet1 = 123; bulletBlueprint.applyOnto(bullet1); Entity bullet2 = 456; bulletBlueprint.applyOnto(bullet2); return 0; }
Key Advantages & Notes
- No Entity Copying: Instead of duplicating entities, we apply pre-defined component logic to fresh, empty entities—eliminating resource bloat and crash risks from invalid copies.
- Blueprint Is Clean: The blueprint itself never gets added to any component maps; it only holds logic to modify other entities.
- Automatic Type Handling: Templates handle component type deduction for you—no manual type checks required.
- Lifetime Care: Ensure your
Componentinstances outlive the Blueprint. If you use singleton components (standard in ECS), this isn’t a problem. If not, storestd::shared_ptr<Component<T>>in the Blueprint instead of references.
内容的提问来源于stack exchange,提问作者MoustacheSpy

