2010-01-10 31 views
1

警告这是一个很长的问题!是否在这个类中存储迭代器是不明智的?还有其他什么方法来迭代这个序列?

我在Win32上使用C++实现纸牌游戏,并且在询问this问题后,我很清楚,我可能需要关于实际类设计而不是实现细节的指导。

我正在使用模型视图控制器模式来实现游戏。模型是游戏,卡片,专栏和移动历史。该视图负责绘画到屏幕以及负责处理消息和计时器的控件。

我目前试图实现的游戏方面是动作历史,属于Model - 我希望能够“撤消”和“重做”任何Action

我将Move对象描述为从一个CardPile到另一个的单个卡的原子移动。并且我将Action描述为由一个或多个Moves组成。例如一笔交易将从Deck到。 (DeckColumn仅仅是CardPile的专业化)。

我将Action定义为Moves的双向移动,并且已经为GetCurrentMove()提供了一些函数,并且在执行它时提前()移动。

class Action 
{ 
public: 
    void SetMoves(std::deque<Move> dmoves){ _m_deque = dmoves; } 
    void Advance(); 
    std::deque<Move>::const_iterator GetCurrentMove(); 
private: 
    std::deque<Move> _m_deque; 
    std::deque<Move>::const_iterator currentmove; 
}; 

当处理(或设置,或撤消),这些Move对象是动画数据。我需要一次只能访问一个Move对象。我检索Move,将其解析为x,y共同剧组,然后启动动画,将卡从一个位置移动到另一个位置。当卡片到达目的地后,我再从deque中取出另一个Move

我已经被其他有更多经验的人建议,不要在Action类中存储迭代器。 STL不这样做,显然有很好的理由。

但我的问题是 - 难道我Action类中存储迭代器? 您看到我的模型和视图都需要访问当前的Move,那么我还可以在那里存储指向当前Move ...的迭代器...在Controller中?

我的游戏动画是基于(非常广泛的)这个模型:

void control.game_loop(message) 
{ 
    switch(message) 
    { 
     case TIMER: 
     { 
      if(view.CardHasReachedDestination()) 
      { 
      game.AdvanceAnimation(); 
      if(!game.AnimationFinished()) 
       view.Parse(game.GetNextMove()); 
      } 
      view.MoveCardXY(); 
      view.PaintToTheScreen(); 
      controller.StartTheTimerAgain(); 
     } 
    } 
} 

最良好的祝愿,

BeeBand

回答

1

我会创建一个函数模板来动画整个动作,而不是一次移动一次。调用与开始和结束迭代器需要被动画行动:

template <class iterator> 
void animate_action(iterator first, iterator last) { 
    for (iterator i=first; i!=last; ++i) 
     animate_move(*i); 
} 

哪里animate_move是相当多的,你已经有什么出单招的动画。你会喜欢的东西调用此:

animate_action(action.begin(), action.end()); 

或以相反的顺序动画:

animate_action(action.rbegin(), action.rend()); 

这就是为什么你想animate_action模板(很大一部分) - 这种方式它既不知道也不关心它是否接收到前向迭代器或反向引用器。

编辑:根据进一步的评论,似乎有几个选择。

标准待机将是使用一个单独的线程来处理动画绘制,所以它只是有这样的事情:

while (current_position != final_position) { 
    draw_card(currrent_position); 
    current_position = next_position(); 
    sleep(timer_period); 
} 

另一个办法是,而不是等待一个定时器火了,请求当前的迭代器,我倾向于创建并排队表示动画中每个动作的对象,然后当定时器触发时,定时器函数将检索并执行队列中的下一项:

for (int i=0;i<Move.size(); i++) 
    for (int j=0; j<num_positions; j++) 
     enqueue(move, Move[i], position(j)); 
+0

但是一定要以相反的顺序动画,你需要做更多的事情这一系列的行动是以相反的顺序进行的 - 每个行动本身也必须颠倒过来。 – James 2010-01-10 22:17:07

+0

@Autopulated:我只提到了反向迭代器,因为在他之前的问题中,他询问过正向和反向迭代器。你说得对,实际上倒转动画(例如撤销动作),你也需要倒转每个单独的动画。 – 2010-01-10 22:28:40

+0

@Both:re。反向动画。是'撤销'我有一个函数view.ParseUnMove(),而不是ParseMove(),它反转了源和目标'CardPiles' - 这会创建一个反向动画。 – BeeBand 2010-01-10 23:06:00

0

如果你使用一个列表,而不是一个deque的,那么迭代器指向元素在元素的生命周期中保持有效。

如果你这样做,我没有看到在这种情况下存储迭代器有什么问题。

相关问题