• 游戏人生Silverlight(2) 趣味钢琴[Silverlight 2.0(c#)]


    [索引页]
    [源码下载]


    游戏人生Silverlight(2) - 趣味钢琴[Silverlight 2.0(c#)]



    作者:webabcd


    介绍
    使用 Silverlight 2.0(c#) 开发一个趣味钢琴


    玩法
    打开音箱,从左侧列表选择要挑战的乐谱,右侧会出现对应的乐谱提示动画,等按键提示移动到目标区后敲击键盘上对应的按键


    在线DEMO
    Get Microsoft Silverlight


    思路
    1、添加多个MediaElement控件,循环使用,以达到同时播放多个音阶的效果
    2、提示按键模块分3组动画,分别为提示部分、目标部分和离开部分,进入目标区和离开目标区都要触发对应的事件,以使外部判断用户是否按照提示正确地敲击了按键


    关键代码
    1、钢琴音阶播放器
    ScalePlayer.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;

    namespace YYPiano.Controls.Parts
    {
        
    public partial class ScalePlayer : UserControl
        
    {
            
    // MediaElement 控件总数
            private int _count = 32;

            
    // MediaElement 控件集合的索引
            private int _index = 0;

            
    public ScalePlayer()
            
    {
                InitializeComponent();

                
    this.Loaded += new RoutedEventHandler(Player_Loaded);
            }


            
    void Player_Loaded(object sender, RoutedEventArgs e)
            
    {
                
    // 在 Canvas 上添加指定数量的 MediaElement 控件
                for (int i = 0; i < _count; i++)
                
    {
                    var element 
    = new MediaElement();
                    element.Volume 
    = 1d;

                    root.Children.Add(element);
                }

            }


            
    /// <summary>
            
    /// 播放音阶
            
    /// A 键对应 Scale 文件夹内的 A.mp3,以此类推
            
    /// A 键对应 C 大调的低音 dou,以此类推
            
    /// </summary>
            
    /// <param name="key">键值</param>

            public void Play(Key key)
            
    {
                
    if (key >= Key.A && key <= Key.Z)
                
    {
                    
    // 循环使用 MediaElement 控件集合中的控件
                    if (_index > _count - 1)
                        _index 
    = 0;

                    
    // 设置 MediaElement 的 Source 并播放
                    var element = root.Children[_index] as MediaElement;
                    element.Source 
    = new Uri("/YYPiano;component/Scale/" + key.ToString() + ".mp3", UriKind.Relative);
                    element.Stop();
                    element.Play();

                    _index
    ++;
                }

            }

        }

    }



    2、按键提示动画
    AnimationKey.xaml

    <UserControl x:Class="YYPiano.Controls.Parts.AnimationKey"
        xmlns
    ="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x
    ="http://schemas.microsoft.com/winfx/2006/xaml">
        
    <Canvas>
            
    <!--3个椭圆,目标区,按键动画进入该区域后敲击则为有效敲击-->
            
    <Ellipse x:Name="target" Width="80" Height="80" Stroke="#F80" Fill="Transparent" StrokeThickness="1" Canvas.Left="0" Canvas.Top="250" />
            
    <Ellipse x:Name="target2" Width="80" Height="80" Stroke="#F80" Fill="Transparent" StrokeThickness="1" Canvas.Left="120" Canvas.Top="250" />
            
    <Ellipse x:Name="target3" Width="80" Height="80" Stroke="#F80" Fill="Transparent" StrokeThickness="1" Canvas.Left="240" Canvas.Top="250" />

            
    <!--提示按键-->
            
    <Border x:Name="container" BorderBrush="Gray" BorderThickness="1" Width="50" Height="50" CornerRadius="50" Canvas.Left="135" RenderTransformOrigin="0.5, 0.5">
                
    <TextBlock x:Name="key" TextAlignment="Center" VerticalAlignment="Center" FontSize="40" FontWeight="Bold">
                
    </TextBlock>
                
    <Border.RenderTransform>
                    
    <TransformGroup>
                        
    <RotateTransform x:Name="rt" />
                        
    <TranslateTransform x:Name="tt" />
                        
    <ScaleTransform x:Name="st" ScaleX="0.3" ScaleY="0.3" />
                    
    </TransformGroup>
                
    </Border.RenderTransform>
            
    </Border>

            
    <Canvas.Resources>
                
    <!--主动画(缓冲提示)-->
                
    <Storyboard x:Name="mainAni" Completed="mainAni_Completed">
                    
    <!--坐标-->
                    
    <DoubleAnimation x:Name="targetX" From="0" To="0" Duration="0:0:4" Storyboard.TargetName="tt" Storyboard.TargetProperty="X" />
                    
    <DoubleAnimation From="0" To="250" Duration="0:0:4" Storyboard.TargetName="tt" Storyboard.TargetProperty="Y" />

                    
    <!--旋转-->
                    
    <DoubleAnimationUsingKeyFrames Storyboard.TargetName="rt" Storyboard.TargetProperty="Angle" RepeatBehavior="1x" >
                        
    <SplineDoubleKeyFrame Value="366" KeySpline="0.1,0 0.2,0.95" KeyTime="0:0:4" />
                    
    </DoubleAnimationUsingKeyFrames>

                    
    <!--缩放-->
                    
    <DoubleAnimationUsingKeyFrames Storyboard.TargetName="st" Storyboard.TargetProperty="ScaleX">
                        
    <SplineDoubleKeyFrame Value="1" KeySpline="0.1,0 0.3,0.8" KeyTime="0:0:4" />
                    
    </DoubleAnimationUsingKeyFrames>
                    
    <DoubleAnimationUsingKeyFrames Storyboard.TargetName="st" Storyboard.TargetProperty="ScaleY">
                        
    <SplineDoubleKeyFrame Value="1" KeySpline="0.1,0 0.3,0.8" KeyTime="0:0:4" />
                    
    </DoubleAnimationUsingKeyFrames>
                
    </Storyboard>

                
    <!--进入目标区后的动画-->
                
    <Storyboard x:Name="insideAni" Completed="insideAni_Completed" Duration="0:0:0.4">
                    
    <DoubleAnimation To="310" Storyboard.TargetName="tt" Storyboard.TargetProperty="Y" />
                
    </Storyboard>

                
    <!--离开目标区后的动画-->
                
    <Storyboard x:Name="outsideAni">
                    
    <DoubleAnimation To="400" Storyboard.TargetName="tt" Storyboard.TargetProperty="Y" />
                    
    <DoubleAnimation To="0" Storyboard.TargetName="container" Storyboard.TargetProperty="Opacity" />
                
    </Storyboard>
            
    </Canvas.Resources>
        
    </Canvas>
    </UserControl>


    AnimationKey.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;

    namespace YYPiano.Controls.Parts
    {
        
    public partial class AnimationKey : UserControl
        
    {
            
    public AnimationKey()
            
    {
                InitializeComponent();
            }


            
    /// <summary>
            
    /// 键值 A - Z,动画显示,用于提示用户应该敲什么键
            
    /// </summary>

            public Key Key
            
    {
                
    get return Convert.ToChar(key.Text).ToKey(); }
                
    set { key.Text = value.ToChar().ToString(); }
            }


            
    /// <summary>
            
    /// 开始动画
            
    /// </summary>

            public void Start()
            
    {
                mainAni.Begin();
            }


            
    /// <summary>
            
    /// 停止动画
            
    /// </summary>

            public void Stop()
            
    {
                mainAni.Stop();
                insideAni.Stop();
                outsideAni.Stop();
            }


            
    /// <summary>
            
    /// 动画开始时间
            
    /// </summary>

            public TimeSpan BeginTime
            
    {
                
    set { mainAni.BeginTime = value; }
            }


            
    private int _targetIndex;
            
    /// <summary>
            
    /// UI 上设置了 3 个目标区,设置键的动画最终要落到哪个区上
            
    /// </summary>

            public int TargetIndex
            
    {
                
    set
                
    {
                    
    if (value == 0)
                        targetX.To 
    = -120;
                    
    else if (value == 1)
                        targetX.To 
    = 0;
                    
    else if (value == 2)
                        targetX.To 
    = 120;
                    
    else
                        targetX.To 
    = 0;

                    _targetIndex 
    = value;
                }

            }


            
    /// <summary>
            
    /// 主动画完成后
            
    /// </summary>
            
    /// <param name="sender"></param>
            
    /// <param name="e"></param>

            private void mainAni_Completed(object sender, EventArgs e)
            
    {
                
    if (_targetIndex == 0)
                    target.Fill 
    = new SolidColorBrush(Colors.Orange);
                
    else if (_targetIndex == 1)
                    target2.Fill 
    = new SolidColorBrush(Colors.Orange);
                
    else if (_targetIndex == 2)
                    target3.Fill 
    = new SolidColorBrush(Colors.Orange);

                insideAni.Begin();

                OnInside();
            }


            
    /// <summary>
            
    /// 目标区动画完成后
            
    /// </summary>
            
    /// <param name="sender"></param>
            
    /// <param name="e"></param>

            private void insideAni_Completed(object sender, EventArgs e)
            
    {
                
    if (_targetIndex == 0)
                    target.Fill 
    = new SolidColorBrush(Colors.Transparent);
                
    else if (_targetIndex == 1)
                    target2.Fill 
    = new SolidColorBrush(Colors.Transparent);
                
    else if (_targetIndex == 2)
                    target3.Fill 
    = new SolidColorBrush(Colors.Transparent);

                outsideAni.Begin();

                OnOutside();
            }


            
    /// <summary>
            
    /// 动画进入目标区后的事件
            
    /// </summary>

            public event EventHandler<PianoKeyEventArgs> Inside;
            
    public void OnInside()
            
    {
                
    if (Inside != null)
                
    {
                    Inside(
    thisnew PianoKeyEventArgs() { Key = this.Key });
                }

            }


            
    /// <summary>
            
    /// 动画离开目标区后的事件
            
    /// </summary>

            public event EventHandler<PianoKeyEventArgs> Outside;
            
    public void OnOutside()
            
    {
                
    if (Outside != null)
                
    {
                    Outside(
    thisnew PianoKeyEventArgs() { Key = this.Key });
                }

            }

        }

    }



    3、乐谱提示动画
    AnimationMusicBook.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;

    using YYPiano.Controls.Parts;
    using System.Threading;

    namespace YYPiano.Controls
    {
        
    /// <summary>
        
    /// 乐谱动画
        
    /// </summary>

        public partial class AnimationMusicBook : UserControl
        
    {
            
    /// <summary>
            
    /// 当前进入到目标区域的按键集合(先进先出)
            
    /// </summary>

            private List<KeyHitModel> _currentKeys = new List<KeyHitModel>();

            
    public AnimationMusicBook()
            
    {
                InitializeComponent();
            }


            
    /// <summary>
            
    /// 启动乐谱动画
            
    /// </summary>
            
    /// <param name="code">乐谱编码</param>
            
    /// <returns>是否成功地启动了乐谱动画</returns>

            public bool Start(string code)
            
    {
                code 
    = code.ToUpper().Trim();

                
    // 清除已有的 AnimationKey 控件
                foreach (var c in root.Children)
                
    {
                    var ak 
    = c as AnimationKey;
                    ak.Stop();
                }

                root.Children.Clear();
                _currentKeys.Clear();

                
    // 把乐谱编码解析为乐谱实体类(用于描述乐谱的每一音阶)集合
                var musicBook = new List<MusicBookModel>();
                var countDelay 
    = 0;
                
    try
                
    {
                    
    foreach (var s in code.Split(','))
                    
    {
                        var delay 
    = int.Parse(s.Trim().Substring(1));
                        var key 
    = Convert.ToChar(s.Trim().Substring(01)).ToKey();

                        musicBook.Add(
    new MusicBookModel() { Length = countDelay, Key = key });

                        countDelay 
    += delay;
                    }

                }

                
    catch (Exception)
                
    {
                    
    return false;
                }


                
    // 在容器内放置相应的 AnimationKey 控件
                for (int i = 0; i < musicBook.Count; i++)
                
    {
                    AnimationKey key 
    = new AnimationKey();
                    key.TargetIndex 
    = i % 3;
                    key.Key 
    = musicBook[i].Key;
                    key.BeginTime 
    = TimeSpan.FromMilliseconds(musicBook[i].Length);
                    key.Inside 
    += new EventHandler<PianoKeyEventArgs>(key_Inside);
                    key.Outside 
    += new EventHandler<PianoKeyEventArgs>(key_Outside);
                    key.Start();

                    root.Children.Add(key);
                }


                
    return true;
            }


            
    /// <summary>
            
    /// 按键进入目标区
            
    /// </summary>
            
    /// <param name="sender"></param>
            
    /// <param name="e"></param>

            void key_Inside(object sender, PianoKeyEventArgs e)
            
    {
                _currentKeys.Add(
    new KeyHitModel { Key = e.Key, Hit = false });
            }


            
    /// <summary>
            
    /// 按键离开目标区
            
    /// </summary>
            
    /// <param name="sender"></param>
            
    /// <param name="e"></param>

            void key_Outside(object sender, PianoKeyEventArgs e)
            
    {
                
    // 获取此次离开目标区的按键(进入到目标区域的按键集合的第一个成员)
                var key = _currentKeys.First();

                
    if (!key.Hit)
                    OnLost();

                _currentKeys.RemoveAt(
    0);
            }


            
    /// <summary>
            
    /// 指定的键值被敲击后所执行的方法
            
    /// </summary>
            
    /// <param name="key">键值</param>

            public void Play(Key key)
            
    {
                
    if (key >= Key.A && key <= Key.Z && _currentKeys.Where(p => !p.Hit).Count() > 0)
                
    {
                    var validKey 
    = _currentKeys.Where(p => !p.Hit && p.Key == key).FirstOrDefault();
                    
    if (validKey != null)
                    
    {
                        OnScore();
                        validKey.Hit 
    = true;
                    }

                    
    else
                    
    {
                        OnLost();
                    }

                }

            }


            
    /// <summary>
            
    /// 按键敲击正确的事件
            
    /// </summary>

            public event EventHandler<EventArgs> Score;
            
    public void OnScore()
            
    {
                
    if (Score != null)
                
    {
                    Score(
    thisnew EventArgs());
                }

            }


            
    /// <summary>
            
    /// 按键敲击错误或未及时敲击的事件
            
    /// </summary>

            public event EventHandler<EventArgs> Lost;
            
    public void OnLost()
            
    {
                
    if (Lost != null)
                
    {
                    Lost(
    thisnew EventArgs());
                }

            }

        }

    }



    OK
    [源码下载]

  • 相关阅读:
    git小乌龟的使用
    C语言笔记(二):数据类型(基本数据类型)、类型转换(自动转换、强制转换)
    Edge Chromium 中如何始终允许运行 Flash 内容
    【DTOJ】2704:数字互换
    【DTOJ】2703:两个数的余数和商
    【DTOJ】1001:长方形周长和面积
    Linux_simpl shell-利用Shell脚本for循环输出系统中的用户及其Shell
    Linux_Centos7安装VNC实现远程桌面
    Linux_crontab参数表示的意思
    Docke部署nginx并配置nginx
  • 原文地址:https://www.cnblogs.com/webabcd/p/1391208.html
Copyright © 2020-2023  润新知