diff --git a/Wpf_AiSportsMicrospace/Common/SportOperate.cs b/Wpf_AiSportsMicrospace/Common/SportOperate.cs index 7148e16..5be2d76 100644 --- a/Wpf_AiSportsMicrospace/Common/SportOperate.cs +++ b/Wpf_AiSportsMicrospace/Common/SportOperate.cs @@ -56,7 +56,7 @@ namespace Wpf_AiSportsMicrospace.Common { try { - _webcamClient = WebcamClient.CreateRTSP("172.17.30.64", "admin", "yd708090", 554u); + _webcamClient = WebcamClient.CreateRTSP("172.17.30.65", "admin", "yd708090", 554u); } catch (Exception) { diff --git a/Wpf_AiSportsMicrospace/Dto/MusicJumpRopeContext.cs b/Wpf_AiSportsMicrospace/Dto/MusicJumpRopeContext.cs index 4848e99..c07300d 100644 --- a/Wpf_AiSportsMicrospace/Dto/MusicJumpRopeContext.cs +++ b/Wpf_AiSportsMicrospace/Dto/MusicJumpRopeContext.cs @@ -14,7 +14,7 @@ namespace Dto // 静态字段,保存排名列表 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 UserList { get; private set; } public List UserNumberList { get; private set; } public List UserScoreList { get; private set; } public List Sports { get; private set; } @@ -56,13 +56,13 @@ namespace Dto { CirclePositions = new List<(double XNorm, double YNorm)> { - (0.78, 0.88), (0.50, 0.88), + (0.78, 0.88), }; MusicBeatsDic = MusicBeats["1"].GroupBy(b => (int)Math.Ceiling(b) - 1).ToDictionary(g => g.Key, g => g.ToList()); - UserList = new List(); + UserList = new List(); UserNumberList = new List(); Sports = new List(); } diff --git a/Wpf_AiSportsMicrospace/MainWindow.xaml b/Wpf_AiSportsMicrospace/MainWindow.xaml index 30dd2fe..1e0865f 100644 --- a/Wpf_AiSportsMicrospace/MainWindow.xaml +++ b/Wpf_AiSportsMicrospace/MainWindow.xaml @@ -19,7 +19,7 @@ DisplayMemberPath="Name" SelectedValuePath="Key" SelectionChanged="sportList_SelectionChanged" d:IsHidden="True"/> - + diff --git a/Wpf_AiSportsMicrospace/MyUserControl/MusicUserItem.xaml b/Wpf_AiSportsMicrospace/MyUserControl/MusicUserItem.xaml new file mode 100644 index 0000000..7d3e3d7 --- /dev/null +++ b/Wpf_AiSportsMicrospace/MyUserControl/MusicUserItem.xaml @@ -0,0 +1,25 @@ + + + + + + + + \ No newline at end of file diff --git a/Wpf_AiSportsMicrospace/MyUserControl/MusicUserItem.xaml.cs b/Wpf_AiSportsMicrospace/MyUserControl/MusicUserItem.xaml.cs new file mode 100644 index 0000000..5b34f29 --- /dev/null +++ b/Wpf_AiSportsMicrospace/MyUserControl/MusicUserItem.xaml.cs @@ -0,0 +1,144 @@ +using HandyControl.Controls; +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 MusicUserItem : UserControl + { + public MusicUserItem() + { + InitializeComponent(); + //InitGif(); + } + + public string DisplayText + { + get => (string)GetValue(DisplayTextProperty); + set => SetValue(DisplayTextProperty, value); + } + + public static readonly DependencyProperty DisplayTextProperty = + DependencyProperty.Register(nameof(DisplayText), typeof(string), typeof(MusicUserItem), new PropertyMetadata("??")); + + public string NumberText + { + get => (string)GetValue(NumberTextProperty); + set => SetValue(NumberTextProperty, value); + } + + public static readonly DependencyProperty NumberTextProperty = + DependencyProperty.Register(nameof(NumberText), typeof(string), typeof(MusicUserItem), new PropertyMetadata("0")); + + public string ImageState + //0 没有人 1 准备中 2 运动中 3 出圈了 + { + get => (string)GetValue(ImageStateProperty); + set => SetValue(ImageStateProperty, value); + } + + public static readonly DependencyProperty ImageStateProperty = + DependencyProperty.Register(nameof(ImageState), typeof(string), typeof(MusicUserItem), new PropertyMetadata("0", OnImageStateChanged)); + + private static void OnImageStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = (MusicUserItem)d; + control.ShowImage((string)e.NewValue); + } + private void ShowImage(string imageIndex) + { + // 隐藏所有图片 + image1.Visibility = Visibility.Hidden; + image2.Visibility = Visibility.Hidden; + image3.Visibility = Visibility.Hidden; + + // 显示指定的图片 + switch (imageIndex) + { + case "1": + //image1.Visibility = Visibility.Visible; + //image1.Visibility = Visibility.Visible; + image1.Visibility = Visibility.Visible; + //Pause_Click(); + break; + case "2": + //image2.Visibility = Visibility.Visible; + image2.Visibility = Visibility.Visible; + //Play_Click(); + break; + case "3": + image3.Visibility = Visibility.Visible; + break; + } + } + private BitmapImage _gifSource; + private BitmapFrame _firstFrame; // <- 改为 BitmapFrame + + private void InitGif() + { + var uri = new Uri("pack://application:,,,/Resources/Img/test_img/one_rope/jump_rope.gif"); + + // 1) 加载用于播放的 BitmapImage(注意 OnLoad 防止被锁定) + _gifSource = new BitmapImage(); + _gifSource.BeginInit(); + _gifSource.UriSource = uri; + _gifSource.CacheOption = BitmapCacheOption.OnLoad; + _gifSource.EndInit(); + + // 2) 提取第一帧(使用 GifBitmapDecoder) + var sri = Application.GetResourceStream(uri); + if (sri != null) + { + using (var stream = sri.Stream) + { + var decoder = new GifBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad); + if (decoder.Frames.Count > 0) + _firstFrame = decoder.Frames[0]; + } + } + + // 3) 默认显示第一帧(静态) + image2.Source = _firstFrame; + } + + private void Play_Click() + { + // 重新设置动画源并播放 + //ImageBehavior.SetAnimatedSource(image2, _gifSource); + //ImageBehavior.GetAnimationController(image2)?.Play(); + var controller = ImageBehavior.GetAnimationController(image2); + controller?.Play(); + } + private void Pause_Click() + { + var controller = ImageBehavior.GetAnimationController(image2); + if (controller != null) + { + controller.Pause(); // 暂停动画 + //controller.GotoFrame(0); // 回到第一帧 + } + } + } +} \ No newline at end of file diff --git a/Wpf_AiSportsMicrospace/MyUserControl/PopSilder.xaml b/Wpf_AiSportsMicrospace/MyUserControl/PopSilder.xaml index 899be53..6b5d882 100644 --- a/Wpf_AiSportsMicrospace/MyUserControl/PopSilder.xaml +++ b/Wpf_AiSportsMicrospace/MyUserControl/PopSilder.xaml @@ -16,7 +16,7 @@ - + diff --git a/Wpf_AiSportsMicrospace/MyUserControl/PopSilder.xaml.cs b/Wpf_AiSportsMicrospace/MyUserControl/PopSilder.xaml.cs index 86e009f..80dfd6c 100644 --- a/Wpf_AiSportsMicrospace/MyUserControl/PopSilder.xaml.cs +++ b/Wpf_AiSportsMicrospace/MyUserControl/PopSilder.xaml.cs @@ -122,7 +122,7 @@ namespace Wpf_AiSportsMicrospace.MyUserControl _marginAnimation = new ThicknessAnimation { From = new Thickness(startMargin, 0, 0, 0), // 起始值 - To = new Thickness(-time * (200 + 52) - 350, 0, 0, 0), // 目标值 + To = new Thickness(-time * (200 + 52) - 650, 0, 0, 0), // 目标值 Duration = TimeSpan.FromSeconds(time), // time秒持续时间 FillBehavior = FillBehavior.HoldEnd // 动画完成后保持状态 }; @@ -167,27 +167,33 @@ namespace Wpf_AiSportsMicrospace.MyUserControl { head_m.Visibility = Visibility.Visible; miss.Visibility = Visibility.Visible; - //200ms后隐藏 + head_g.Visibility = Visibility.Hidden; + great.Visibility = Visibility.Hidden; + // 200ms 后隐藏 var hideTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(200) }; + hideTimer.Start(); hideTimer.Tick += (s, e) => { head_m.Visibility = Visibility.Hidden; miss.Visibility = Visibility.Hidden; - //_isMiss = true; - hideTimer.Stop(); + ((DispatcherTimer)s).Stop(); }; } else { head_g.Visibility = Visibility.Visible; great.Visibility = Visibility.Visible; - //200ms后隐藏 + head_m.Visibility = Visibility.Hidden; + miss.Visibility = Visibility.Hidden; + // 200ms 后隐藏 var hideTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(200) }; + hideTimer.Start(); hideTimer.Tick += (s, e) => { + _isMiss = true; head_g.Visibility = Visibility.Hidden; great.Visibility = Visibility.Hidden; - hideTimer.Stop(); + ((DispatcherTimer)s).Stop(); }; } } diff --git a/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/bg_mic.gif b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/bg_mic.gif new file mode 100644 index 0000000..03a17b3 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/bg_mic.gif differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/play_bg.jpg b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/play_bg.jpg new file mode 100644 index 0000000..35aed37 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/play_bg.jpg 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_bg1.png similarity index 100% rename from Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/play_bg.png rename to Wpf_AiSportsMicrospace/Resources/Img/play_img/music_rope/play_bg1.png diff --git a/Wpf_AiSportsMicrospace/Views/Home.xaml b/Wpf_AiSportsMicrospace/Views/Home.xaml index 6d3bc55..b04b32f 100644 --- a/Wpf_AiSportsMicrospace/Views/Home.xaml +++ b/Wpf_AiSportsMicrospace/Views/Home.xaml @@ -57,7 +57,7 @@ gif:ImageBehavior.AnimatedSource="/Resources/Img/Album/1.gif" gif:ImageBehavior.RepeatBehavior="Forever" HorizontalAlignment="right" - VerticalAlignment="Top" + VerticalAlignment="Top" Margin="50,10,200,20" /> diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml index 39ecd6a..2af2d90 100644 --- a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml @@ -19,11 +19,11 @@ /> - + - + - - - + @@ -57,9 +55,36 @@ + + + + + + + + + + + - + diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs index 3cc38ec..d3365c3 100644 --- a/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs @@ -23,6 +23,7 @@ using Wpf_AiSportsMicrospace.Common; using Wpf_AiSportsMicrospace.Enum; using Wpf_AiSportsMicrospace.MyUserControl; using Wpf_AiSportsMicrospace.Views; +using WpfAnimatedGif; using Yztob.AiSports.Inferences.Things; using Yztob.AiSports.Postures.Sports; @@ -40,7 +41,6 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope private MusicJumpRopeContext _musicJumpRopeContext; private GameState _currentGameState = GameState.NotStarted; - private List _musicBeatTextBlock = new List(); // 容忍时间(节拍误差) public double _beatTolerance = 0.15; // ±150ms @@ -62,7 +62,7 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope DrawCirclesWithText(); // 播放音乐 PlayMusic("raisehand.mp3"); - PkBar.LeftProgress = 1; + PkBar.LeftProgress = 0.5; popSilder1.MusicBeats = _musicJumpRopeContext.MusicBeats["1"]; popSilder2.MusicBeats = _musicJumpRopeContext.MusicBeats["1"]; @@ -253,6 +253,7 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope countdownGrid.Visibility = Visibility.Hidden; // 启动60秒倒计时(独立任务) StartGameCountdown(105); + ShowMusicAnimation(); } private async void StartGameCountdown(int seconds) @@ -446,7 +447,6 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope _musicJumpRopeContext.UserList.Clear(); _musicJumpRopeContext.UserNumberList.Clear(); _musicJumpRopeContext.UserBeatSyncList.Clear(); - _musicBeatTextBlock.Clear(); double imgWidth = userBox.ActualWidth; double imgHeight = userBox.ActualHeight; @@ -462,11 +462,11 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope double y = pos.YNorm * imgHeight; // 绘制发光圆 - //var userItem = AddUserItem(x, y, i); + var userItem = AddUserItem(x, y, i); // 绑定运动对象 var sport = SportBase.Create("rope-skipping"); int indexCopy = i; - //var currentItem = userItem; + var currentItem = userItem; // 订阅事件 sport.OnTicked += (count, times) => @@ -476,9 +476,9 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope // 更新数字源 _musicJumpRopeContext.UserNumberList[indexCopy] = count.ToString(); - //if (userItem.ImageState != "2") - // userItem.ImageState = "2"; - ChangeImgState(indexCopy, "2"); //改变当前图的状态 + if (userItem.ImageState != "2") + userItem.ImageState = "2"; + //ChangeImgState(indexCopy, "2"); //改变当前图的状态 var currentTime = Utils.GetMusicCurrentTime(); @@ -489,24 +489,26 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope bool hit = beats.Any(b => Math.Abs(b - currentTime) <= _beatTolerance); if (hit) { - _musicJumpRopeContext.UserBeatSyncList[indexCopy]++; - _musicBeatTextBlock[indexCopy].Text = $"卡点 x{_musicJumpRopeContext.UserBeatSyncList[indexCopy]}"; + _musicJumpRopeContext.UserBeatSyncList[indexCopy] += 1; double left = _musicJumpRopeContext.UserBeatSyncList[0]; double right = _musicJumpRopeContext.UserBeatSyncList[1]; double total = left + right; - PkBar.LeftProgress = total == 0 ? 0 : Math.Round(left / total, 2); + + PkBar.LeftProgress = 1 - (total == 0 ? 0.5 : Math.Round(left / total, 2)); if (indexCopy == 0) { - popSilder1.IsMiss = false; - UpdateScore(left, score1); + popSilder2.IsMiss = false; + //UpdateScore(left, score1); + score2.Text = (left * 10).ToString(); } else { - UpdateScore(right,score2); - popSilder2.IsMiss = false; + popSilder1.IsMiss = false; + //UpdateScore(right, score2); + score1.Text = (right * 10).ToString(); } - + } }; @@ -515,7 +517,7 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope } } - private void UpdateScore(double to , TextBlock score) + private void UpdateScore(double to, TextBlock score) { DoubleAnimation animation = new DoubleAnimation { @@ -528,19 +530,27 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope score.BeginAnimation(TextBlock.TextProperty, animation); } - private void ChangeImgState(int index , string state) + //private void ChangeImgState(int index , string state) + //{ + // if(index== 0) + // { + // left1.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden; + // left2.Visibility = state == "2" ? Visibility.Visible : Visibility.Hidden; + // left3.Visibility = state == "3" ? Visibility.Visible : Visibility.Hidden; + // }else if (index == 1) + // { + // right1.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden; + // right2.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden; + // right3.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden; + // } + //} + + public void ShowMusicAnimation() { - if(index== 0) - { - left1.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden; - left2.Visibility = state == "2" ? Visibility.Visible : Visibility.Hidden; - left3.Visibility = state == "3" ? Visibility.Visible : Visibility.Hidden; - }else if (index == 1) - { - right1.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden; - right2.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden; - right3.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden; - } + ImageBehavior.SetRepeatBehavior(leftm, RepeatBehavior.Forever); + ImageBehavior.SetRepeatBehavior(rightm, RepeatBehavior.Forever); + ImageBehavior.GetAnimationController(leftm).Play(); + ImageBehavior.GetAnimationController(rightm).Play(); } private void UpdateCircleCounts(List humans) @@ -585,9 +595,9 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope bool hasHuman = humanInCircle != null; lock (_updateLock) { - //_musicJumpRopeContext.UserList[i].ImageState = GetJumpState(i, hasHuman); - var state = GetJumpState(i, hasHuman); - ChangeImgState(i, state); + _musicJumpRopeContext.UserList[i].ImageState = GetJumpState(i, hasHuman); + //var state = GetJumpState(i, hasHuman); + //ChangeImgState(i, state); } // 推送计数 @@ -631,7 +641,19 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope return lastState; } - userItem.Margin = new Thickness(centerX + 120, centerY - 700, 0, 0); + private MusicUserItem AddUserItem(double centerX, double centerY, int index) + { + var userItem = new MusicUserItem(); + userItem.VerticalAlignment = VerticalAlignment.Top; + userItem.HorizontalAlignment = index == 1 ? HorizontalAlignment.Left : HorizontalAlignment.Right; + userItem.ImageState = "1"; + userItem.Margin = index == 1 ? new Thickness(226, 345, 0, 0) : new Thickness(0, 345, 226, 0); + userBox.Children.Add(userItem); + _musicJumpRopeContext.UserList.Add(userItem); + _musicJumpRopeContext.UserNumberList.Add("0"); + _musicJumpRopeContext.UserBeatSyncList.Add(0); + return userItem; // + } private void Image_MouseDown(object sender, MouseButtonEventArgs e) { diff --git a/Wpf_AiSportsMicrospace/Views/Main.xaml b/Wpf_AiSportsMicrospace/Views/Main.xaml index 43d4407..b80a7a1 100644 --- a/Wpf_AiSportsMicrospace/Views/Main.xaml +++ b/Wpf_AiSportsMicrospace/Views/Main.xaml @@ -5,6 +5,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.Views" xmlns:gif="http://wpfanimatedgif.codeplex.com" + WindowStyle="None" mc:Ignorable="d" WindowState="Maximized"> diff --git a/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj b/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj index f39f301..3048eb9 100644 --- a/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj +++ b/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj @@ -43,6 +43,7 @@ + @@ -51,7 +52,7 @@ - + @@ -93,6 +94,9 @@ + + Always + Always @@ -260,7 +264,7 @@ Always - + Always