2017-01-03 223 views
0

我想在我的网格中创建一个动画。我有一个5x5的网格,每个网格显示一个按钮。在网格加载之后,其中一个按钮应随机地将其颜色更改为绿色。 1秒后该按钮应该变回,另一个应该将其颜色改变为绿色。网格动画(按钮颜色变化)

如果用户能够将此1秒钟他的鼠标(鼠标悬停)按钮应他的颜色变为红色,并保持红色内达到这个按钮。将他的颜色改为绿色的下一个按钮不应该是这个。

这应该是一个小游戏。我的问题是,实现这个游戏最简单的方法是什么?

请帮帮我!

<Page x:Class="LeapTest.Layout" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:local="clr-namespace:LeapTest" 
    mc:Ignorable="d" 
    d:DesignHeight="1050" d:DesignWidth="1000" 
    Title="Layout"> 

<Page.Resources> 
    <Style x:Key="pageTitle" TargetType="TextBlock"> 
     <Setter Property="Background" Value="DimGray"/> 
     <Setter Property="FontSize" Value="40"/> 
     <Setter Property="FontFamily" Value="Arial"/> 
     <Setter Property="TextAlignment" Value="Center"/> 
     <Setter Property="Padding" Value="0,5,0,5"/> 
    </Style> 

    <Style x:Key="Grid" TargetType="Grid"> 
     <Setter Property="Background" Value="White"/> 
    </Style> 

    <Style x:Key="Button" TargetType="Button"> 
     <Setter Property="Background" Value="White"/> 
     <Setter Property="BorderBrush" Value="Green"/> 
     <Setter Property="BorderThickness" Value="2"/> 
    </Style> 

</Page.Resources> 

<Grid Style="{StaticResource Grid}"> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="50" /> 
     <RowDefinition Height="200" /> 
     <RowDefinition Height="200" /> 
     <RowDefinition Height="200" /> 
     <RowDefinition Height="200" /> 
     <RowDefinition Height="200" /> 
    </Grid.RowDefinitions> 

    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="200" /> 
     <ColumnDefinition Width="200" /> 
     <ColumnDefinition Width="200" /> 
     <ColumnDefinition Width="200" /> 
     <ColumnDefinition Width="200" /> 
    </Grid.ColumnDefinitions> 

    <TextBlock Grid.Column="0" Grid.ColumnSpan="5" Style="{StaticResource pageTitle}"> LEAP Motion </TextBlock> 

    <Button Name ="BTN_0_0" Grid.Column="0" Grid.Row="1" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_0_1" Grid.Column="1" Grid.Row="1" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_0_2" Grid.Column="2" Grid.Row="1" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_0_3" Grid.Column="3" Grid.Row="1" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_0_4" Grid.Column="4" Grid.Row="1" Click="BTN_Click" Style="{StaticResource Button}"/> 

    <Button Name ="BTN_1_0" Grid.Column="0" Grid.Row="2" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_1_1" Grid.Column="1" Grid.Row="2" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_1_2" Grid.Column="2" Grid.Row="2" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_1_3" Grid.Column="3" Grid.Row="2" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_1_4" Grid.Column="4" Grid.Row="2" Click="BTN_Click" Style="{StaticResource Button}"/> 

    <Button Name ="BTN_2_0" Grid.Column="0" Grid.Row="3" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_2_1" Grid.Column="1" Grid.Row="3" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_2_2" Grid.Column="2" Grid.Row="3" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_2_3" Grid.Column="3" Grid.Row="3" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_2_4" Grid.Column="4" Grid.Row="3" Click="BTN_Click" Style="{StaticResource Button}"/> 

    <Button Name ="BTN_3_0" Grid.Column="0" Grid.Row="4" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_3_1" Grid.Column="1" Grid.Row="4" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_3_2" Grid.Column="2" Grid.Row="4" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_3_3" Grid.Column="3" Grid.Row="4" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_3_4" Grid.Column="4" Grid.Row="4" Click="BTN_Click" Style="{StaticResource Button}"/> 

    <Button Name ="BTN_4_0" Grid.Column="0" Grid.Row="5" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_4_1" Grid.Column="1" Grid.Row="5" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_4_2" Grid.Column="2" Grid.Row="5" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_4_3" Grid.Column="3" Grid.Row="5" Click="BTN_Click" Style="{StaticResource Button}"/> 
    <Button Name ="BTN_4_4" Grid.Column="4" Grid.Row="5" Click="BTN_Click" Style="{StaticResource Button}"/> 

