diff --git a/Wpf_AiSportsMicrospace/MyUserControl/ImageStateToVisibilityConverter.cs b/Wpf_AiSportsMicrospace/MyUserControl/ImageStateToVisibilityConverter.cs index 0fc8476..ee4c005 100644 --- a/Wpf_AiSportsMicrospace/MyUserControl/ImageStateToVisibilityConverter.cs +++ b/Wpf_AiSportsMicrospace/MyUserControl/ImageStateToVisibilityConverter.cs @@ -2,6 +2,7 @@ using System; using System.Globalization; using System.Windows; using System.Windows.Data; +using System.Windows.Media.Animation; namespace Wpf_AiSportsMicrospace.MyUserControl { @@ -21,4 +22,137 @@ namespace Wpf_AiSportsMicrospace.MyUserControl throw new NotImplementedException(); } } + + public class MarginAnimationController + { + private Storyboard _storyboard; + private FrameworkElement _targetElement; + private ThicknessAnimation _thicknessAnimation; + + /// + /// 初始化动画控制器 + /// + /// 目标UI元素 + public MarginAnimationController(FrameworkElement targetElement) + { + _targetElement = targetElement; + InitializeAnimation(); + } + + private void InitializeAnimation() + { + // 创建厚度动画 + _thicknessAnimation = new ThicknessAnimation + { + Duration = TimeSpan.FromSeconds(1), + FillBehavior = FillBehavior.HoldEnd + }; + + // 创建故事板 + _storyboard = new Storyboard(); + _storyboard.Children.Add(_thicknessAnimation); + + // 设置目标属性和目标对象 + Storyboard.SetTarget(_thicknessAnimation, _targetElement); + Storyboard.SetTargetProperty(_thicknessAnimation, new PropertyPath(FrameworkElement.MarginProperty)); + } + + /// + /// 开始动画 + /// + /// 目标边距 + /// 动画时长(毫秒) + /// 缓动函数 + public void StartAnimation(Thickness targetMargin, int durationMs = 1000, IEasingFunction easingFunction = null) + { + // 设置动画参数 + _thicknessAnimation.To = targetMargin; + _thicknessAnimation.Duration = TimeSpan.FromMilliseconds(durationMs); + + if (easingFunction != null) + { + _thicknessAnimation.EasingFunction = easingFunction; + } + + // 开始动画 + _storyboard.Begin(); + } + + /// + /// 开始从当前值到目标值的动画 + /// + public void StartAnimationFromCurrent(Thickness targetMargin, int durationMs = 1000) + { + _thicknessAnimation.From = null; // 从当前值开始 + _thicknessAnimation.To = targetMargin; + _thicknessAnimation.Duration = TimeSpan.FromMilliseconds(durationMs); + + _storyboard.Begin(); + } + + /// + /// 开始从指定值到目标值的动画 + /// + public void StartAnimationFromTo(Thickness fromMargin, Thickness toMargin, int durationMs = 1000) + { + _thicknessAnimation.From = fromMargin; + _thicknessAnimation.To = toMargin; + _thicknessAnimation.Duration = TimeSpan.FromMilliseconds(durationMs); + + _storyboard.Begin(); + } + + /// + /// 停止动画 + /// + public void StopAnimation() + { + _storyboard.Stop(); + } + + /// + /// 暂停动画 + /// + public void PauseAnimation() + { + _storyboard.Pause(); + } + + /// + /// 恢复动画 + /// + public void ResumeAnimation() + { + _storyboard.Resume(); + } + + /// + /// 设置动画完成回调 + /// + public void SetCompletedCallback(EventHandler callback) + { + _storyboard.Completed += callback; + } + + /// + /// 移除动画完成回调 + /// + public void RemoveCompletedCallback(EventHandler callback) + { + _storyboard.Completed -= callback; + } + + /// + /// 检查动画是否正在运行 + /// + public bool IsAnimating => _storyboard.GetCurrentState() == ClockState.Active; + + /// + /// 设置缓动函数 + /// + public void SetEasingFunction(IEasingFunction easingFunction) + { + _thicknessAnimation.EasingFunction = easingFunction; + } + } } \ No newline at end of file diff --git a/Wpf_AiSportsMicrospace/MyUserControl/PopSilder.xaml b/Wpf_AiSportsMicrospace/MyUserControl/PopSilder.xaml new file mode 100644 index 0000000..def6c5c --- /dev/null +++ b/Wpf_AiSportsMicrospace/MyUserControl/PopSilder.xaml @@ -0,0 +1,39 @@ +锘 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Wpf_AiSportsMicrospace/MyUserControl/PopSilder.xaml.cs b/Wpf_AiSportsMicrospace/MyUserControl/PopSilder.xaml.cs new file mode 100644 index 0000000..be5490b --- /dev/null +++ b/Wpf_AiSportsMicrospace/MyUserControl/PopSilder.xaml.cs @@ -0,0 +1,230 @@ +锘縰sing HandyControl.Controls; +using SharpDX.Direct3D9; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Windows.Threading; +using WpfAnimatedGif; + +namespace Wpf_AiSportsMicrospace.MyUserControl +{ + /// + /// CoverFlowControl.xaml 鐨勪氦浜掗昏緫 + /// + /// ST + /// + public partial class PopSilder : UserControl + { + + private List _musicBeats = new List() + { + 0.545,1.09,1.635,2.18,2.725,3.27,3.815,4.36,4.905,5.45, + 5.995,6.54,7.085,7.63,8.175,8.72,9.265,9.81,10.355,10.9, + //11.445,11.99,12.535,13.08,13.625,14.17,14.715,15.26,15.805,16.35, + //16.895,17.44,17.985,18.53,19.075,19.62,20.165,20.71,21.255,21.8, + //22.345,22.89,23.435,23.98,24.525,25.07,25.615,26.16,26.705,27.25, + //27.795,28.34,28.885,29.43,29.975,30.52,31.065,31.61,32.155,32.7, + //33.245,33.79,34.335,34.88,35.425,35.97,36.515,37.06,37.605,38.15, + //38.695,39.24,39.785,40.33,40.875,41.42,41.965,42.51,43.055,43.6, + //44.145,44.69,45.235,45.78,46.325,46.87,47.415,47.96,48.505,49.05, + //49.595,50.14,50.685,51.23,51.775,52.32,52.865,53.41,53.955,54.5, + //55.045,55.59,56.135,56.68,57.225,57.77,58.315,58.86,59.405,59.95, + //60.495,61.04,61.585,62.13,62.675,63.22,63.765,64.31,64.855,65.4, + //65.945,66.49,67.035,67.58,68.125,68.67,69.215,69.76,70.305,70.85, + //71.395,71.94,72.485,73.03,73.575,74.12,74.665,75.21,75.755,76.3, + //76.845,77.39,77.935,78.48,79.025,79.57,80.115,80.66,81.205,81.75, + //82.295,82.84,83.385,83.93,84.475,85.02,85.565,86.11,86.655,87.2, + //87.745,88.29,88.835,89.38,89.925,90.47,91.015,91.56,92.105,92.65, + //93.195,93.74,94.285,94.83,95.375,95.92,96.465,97.01,97.555,98.1, + //98.645,99.19,99.735,100.28,100.825,101.37,101.915,102.46,103.005,103.55, + //104.095,104.64,105.185,105.73,106.275,106.82,107.365,107.91,108.455 + }; + private Storyboard _marginStoryboard; + private ThicknessAnimation _marginAnimation; + private TimedEventTrigger _trigger; + private bool _isMiss = true; + public bool IsMiss + { + get => _isMiss; + set + { + _isMiss = value; + } + } + public PopSilder() + { + InitializeComponent(); + double time = Math.Floor(_musicBeats[_musicBeats.Count - 1]); + double startMargin = _musicBeats[0] * 200; + ani.Margin = new Thickness(startMargin, 0, 0, 0); + for (int i = 1; i < _musicBeats.Count + 1; i++) + { + double width = i != _musicBeats.Count ? (_musicBeats[i] - _musicBeats[i - 1]) * 200 : 0; + var img = new Image + { + Width = 52, + Height = 50, + Source = new BitmapImage(new Uri("pack://application:,,,/Resources/Img/play_img/music_rope/point.png")), + }; + var grid = new StackPanel + { + Width = width, + Height = 5, + Background = new SolidColorBrush(Color.FromRgb(0, 0, 0)) + }; + + var StackPanel = new StackPanel { Orientation = Orientation.Horizontal }; + StackPanel.Children.Add(img); + StackPanel.Children.Add(grid); + ani.Children.Add(StackPanel); + } + } + + + private void InitializeMarginAnimation() + { + double time = Math.Floor(_musicBeats[_musicBeats.Count - 1]) + 1; + double startMargin = _musicBeats[0] * 200; + // 鍒涘缓鍘氬害鍔ㄧ敾 + _marginAnimation = new ThicknessAnimation + { + From = new Thickness(startMargin, 0, 0, 0), // 璧峰鍊 + To = new Thickness(-time * (200 + 52) - 350, 0, 0, 0), // 鐩爣鍊 + Duration = TimeSpan.FromSeconds(time), // time绉掓寔缁椂闂 + FillBehavior = FillBehavior.HoldEnd // 鍔ㄧ敾瀹屾垚鍚庝繚鎸佺姸鎬 + }; + Console.WriteLine("ani.Width:" + ani.Width); + // 鍒涘缓鏁呬簨鏉 + _marginStoryboard = new Storyboard(); + _marginStoryboard.Children.Add(_marginAnimation); + + // 璁剧疆鐩爣瀵硅薄鍜屽睘鎬 + Storyboard.SetTarget(_marginAnimation, ani); + Storyboard.SetTargetProperty(_marginAnimation, new PropertyPath(StackPanel.MarginProperty)); + + + _trigger = new TimedEventTrigger(_musicBeats); + _trigger.TimePointReached += OnTimePointReached; + } + + // 榧犳爣鐐瑰嚮浜嬩欢 - 寮濮嬪姩鐢 + private void ani_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e) + { + StartMarginAnimation(); + } + + public void StartMarginAnimation() + { + InitializeMarginAnimation(); + _marginStoryboard?.Begin(); + _trigger.Start(); + } + + public void StopMarginAnimation() + { + _marginStoryboard?.Stop(); + _trigger.Stop(); + } + + + private void OnTimePointReached(double timePoint) + { + Console.WriteLine($"瑙﹀彂鏃堕棿鐐: {timePoint}"); + if (_isMiss) + { + head_m.Visibility = Visibility.Visible; + //200ms鍚庨殣钘 + var hideTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(200) }; + hideTimer.Tick += (s, e) => + { + head_m.Visibility = Visibility.Hidden; + _isMiss = true; + hideTimer.Stop(); + }; + } + else + { + head_g.Visibility = Visibility.Visible; + //200ms鍚庨殣钘 + var hideTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(200) }; + hideTimer.Tick += (s, e) => + { + head_g.Visibility = Visibility.Hidden; + _isMiss = false; + hideTimer.Stop(); + }; + } + } + } + + public class TimedEventTrigger + { + private DispatcherTimer _timer; + private List _timePoints; + private int _currentIndex; + private DateTime _startTime; + + public TimedEventTrigger(List timePoints) + { + _timePoints = timePoints; + _currentIndex = 0; + + _timer = new DispatcherTimer(); + _timer.Interval = TimeSpan.FromMilliseconds(10); // 10ms绮惧害 + _timer.Tick += CheckTimePoint; + } + + public void Start() + { + _startTime = DateTime.Now; + _timer.Start(); + } + + public void Stop() + { + _timer.Stop(); + } + + private void CheckTimePoint(object sender, EventArgs e) + { + double elapsedSeconds = (DateTime.Now - _startTime).TotalSeconds; + + // 妫鏌ユ槸鍚﹀埌杈句笅涓涓椂闂寸偣 + if (_currentIndex < _timePoints.Count && + elapsedSeconds >= _timePoints[_currentIndex]) + { + // 瑙﹀彂浜嬩欢 + OnTimePointReached(_timePoints[_currentIndex]); + _currentIndex++; + } + + // 鎵鏈夋椂闂寸偣閮藉鐞嗗畬姣曪紝鍋滄璁℃椂鍣 + if (_currentIndex >= _timePoints.Count) + { + _timer.Stop(); + } + } + + public event Action TimePointReached; + + protected virtual void OnTimePointReached(double timePoint) + { + TimePointReached?.Invoke(timePoint); + } + } +} \ No newline at end of file diff --git a/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/great-p.png b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/great-p.png new file mode 100644 index 0000000..ee8e9d1 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/great-p.png differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/great.png b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/great.png new file mode 100644 index 0000000..975533b Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/great.png differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/head_g.png b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/head_g.png new file mode 100644 index 0000000..b7788b6 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/head_g.png differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/head_m.png b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/head_m.png new file mode 100644 index 0000000..5a2f009 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/head_m.png differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/miss.png b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/miss.png new file mode 100644 index 0000000..91ed76d Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/miss.png differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/play_bg.png b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/play_bg.png new file mode 100644 index 0000000..a464956 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/play_bg.png differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/point.png b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/point.png new file mode 100644 index 0000000..2dbebed Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/point.png differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/title.png b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/title.png new file mode 100644 index 0000000..0261698 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/title.png differ diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml index 52d3bf4..7b9d6a8 100644 --- a/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml @@ -8,14 +8,14 @@ Height="1080" Width="1920" Loaded="UserControl_Loaded" Unloaded="UserControl_Unloaded"> - + @@ -58,5 +58,23 @@ + + + diff --git a/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj b/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj index 50a781f..7b7877b 100644 --- a/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj +++ b/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj @@ -42,6 +42,14 @@ + + + + + + + + @@ -77,6 +85,24 @@ + + + Always + + + Always + + + Always + + + Always + + + Always + + + @@ -215,6 +241,15 @@ Always + + Always + + + Always + + + Always + Always