diff --git a/Wpf_AiSportsMicrospace/Dto/GroupJumpRopeContext.cs b/Wpf_AiSportsMicrospace/Dto/GroupJumpRopeContext.cs index 3a6e077..a396dd7 100644 --- a/Wpf_AiSportsMicrospace/Dto/GroupJumpRopeContext.cs +++ b/Wpf_AiSportsMicrospace/Dto/GroupJumpRopeContext.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; using System.Drawing; +using System.Runtime.CompilerServices; using System.Text; using Wpf_AiSportsMicrospace.MyUserControl; using Yztob.AiSports.Postures.Sports; @@ -10,7 +13,7 @@ namespace Dto public class GroupJumpRopeContext { // 静态字段,保存排名列表 - public static List RankList { get; set; } = new List(); + //public static List RankList { get; set; } = new List(); public List<(double XNorm, double YNorm)> CirclePositions { get; private set; } public List UserList { get; private set; } public List UserNumberList { get; private set; } @@ -38,23 +41,25 @@ namespace Dto } // 更新排行榜方法 - public void UpdateRankList() + public List UpdateRankList() { - RankList = UserNumberList - .Select((numStr, index) => new - { - Index = index, - Name = UseNameList[index], - Number = int.TryParse(numStr, out var n) ? n : 0 - }) - .OrderByDescending(x => x.Number) - .Select((x, rank) => new RankItem - { - Rank = rank + 1, - Name = x.Name, - Number = x.Number - }) - .ToList(); + var rankList = UserNumberList + .Select((numStr, index) => new + { + Index = index, + Name = UseNameList[index], + Number = int.TryParse(numStr, out var n) ? n : 0 + }) + .OrderByDescending(x => x.Number) + .Select((x, rank) => new RankItem + { + Rank = rank + 1, + Name = x.Name, + Number = x.Number + }) + .ToList(); + + return rankList; } } @@ -65,4 +70,5 @@ namespace Dto public string Name { get; set; } public int Number { get; set; } } + } diff --git a/Wpf_AiSportsMicrospace/Resources/Img/gif/bottom_animation_image.png b/Wpf_AiSportsMicrospace/Resources/Img/gif/bottom_animation_image.png new file mode 100644 index 0000000..eeb9275 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/gif/bottom_animation_image.png differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/gif/top_animation_image.png b/Wpf_AiSportsMicrospace/Resources/Img/gif/top_animation_image.png new file mode 100644 index 0000000..5ec8c1f Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/gif/top_animation_image.png differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/1.png b/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/1.png new file mode 100644 index 0000000..28b19aa Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/1.png differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/2.png b/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/2.png new file mode 100644 index 0000000..ca5b56e Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/2.png differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/3.png b/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/3.png new file mode 100644 index 0000000..a7e9760 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/3.png differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/finish_bg.png b/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/finish_bg.png new file mode 100644 index 0000000..38291f9 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/finish_bg.png differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/star.png b/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/star.png new file mode 100644 index 0000000..c9103a7 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/star.png differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/top.png b/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/top.png new file mode 100644 index 0000000..96f1d48 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/test_img/one_rope/finish_img/top.png differ diff --git a/Wpf_AiSportsMicrospace/Views/Home.xaml.cs b/Wpf_AiSportsMicrospace/Views/Home.xaml.cs index 5d25b75..87d334e 100644 --- a/Wpf_AiSportsMicrospace/Views/Home.xaml.cs +++ b/Wpf_AiSportsMicrospace/Views/Home.xaml.cs @@ -106,6 +106,8 @@ namespace Wpf_AiSportsMicrospace // 停止抽帧线程/释放资源 try { + //_mainWin.HumanFrameUpdated -= OnHumanFrameUpdated; + //_mainWin.WebcamClient.StopExtract(); RouterGoNew(); } catch (Exception ex) @@ -128,12 +130,12 @@ namespace Wpf_AiSportsMicrospace if (coverFlow.SelectedIndex == 0) { var newPage = new GroupJumpRope(); - mainWin?.SwitchPage(newPage, true); + mainWin?.SwitchPageWithMaskAnimation(newPage, true); } else { var newPage = new MusicJumpRope(); - mainWin?.SwitchPage(newPage, true); + mainWin?.SwitchPageWithMaskAnimation(newPage, true); } } @@ -147,12 +149,12 @@ namespace Wpf_AiSportsMicrospace if (coverFlow.SelectedIndex == 0) { var newPage = new GroupJumpRope(); - mainWin?.SwitchPage(newPage, true); + mainWin?.SwitchPageWithMaskAnimation(newPage, true); } else { var newPage = new MusicJumpRope(); - mainWin?.SwitchPage(newPage, true); + mainWin?.SwitchPageWithMaskAnimation(newPage, true); } } } diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml index 658dfdd..90a1517 100644 --- a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml @@ -32,5 +32,111 @@ TextAlignment="Center" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs index acdd30d..ad54860 100644 --- a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs @@ -5,9 +5,12 @@ using SharpDX.Direct3D9; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; using System.Globalization; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using System.Windows; @@ -44,6 +47,13 @@ namespace Wpf_AiSportsMicrospace.Views { private Main _mainWin => Application.Current.MainWindow as Main; private MediaPlayer _mediaPlayer = new MediaPlayer(); + List RankingItemList = new(); + + public event PropertyChangedEventHandler PropertyChanged; + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } private bool IsGameStarted = false; private readonly object _updateLock = new object(); private readonly Dictionary _jumpStatus = new Dictionary(); @@ -88,7 +98,7 @@ namespace Wpf_AiSportsMicrospace.Views // 监听播放完成事件 _mediaPlayer.MediaEnded += MediaPlayer_MediaEnded; - + //_mainWin.WebcamClient.StartExtract(); _mediaPlayer.Play(); } private void ShowCenterTip(string imagePath, TimeSpan duration) @@ -261,8 +271,8 @@ namespace Wpf_AiSportsMicrospace.Views x.ImageState = "1"; }); - _groupJumpRopeContext.UpdateRankList(); - + RankingItemList = _groupJumpRopeContext.UpdateRankList(); + ShowRankingBoard(RankingItemList); IsGameStarted = false; Utils.StopBackgroundMusic(); } @@ -507,5 +517,87 @@ namespace Wpf_AiSportsMicrospace.Views _groupJumpRopeContext.UserNumberList.Add("0"); return userItem; // } + + public void ShowRankingBoard(List list) + { + var scoreGrid = FindName("ScoreGrid") as Grid; + name1.Text = list[0].Name; + name2.Text = list[1].Name; + name3.Text = list[2].Name; + number1.Text = list[0].Number.ToString(); + number2.Text = list[1].Number.ToString(); + number3.Text = list[2].Number.ToString(); + foreach (var item in list) + { + var grid = new Grid { + Width = 1344, + Height = 71, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Top, + Margin = new Thickness(0, 57 * item.Rank, 0, 0) + }; + var border = new Border + { + Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#fff")) + }; + grid.Children.Add(border); + var rankText = new TextBlock + { + Text = item.Rank.ToString(), + FontSize = 24, + FontWeight = FontWeights.Bold, + Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#999999")), + HorizontalAlignment = HorizontalAlignment.Left, + VerticalAlignment = VerticalAlignment.Center, + TextAlignment= TextAlignment.Center, + Width=200 + }; + grid.Children.Add(rankText); + + var positionText = new TextBlock + { + Text = item.Name, + FontSize = 24, + FontWeight = FontWeights.Bold, + Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#999999")), + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center + }; + grid.Children.Add(positionText); + + var scoreText = new TextBlock + { + Text = item.Number.ToString(), + FontSize = 24, + FontWeight = FontWeights.Bold, + Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#999999")), + HorizontalAlignment = HorizontalAlignment.Right, + VerticalAlignment = VerticalAlignment.Center, + TextAlignment = TextAlignment.Center, + Width = 200 + }; + grid.Children.Add(scoreText); + ScoreGrid.Children.Add(grid); + } + + var rankingGrid = FindName("RankingGrid") as Grid; + if (rankingGrid == null) return; + + rankingGrid.Visibility = Visibility.Visible; + var fadeIn = new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(600)); + rankingGrid.BeginAnimation(UIElement.OpacityProperty, fadeIn); + } + + // 控制排行榜隐藏(渐隐动画) + public void HideRankingBoard() + { + var rankingGrid = FindName("RankingGrid") as Grid; + if (rankingGrid == null) return; + + var fadeOut = new DoubleAnimation(1, 0, TimeSpan.FromMilliseconds(600)); + fadeOut.Completed += (s, e) => rankingGrid.Visibility = Visibility.Collapsed; + rankingGrid.BeginAnimation(UIElement.OpacityProperty, fadeOut); + } + } } diff --git a/Wpf_AiSportsMicrospace/Views/Main.xaml.cs b/Wpf_AiSportsMicrospace/Views/Main.xaml.cs index 44723f7..660da53 100644 --- a/Wpf_AiSportsMicrospace/Views/Main.xaml.cs +++ b/Wpf_AiSportsMicrospace/Views/Main.xaml.cs @@ -261,6 +261,89 @@ namespace Wpf_AiSportsMicrospace.Views newPage.BeginAnimation(OpacityProperty, fadeAnim); } + public void SwitchPageWithMaskAnimation(UserControl newPage, bool fromRight, double durationSeconds = 1.2) + { + if (MainContent.Content == newPage) return; + var oldPage = MainContent.Content as UserControl; + PreloadPageResources(newPage); + + // 每次都创建新的 Image 实例 + var maskTop = new Image + { + Source = new BitmapImage(new Uri("/Resources/Img/gif/top_animation_image.png", UriKind.Relative)), + Stretch = Stretch.Fill, + HorizontalAlignment = HorizontalAlignment.Stretch, + VerticalAlignment = VerticalAlignment.Top, + Width = 1920, + Height = 1000 + }; + var maskBottom = new Image + { + Source = new BitmapImage(new Uri("/Resources/Img/gif/bottom_animation_image.png", UriKind.Relative)), + Stretch = Stretch.Fill, + HorizontalAlignment = HorizontalAlignment.Stretch, + VerticalAlignment = VerticalAlignment.Bottom, + Width = 1920, + Height = 1000 + }; + + var maskGrid = new Grid { Background = Brushes.Transparent, Width = 1920, Height = 1080 }; + maskGrid.Children.Add(maskTop); + maskGrid.Children.Add(maskBottom); + + if (MainContent.Parent is Grid parentGrid) + { + parentGrid.Children.Add(maskGrid); + Grid.SetZIndex(maskGrid, 9999); + } + else + { + var win = Window.GetWindow(this); + if (win != null && win.Content is Grid winGrid) + { + winGrid.Children.Add(maskGrid); + Grid.SetZIndex(maskGrid, 9999); + } + } + + double height = ActualHeight; + double maskHeight = 1000; + //double maskHeight = height / 2 - 150; + + //maskTop.Height = maskHeight; + //maskBottom.Height = maskHeight; + + maskTop.RenderTransform = new TranslateTransform(0, -maskHeight); + maskBottom.RenderTransform = new TranslateTransform(0, maskHeight); + + var duration = TimeSpan.FromSeconds(durationSeconds); + var ease = new CubicEase { EasingMode = EasingMode.EaseInOut }; + + var topInAnim = new DoubleAnimation(-maskHeight, 0, duration) { EasingFunction = ease }; + var bottomInAnim = new DoubleAnimation(maskHeight, 0, duration) { EasingFunction = ease }; + //var topOutAnim = new DoubleAnimation(0, maskHeight, duration) { EasingFunction = ease }; + //var bottomOutAnim = new DoubleAnimation(0, -maskHeight, duration) { EasingFunction = ease }; + var bottomOutAnim = new DoubleAnimation(0, maskHeight, duration) { EasingFunction = ease }; + var topOutAnim = new DoubleAnimation(0, -maskHeight, duration) { EasingFunction = ease }; + + topInAnim.Completed += (s, e) => + { + MainContent.Content = newPage; + maskTop.RenderTransform.BeginAnimation(TranslateTransform.YProperty, topOutAnim); + maskBottom.RenderTransform.BeginAnimation(TranslateTransform.YProperty, bottomOutAnim); + }; + + topOutAnim.Completed += (s, e) => + { + if (maskGrid.Parent is Grid grid) + grid.Children.Remove(maskGrid); + if (oldPage is IDisposable disposable) + disposable.Dispose(); + }; + + maskTop.RenderTransform.BeginAnimation(TranslateTransform.YProperty, topInAnim); + maskBottom.RenderTransform.BeginAnimation(TranslateTransform.YProperty, bottomInAnim); + } } } \ No newline at end of file diff --git a/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj b/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj index 3261e1b..f21a327 100644 --- a/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj +++ b/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj @@ -39,11 +39,19 @@ + + + + + + + + @@ -196,6 +204,12 @@ Always + + Always + + + Always + Always @@ -211,6 +225,24 @@ Always + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + Always