</Grid> 

//BackEnd Code 
     private void BTN_Click(object sender, RoutedEventArgs e) 
    { 
     //BTN1.Background = Brushes.Green; 

     Button btnTest = (Button)sender; 
     if (btnTest.Background == Brushes.Green) 
     { 
      btnTest.Background = Brushes.White; 
     } 
     else 
     { 
      btnTest.Background = Brushes.Green; 
     } 
    } 
+0

什么你的代码是后端吗?你试过了什么? –

+0

后端代码确实很有趣,你也可以用模板创建你的网格/按钮(绑定到值或简单模型的支持列表),它应该清理你的代码 – Staeff

+0

我使用Visual Studio进行编程,我已经尝试使用故事板......但由于不同的原因而失败。其中之一是我不知道如何在没有鼠标事件的情况下开始动画 –

回答

0

你应该遍历一个特殊的名称或标记的形式上的所有按钮控件。将其保存在数组中,随机选择一个并更改其颜色。如果鼠标悬停找到具有正确颜色的那个,则可以调用随机查找控件的方法等等。

这应该是相当直截了当。因为这看起来像功课。我不会为你解决它,因为你不会学到任何东西。想想需要做些什么,并分别在各个部分中进行谷歌搜索。尝试了解它,然后继续!祝你好运!

0

编辑:关于在严格的方式你的问题,你不需要动画acheive你想做的事,除非你需要的是动画颜色变化是什么。

这里是一个完整的工作示例不使用MVVM但使用代表按钮的模型集合。

主窗口/页代码处理所有的逻辑(随机,模型的变化,等):

public partial class MainWindow : Window, INotifyPropertyChanged 
{ 
    private const int BTN_NUMBERS = 25; 
    private ObservableCollection<ButtonModel> _buttonsCollection; 
    private ButtonModel _currentTarget; 

    public ObservableCollection<int> ExcludedItems 
    { 
     get { return _excludedItems; } 
     private set { _excludedItems = value; OnPropertyChanged(); } 
    } 

    private Random _rnd; 
    private Timer _timer; 
    private ObservableCollection<int> _excludedItems = new ObservableCollection<int>(); 

    public MainWindow() 
    { 
     DataContext = this; 

     InitializeComponent(); 
     ButtonsCollection = new ObservableCollection<ButtonModel>(); 
     for (int i = 0; i < BTN_NUMBERS; i++) 
     { 
      ButtonsCollection.Add(new ButtonModel() { ButtonNumber = i }); 
     } 

     Start(); 
    } 

    private void Start() 
    { 
     _currentTarget = null; 
     foreach (var bm in ButtonsCollection) 
     { 
      bm.IsCurrentTarget = bm.IsReached = false; 
     } 
     ExcludedItems.Clear(); 
     _rnd = new Random(DateTime.Now.Second); 
     _timer = new Timer(OnTargetChanged, null, 0, 1000); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    public ObservableCollection<ButtonModel> ButtonsCollection 
    { 
     get { return _buttonsCollection; } 
     set { _buttonsCollection = value; OnPropertyChanged(); } 
    } 

    void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    private void Btn_candidate_OnMouseEnter(object sender, MouseEventArgs e) 
    { 
     ButtonModel model = ((Button)sender).DataContext as ButtonModel; 
     if (model != null && model.IsCurrentTarget && !ExcludedItems.Contains(model.ButtonNumber)) 
     { 
      model.IsReached = true; 
      ExcludedItems.Add(model.ButtonNumber); 
     } 
    } 

    private void ChangeTarget() 
    { 
     var target = GetNextTarget(); 
     if (target == -1) 
     { 

      if (_timer != null) 
      { 
       _timer.Dispose(); 
       _timer = null; 
      } 
      MessageBox.Show("All items have been reached ! Congratulations"); 
     } 
     if (_currentTarget != null) _currentTarget.IsCurrentTarget = false; 
     _currentTarget = ButtonsCollection[target]; 
     _currentTarget.IsCurrentTarget = true; 
    } 

    private int GetNextTarget() 
    { 
     if (ExcludedItems.Count == BTN_NUMBERS) 
     { 
      return -1; 
     } 
     var target = _rnd.Next(0, BTN_NUMBERS); 
     if (ExcludedItems.Contains(target)) 
     { 
      return GetNextTarget(); 
     } 
     return target; 
    } 

    private void OnTargetChanged(object state) 
    { 
     this.Dispatcher.InvokeAsync(ChangeTarget); 
    } 

    private void Btn_startover_OnClick(object sender, RoutedEventArgs e) 
    { 
     Start(); 
    } 
} 

表示的按钮的模式,即包含触发XAML变化的代码:

public class ButtonModel : INotifyPropertyChanged 
{ 
    private bool _isCurrentTarget; 
    private bool _isReached; 

