You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++实现Blueprint类:绑定函数参数并批量创建Entity

Solution for Implementing Blueprint in Your ECS

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 Component instances outlive the Blueprint. If you use singleton components (standard in ECS), this isn’t a problem. If not, store std::shared_ptr<Component<T>> in the Blueprint instead of references.

内容的提问来源于stack exchange,提问作者MoustacheSpy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:27:34