2

我正在编写一个游戏,它将使用基于组件的实体系统。我要实现的前两个组件是 EntityRepresentation 和 EntityState。表示包含动画,状态决定实体应如何对游戏事件做出反应(EntityStates 的示例:站立、跳跃、攻击、死亡、坠落)。

EntityRepresnetation 根据实体的 EntityState 决定在屏幕上绘制什么动画。如果实体处于“跳跃”状态,则会播放相应的动画。(参见 EntityRepresentation::changeAnimation() 函数。)

这大概是我写这门课的方式......

class EntityRepresentation
{
  public:
    void draw(float x, float y, long currentTime, DrawingContext& dc) {
        // ...
    }

    void changeAnimation(const EntityState::Id& stateId) {
        currentAnimation = animationMap_[stateId];
    }

  private:
    map<EntityState::Id, const Animation*> animationMap_;
    const Animation* currentAnimation_;
};

我目前的方法确实不喜欢某些东西... >:( EntityState::Id 部分。目前,EntityRepresentation 将其持有的每个动画映射到特定的 EntityState::Id。ID 对于每个类都是唯一的派生自 EntityState (类独有,而不是实例独有)。这些 ID 基本上是必须在类的构造函数中手动编写的字符串,这意味着它们很容易发生名称冲突——因为我打算使游戏可编写脚本(Python)。

有人可以给我一些建议,告诉我如何缓解我在 ID 上遇到的这个问题。我在同样使用 ID 的游戏中看到了很多基于组件的系统的实现,但我仍然不喜欢它们。它只是以错误的方式摩擦我。

也许您可以建议进行设计更改,这样 EntityRepresentation 就不必知道 EntityState 的类型,同时仍然保留封装。

4

3 回答 3

1

假设在编译时不需要与每个 EntityState 关联的 ID,我使用的一个技巧是使用指针作为 ID。如果 EntityState 是单例,这尤其适用,在这种情况下,您可以简单地使用单例实例的地址作为 ID。否则,为每个 ID 静态分配一小块内存可以正常工作。

class EntityState {
public:
    EntityState(void *id) : mId(id) { }
private:
    void *mId;
};

class EntityStateJump : public EntityState {
public:
    EntityStateJump() : EntityState(getId()) { }
private:
    void *getId() {
        static void *id = new int;
        return id;
    }
};

编辑:为避免静态初始化顺序问题而进行的微小更改。

于 2011-06-16T12:50:56.973 回答
1

我建议使用状态模式来实现设计

class EntityState
{
public:
    EntityState(const Animation* animation);
    static const EntityState* getStandingState();
    static const EntityState* getJumpingState();
    static const EntityState* getAttackingState();

    const Animation& getAnimation() const;

protected:
    const Animation* pAnymation_;
};

class EntityRepresentation
{
public:
    void draw(float x, float y, long currentTime, DrawingContext& dc) {
        // ...
        const Animation& animation(state_->getAnimation());
    }

    void changeState(const EntityState* newState) {
        state_ = newState;
    }

private:
    const EntityState* state_;
};

void EventHandler(EntityRepresentation& entity)
{
    entity.changeState(EntityState::getJumpingState());
}
于 2011-06-16T13:13:40.077 回答
1

使用 typeid(),这就是它的用途。您可以使用 aconst type_info*作为键类型。

或者,您知道,您可以只使用实际继承,例如调用虚函数来获取当前动画,这样会更智能。

于 2011-06-16T13:15:08.547 回答