    public event PropertyChangedEventHandler PropertyChanged; 

    public int ButtonNumber { get; set; } 

    public bool IsCurrentTarget 
    { 
     get { return _isCurrentTarget; } 
     set { _isCurrentTarget = value; OnPropertyChanged(); } 
    } 

    public bool IsReached 
    { 
     get { return _isReached; } 
     set { _isReached = value; OnPropertyChanged(); } 
    } 

    private void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

最后,也是最重要的,简化的XAML代码:

<Window x:Class="GridAnimame.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:GridAnimame" 
    mc:Ignorable="d" 
    d:DataContext="{d:DesignInstance {x:Type local:MainWindow}}" 
    Title="MainWindow" Height="500" Width="500"> 
<Grid> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="400"/> 
     <ColumnDefinition/> 
    </Grid.ColumnDefinitions> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="400"/> 
     <RowDefinition/> 
    </Grid.RowDefinitions> 
    <ItemsControl ItemsSource="{Binding ButtonsCollection}"> 
     <ItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
       <UniformGrid /> 
      </ItemsPanelTemplate> 
     </ItemsControl.ItemsPanel> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <Button Name="btn_candidate" MouseEnter="Btn_candidate_OnMouseEnter" Margin="1"> 
        <Button.Template> 
         <ControlTemplate TargetType="Button"> 
          <Border x:Name="brd_btn_layout" Background="LightGray" BorderBrush="Black" BorderThickness="1"> 
           <TextBlock Text="{Binding ButtonNumber}" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Black"></TextBlock> 
          </Border> 
          <ControlTemplate.Triggers> 
           <DataTrigger Binding="{Binding IsCurrentTarget}" Value="true"> 
            <Setter TargetName="brd_btn_layout" Property="Background" Value="Green"></Setter> 
           </DataTrigger> 
           <DataTrigger Binding="{Binding IsReached}" Value="true"> 
            <Setter TargetName="brd_btn_layout" Property="Background" Value="Red"></Setter> 
           </DataTrigger> 
          </ControlTemplate.Triggers> 
         </ControlTemplate> 
        </Button.Template> 
       </Button> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 

    <ListBox Grid.Row="0" Grid.Column="1" ItemsSource="{Binding ExcludedItems}"></ListBox> 

    <Button x:Name="btn_startover" Grid.Row="1" Grid.Column="1" Content="Start Over !" Margin="2" Click="Btn_startover_OnClick"></Button> 
</Grid> 

Althought逻辑可以改进,下面是这个样的关键点:

  • 不声明在XAML中静态的方式,所有的按钮。相反,你的主模型认为代表在按钮和包含所有将触发XAML(视觉)变化的数据模型的集合。因此,在XAML表示网格中的控制被绑定到该集合

  • 逻辑由throught代码和这个loggic的视觉效果使用XAML

  • 只有2东西声明触发器被反射还是要做有一个干净的方法:1)主窗口的逻辑,现在可以很容易地被封装到一个真正的视图模型将作为窗口数据上下文和2)事件应该由DelegateCommands更换