我想創建一個非常簡單的遊戲Simon與WiiMote,使用WPF。我堅持的是如何使它基於轉向,程序阻塞,直到GUI完成顯示一個序列。C# - 如何阻止GUI或事件
這裏是我迄今(主要是基於一個答案在這裏:WPF - sequential animation simple example):代碼
public partial class Window1 : Window
{
public enum SimonSquare { BLUE = 1, GREEN = 3, RED = 5, YELLOW = 7 };
List<int> _correctSequence;
int _currentLevel = 1;
Random random = new Random();
Wiimote _wiiMote;
List<int> _squaresEntered;
private IEnumerator<Action> _actions;
Rectangle blueRect;
Rectangle redRect;
Rectangle greenRect;
Rectangle yellowRect;
AutoResetEvent autoEvent;
public Window1()
{
InitializeComponent();
blueRect = new Rectangle() { Fill =
System.Windows.Media.Brushes.Blue, Name = "Blue"};
redRect = new Rectangle() { Fill =
System.Windows.Media.Brushes.Red, Name = "Red" };
greenRect = new Rectangle() { Fill =
System.Windows.Media.Brushes.Green, Name = "Green" };
yellowRect = new Rectangle() { Fill =
System.Windows.Media.Brushes.Yellow, Name = "Yellow" };
UniformGrid1.Children.Add(new Rectangle() { Fill =
System.Windows.Media.Brushes.LightGray });
UniformGrid1.Children.Add(blueRect);
UniformGrid1.Children.Add(new Rectangle() { Fill =
System.Windows.Media.Brushes.LightGray });
UniformGrid1.Children.Add(redRect);
UniformGrid1.Children.Add(new Rectangle() { Fill =
System.Windows.Media.Brushes.LightGray });
UniformGrid1.Children.Add(greenRect);
UniformGrid1.Children.Add(new Rectangle() { Fill =
System.Windows.Media.Brushes.LightGray });
UniformGrid1.Children.Add(yellowRect);
UniformGrid1.Children.Add(new Rectangle() { Fill =
System.Windows.Media.Brushes.LightGray });
//connectWiiRemote();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_actions = AnimationSequence().GetEnumerator();
autoEvent = new AutoResetEvent(false);
Thread thread = new Thread(RunNextAction);
thread.Start();
autoEvent.WaitOne(); // need to block here somehow!
int x = 5;
}
IEnumerable<Action> AnimationSequence()
{
getSequence();
foreach(int square in _correctSequence)
{
if(square == (int) SimonSquare.BLUE)
yield return() => animateCell(blueRect, Colors.Blue);
else if(square == (int) SimonSquare.RED)
yield return() => animateCell(redRect, Colors.Red);
else if (square == (int)SimonSquare.GREEN)
yield return() => animateCell(greenRect, Colors.Green);
else if (square == (int)SimonSquare.YELLOW)
yield return() => animateCell(yellowRect, Colors.Yellow);
}
}
private void animateCell(Rectangle rectangle, Color fromColor)
{
this.Dispatcher.BeginInvoke(new Action(delegate
{
Color toColor = Colors.White;
ColorAnimation ani = new ColorAnimation(toColor,
new Duration(TimeSpan.FromMilliseconds(300)));
ani.AutoReverse = true;
SolidColorBrush newBrush = new SolidColorBrush(fromColor);
ani.BeginTime = TimeSpan.FromSeconds(2);
rectangle.Fill = newBrush;
ani.Completed += (s, e) => RunNextAction();
newBrush.BeginAnimation(SolidColorBrush.ColorProperty, ani);
}));
}
private void RunNextAction()
{
if (_actions.MoveNext())
_actions.Current();
else
{
autoEvent.Set();
_currentLevel++;
}
}
private void getSequence()
{
_correctSequence = new List<int>();
int[] values =
Enum.GetValues(typeof(SimonSquare)).Cast<int>().ToArray();
for (int i = 0; i < _currentLevel + 2; i++)
{
_correctSequence.Add(values[random.Next(values.Length)]);
}
}
}
然而,因爲自動設置的了WaitOne /組無法正常工作。它目前調用RunNextAction一次,但是無限期地阻塞waitOne。我究竟做錯了什麼?
編輯: 讓我試着重述這個問題。如果我拿出線程和的AutoResetEvent,在Window_Loaded我:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_actions = AnimationSequence().GetEnumerator();
RunNextAction(); // shows all of the flashing squares
// need to wait here until the flashing squares are all shown
// process player's events etc.
}
當我運行上面的代碼,它會調用一次RunNextAction,這將讓自稱,直到所有的方塊都顯示(似乎就像它自己的線程一樣),但WindowLoaded方法繼續下去。在我調用RunNextAction()之後,我需要Window_Loaded阻塞,直到RunNextAction完成。
你的意思是說你想要輸入在播放動畫時不被接受? – RCIX 2009-10-03 00:43:23
@RCIX是的,有點。由於RunActionOnce是遞歸類型的,我需要最後一次調用它(即顯示最後一個方塊)來通知調用者(Window_Loaded),以便它可以處理玩家的動作。 – 2009-10-03 01:08:59