我正在为自己的乐趣和训练设计一款小游戏。游戏的真实身份与我的实际问题完全无关,假设它是 主谋 游戏(它实际上是:)
我的真正目标是拥有一个界面 IPlayer
它将用于任何玩家:计算机或人,控制台或gui,本地或网络。我也打算有一个GameController,它只会处理两个 IPlayer
秒。
IPlayer接口看起来像这样:
class IPlayer
{
public:
//dtor
virtual ~IPlayer()
{
}
//call this function before the game starts. In subclasses,
//the overriders can, for example, generate and store the combination.
virtual void PrepareForNewGame() = 0;
//make the current guess
virtual Combination MakeAGuess() = 0;
//return false if lie is detected.
virtual bool ProcessResult(Combination const &, Result const &) = 0;
//Answer to opponent's guess
virtual Result AnswerToOpponentsGuess(Combination const&) = 0;
};
GameController类会做这样的事情:
IPlayer* pPlayer1 = PlayerFactory::CreateHumanPlayer();
IPlayer* pPlayer1 = PlayerFactory::CreateCPUPlayer();
pPlayer1->PrepareForNewGame();
pPlayer2->PrepareForNewGame();
while(no_winner)
{
Guess g = pPlayer1->MakeAguess();
Result r = pPlayer2->AnswerToOpponentsGuess(g);
bool player2HasLied = ! pPlayer1->ProcessResult(g, r);
etc.
etc.
}
通过这种设计,我愿意让GameController类不可变,也就是说,我把游戏规则填入其中,而不是其他任何东西,所以既然游戏本身已经建立,那么这个类就不应该改变。对于控制台游戏,这种设计将完美地运作。我会 HumanPlayer
在其中 MakeAGuess
方法会读一个 Combination
从标准输入,和 CPUPlayer
,它会以某种方式随机生成它等。
现在这是我的问题: IPlayer
界面,以及 GameController
阶级,本质上是同步的。我无法想象如何用相同的方式实现游戏的GUI变体 GameController
当。。。的时候 MakeAGuess
的方法 GUIHumanPlayer
必须等待,例如,一些鼠标移动和点击。当然,我可以启动一个等待用户输入的新线程,而主线程会阻塞,以便模仿同步IO,但不知怎的,这个想法令我感到厌恶。或者,或者,我可以将控制器和播放器设计为异步。在这种情况下,对于控制台游戏,我将不得不模仿异步,这似乎比第一个版本更容易。
您是否愿意评论我的设计以及我对选择同步或异步设计的担忧?另外,我觉得我对玩家类的责任比GameController类更多。等等
非常感谢你提前。
附:我不喜欢我的问题的标题。随意编辑:)