2014-02-21 80 views
0

我正在制作一个Hangman Windows Forms应用程序,到目前为止它已经很好地发展了,逻辑在那里,但是我在GUI同步方面遇到了一个小问题。在更新我的GUI时遇到了一些问题

现在我显示来自GameForm.cs这反过来实例化一个单独的线程名为GameRound类的UI,现在的问题是怎么样的怪,游戏回合环路工程,问题是,它不更新UI元素(在这种情况下,显示hangman的picturebox,显示隐藏的单词的文本框和显示已猜测字符的标签),而不是在循环的每次迭代后更新。但是我注意到,如果我在循环中插入MessageBox.Show(),那么当消息框被调用时它们将被更新。

我猜这是某种线程同步问题,在Gameround线程正在工作时窗体不想更新,或者其他什么,但我是一个完整的开发者程序员,所以我需要一些帮助!

下面的代码到游戏回合(Gameround.Start())

public void Start() 
    { 
     Hangman hangman = new Hangman(); 
     do 
     { 
      //Check if hangman is dead first 
      if (hangman.HangmanStep == 6) { 
       MessageBox.Show("You got hanged! RIP"); 
       complete = true; } 

      bool w_reduceSticks = new bool(); 
      string output = WordBuilder.ObscureWord(word); 

      HangManBox.Image = Drawing.Drawer.DrawHangMan(hangman.HangmanStep); 

      WordBox.Text = output; 
      GuessedLetters.Text = ReturnGuessedLetters(incorrectGuesses); 
      MessageBox.Show(""); 

      //After guessing check if we've guessed all letters in the word 
      if (CompareLists(word.dontObscure, word.letters.Distinct().ToList())) 
      { 
       System.Threading.Thread.Sleep(5000); 
       complete = true; 
       break; 
      } 

      Thread readKeyThread = new Thread(InitReadKeyForm); 
      readKeyThread.Start(); 
      readKeyThread.Join(); 

      if (ReadKeyForm.Key == 2) { 
       w_reduceSticks = GuessWord(); 
      } 
      else { 
       w_reduceSticks = GuessLetters(ReadKeyForm.Key); 
      } 

      if (w_reduceSticks) 
      { 
       hangman.HangmanStep++; 
      } 
     } while (!complete); 
+0

由于'Thread.Sleep(2000);'后面的'break',你的代码的下半部分是不可访问的。但那是另一个问题。 –

+0

对,这只是我调试一些东西,我会编辑。 –

回答

0

为什么你认为这是在一个单独的线程中运行?通过所有迹象,它显然是在UI线程上运行(而不是从UI线程外部修改UI元素)。这也是为什么MessageBox.Show“帮助”。 Application.DoEvents也会这样做。

在任何情况下,问题的核心是,你不是在一个单独的线程中实际运行它。向我们展示您用于“启动新线程”的代码。

+0

你是对的,它不是一个单独的线程,我从游戏形式的同一线程调用它。如果我将它与另一个线程分开,我将不得不修改我的代码,或者找到一种更简单的方法从游戏轮回线程更新UI元素。 –

+0

@OverlyExcessive这其实很简单 - 你可以使用Control。Invoke'排队代码以在最接近的便利处在UI线程上运行:)所以,做所有的工作和逻辑,以及何时需要更新UI,只需“调用”代码即可。此外,如果您有权访问.NET 4.5.1,则可能需要使用'await' /'async',这对于不受CPU绑定的异步代码来说非常棒(在您的情况中,唯一的阻塞是等待密钥(I/O绑定)和'Thread.Sleep'(一个坏主意) – Luaan

+0

'Control.Invoke'完美谢谢!:) –

0

随着人们建议,您的UI线程不正确更新的原因是因为它没有得到优先这样做在游戏线程中执行代码后执行。 这可以通过添加Application.DoEvents()(它会告诉系统几乎让其他人也工作)或使用Lock对象来同步两个线程来解决。作为一个方面说明,因为我也开始阅读游戏编程,所以看起来,实现游戏的正确方法(至少到达严肃游戏的地步,我不知道发生了什么)是沿着这些线:

while (!finished){ 
    ProcessInputs(); 
    DoCalculations(); 
    DrawScreen(); 
} 

所以看来,在这些类型的应用程序,它都在同一个线程完成。它很有意义,因为它不像商业程序,你可以发送一个SQL查询,而且你不关心它向用户显示结果需要多长时间。在游戏中,你必须对用户的行为有即时的反馈。
希望我帮了

+0

大多数游戏仍然主要是单线程的原因是多大程度上要做出一个好的多线程多线程游戏引擎。 60 FPS意味着您只有16 ms来处理每个帧,并且同步不同的线程,特别是在该时间范围内,是非常棘手的。在其他软件中工作的方法通常是不可用的(不可变对于并行化非常棒,但在低延迟情况下通常无法承受这些开销)。您的示例(SQL查询)实际上并不相关,因为这是经典的I/O绑定操作 - 您可以在同一个线程上使用'async'处理。 – Luaan

相关问题