diff --git a/Wpf_AiSportsMicrospace/Dto/WhackAMoleContext.cs b/Wpf_AiSportsMicrospace/Dto/WhackAMoleContext.cs index 78f0911..5a44a8e 100644 --- a/Wpf_AiSportsMicrospace/Dto/WhackAMoleContext.cs +++ b/Wpf_AiSportsMicrospace/Dto/WhackAMoleContext.cs @@ -26,12 +26,12 @@ namespace Dto { CirclePositions = new List<(double XNorm, double YNorm)> { - (0.21, 0.88 ), - (0.36, 0.58 ), - (0.50, 0.88), - (0.64, 0.58 ), - (0.78, 0.88), - (0.92, 0.58 ) + (403.2, 950.4 ), + (691.2, 626.4 ), + (960, 950.4 ), + (1228.8, 626.4 ), + (1497.6, 950.4), + (1766.4, 626.4) }; UserList = new List(); diff --git a/Wpf_AiSportsMicrospace/MyUserControl/WhackAMoleUserControl.xaml b/Wpf_AiSportsMicrospace/MyUserControl/WhackAMoleUserControl.xaml index e885102..b1e8d48 100644 --- a/Wpf_AiSportsMicrospace/MyUserControl/WhackAMoleUserControl.xaml +++ b/Wpf_AiSportsMicrospace/MyUserControl/WhackAMoleUserControl.xaml @@ -6,11 +6,13 @@ xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl" xmlns:system="clr-namespace:System;assembly=mscorlib" xmlns:gif="http://wpfanimatedgif.codeplex.com"> - + + Visibility="Hidden"/> - - - - - + Source="/Resources/Img/play_img/whack_mole/score-bg.png" + HorizontalAlignment="Left" + VerticalAlignment="Top" + Width="145" + Margin="234,511,0,0" + /> - + - /// 打地鼠用户控件 /// - public partial class WhackAMoleUserControl : UserControl, INotifyPropertyChanged + public partial class WhackAMoleUserControl : UserControl { - #region 依赖属性 - - /// - /// 玩家索引 - /// - public static readonly DependencyProperty IndexProperty = - DependencyProperty.Register(nameof(Index), typeof(int), typeof(WhackAMoleUserControl), - new PropertyMetadata(0, OnIndexChanged)); - - /// - /// 是否激活游戏 - /// - public static readonly DependencyProperty IsActiveProperty = - DependencyProperty.Register(nameof(IsActive), typeof(bool), typeof(WhackAMoleUserControl), - new PropertyMetadata(false, OnIsActiveChanged)); - - /// - /// 触发值,用于检测打地鼠动作 - /// - public static readonly DependencyProperty TriggerValueProperty = - DependencyProperty.Register(nameof(TriggerValue), typeof(double), typeof(WhackAMoleUserControl), - new PropertyMetadata(0.0, OnTriggerValueChanged)); - - #endregion - - #region 属性 - - /// - /// 玩家索引 - /// - public int Index - { - get => (int)GetValue(IndexProperty); - set => SetValue(IndexProperty, value); - } - - /// - /// 是否激活游戏 - /// - public bool IsActive - { - get => (bool)GetValue(IsActiveProperty); - set => SetValue(IsActiveProperty, value); - } - - /// - /// 触发值 - /// - public double TriggerValue - { - get => (double)GetValue(TriggerValueProperty); - set => SetValue(TriggerValueProperty, value); - } - - #endregion - - #region 私有字段 - - private int _score = 0; - private int _gameTime = 60; - private bool _isCharacterVisible = false; - private CharacterType _currentCharacter = CharacterType.None; - private DateTime _characterAppearTime; - private DispatcherTimer _gameTimer; - private DispatcherTimer _appearanceTimer; - private DispatcherTimer _hitDetectionTimer; - private double _lastTriggerValue; - private bool _isProcessingHit = false; - private readonly Random _random = new Random(); - ImageAnimationController controller1; - ImageAnimationController controller2; - ImageAnimationController controller3; - ImageAnimationController controller4; - private bool _isInitialized = false; - /// - /// 外部上下文,用于更新用户分数列表 - /// 注意:需要根据实际项目调整这个引用方式 - /// - private WhackAMoleContext _whackAMoleContext; - - #endregion - - #region 事件 - - /// - /// 分数改变事件 - /// - public event Action ScoreChanged; - - /// - /// 游戏结束事件 - /// - public event Action GameEnded; - - /// - /// 属性改变事件 - /// - public event PropertyChangedEventHandler PropertyChanged; - - #endregion - - #region 枚举 - - /// - /// 角色类型 - /// - private enum CharacterType - { - None, - Mole, - Rabbit - } - - #endregion - - #region 构造方法 - public WhackAMoleUserControl() { InitializeComponent(); - - // 初始化计时器 - InitializeTimers(); - - // 初始化外部上下文引用 - InitializeContext(); - + //InitGif(); + ImageBehavior.AddAnimationCompletedHandler(image1, TimeDown1); + ImageBehavior.AddAnimationCompletedHandler(image2, TimeDown); + ImageBehavior.AddAnimationCompletedHandler(image3, TimeDown1); + ImageBehavior.AddAnimationCompletedHandler(image4, TimeDown); } + #region 依赖属性 + + public string NumberText + { + get => (string)GetValue(NumberTextProperty); + set => SetValue(NumberTextProperty, value); + } + + public static readonly DependencyProperty NumberTextProperty = + DependencyProperty.Register(nameof(NumberText), typeof(string), typeof(WhackAMoleUserControl), new PropertyMetadata("0")); + + public string NameText + { + get => (string)GetValue(NameTextProperty); + set => SetValue(NameTextProperty, value); + } + + public static readonly DependencyProperty NameTextProperty = + DependencyProperty.Register(nameof(NameText), typeof(string), typeof(WhackAMoleUserControl), new PropertyMetadata("游客")); + #endregion - #region 私有方法 - - /// - /// 初始化计时器 - /// - private void InitializeTimers() + public string ImageState + //1 地鼠 2 地鼠打中 3 兔子 4 兔子打中 { - // 游戏主计时器(60秒倒计时) - _gameTimer = new DispatcherTimer(); - _gameTimer.Interval = TimeSpan.FromSeconds(1); - _gameTimer.Tick += GameTimer_Tick; + get => (string)GetValue(ImageStateProperty); + set => SetValue(ImageStateProperty, value); + } + public static readonly DependencyProperty ImageStateProperty = + DependencyProperty.Register(nameof(ImageState), typeof(string), typeof(WhackAMoleUserControl), new PropertyMetadata("1", OnImageStateChanged)); - // 角色出现计时器(随机间隔) - _appearanceTimer = new DispatcherTimer(); - _appearanceTimer.Tick += AppearanceTimer_Tick; - // 打击检测计时器(200ms检测窗口) - _hitDetectionTimer = new DispatcherTimer(); - _hitDetectionTimer.Interval = TimeSpan.FromMilliseconds(50); - _hitDetectionTimer.Tick += HitDetectionTimer_Tick; - - _whackAMoleContext = new WhackAMoleContext(); + private static void OnImageStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = (WhackAMoleUserControl)d; + control.ShowImage((string)e.NewValue); } - /// - /// 初始化外部上下文引用 - /// - private void InitializeContext() + private DispatcherTimer _imageTimer; + private Image _currentImage; + + private void ShowImage(string imageIndex) { - // 根据项目实际情况获取_context引用 - // 这里需要根据你的项目结构调整 - try + // 隐藏所有图片 + image1.Visibility = Visibility.Hidden; + image2.Visibility = Visibility.Hidden; + image3.Visibility = Visibility.Hidden; + image4.Visibility = Visibility.Hidden; + + // 显示指定的图片 + Image targetImage = null; + + switch (imageIndex) { - // 示例:如果存在全局上下文类 - // _groupJumpRopeContext = GlobalContext.Instance?.GetProperty("_groupJumpRopeContext"); - - // 或者通过查找父窗口/用户控件获取 - var parent = this.Parent as FrameworkElement; - while (parent != null) - { - var contextProperty = parent.GetType().GetProperty("_whackAMoleContext"); - if (contextProperty != null) - { - _whackAMoleContext = (WhackAMoleContext)contextProperty.GetValue(parent); - break; - } - parent = parent.Parent as FrameworkElement; - } + case "1": + targetImage = image1; + break; + case "2": + targetImage = image2; + break; + case "3": + targetImage = image3; + break; + case "4": + targetImage = image4; + break; } - catch (Exception) - { - // 忽略初始化错误,在实际使用时会再次尝试获取 - } - } - - - private void InitImageContal() - { - controller1 = ImageBehavior.GetAnimationController(image1); - controller2 = ImageBehavior.GetAnimationController(image2); - controller3 = ImageBehavior.GetAnimationController(image3); - controller4 = ImageBehavior.GetAnimationController(image4); - controller2.GotoFrame(controller2.FrameCount - 1); - controller4.GotoFrame(controller4.FrameCount - 1); - image2.Visibility = Visibility; - image4.Visibility = Visibility; - if(controller1 != null && controller2 != null && controller3 != null && controller4 != null) - { - _isInitialized = true; - } - } - /// - /// 获取外部上下文 - /// - private void TryGetContext() - { - if (_whackAMoleContext == null) - { - InitializeContext(); - } - } - - /// - /// 更新外部分数列表 - /// - private void UpdateExternalScoreList() - { - TryGetContext(); - - if (_whackAMoleContext != null) - { - try - { - var userNumberList = _whackAMoleContext.GetType().GetProperty("UserNumberList")?.GetValue(_whackAMoleContext) as List; - if (userNumberList != null && Index >= 0 && Index < userNumberList.Count) - { - userNumberList[Index] = _score; - } - } - catch (Exception) - { - // 忽略更新错误 - } - } - } - - /// - /// 开始游戏 - /// - private void StartGame() - { - if (!_isInitialized) { - InitImageContal(); - name.Text = _whackAMoleContext.UserNameList[Index]; - } - - // 重置分数 - _score = 0; - UpdateScoreDisplay(); - - // 重置计时器 - _gameTime = 60; - UpdateTimerDisplay(); - - // 隐藏所有角色 - HideAllCharacters(); - - // 启动游戏计时器 - _gameTimer.Start(); - - // 启动角色出现计时器(1-3秒随机间隔) - ScheduleNextAppearance(); - - // 启动打击检测计时器 - _hitDetectionTimer.Start(); - - // 记录初始触发值 - _lastTriggerValue = TriggerValue; - } - - /// - /// 停止游戏 - /// - private void StopGame() - { - // 停止所有计时器 - _gameTimer.Stop(); - _appearanceTimer.Stop(); - _hitDetectionTimer.Stop(); - - // 隐藏所有角色 - HideAllCharacters(); - - // 重置状态 - _isCharacterVisible = false; - _currentCharacter = CharacterType.None; - _isProcessingHit = false; - - // 发送游戏结束事件 - GameEnded?.Invoke(_score); - } - - /// - /// 安排下一次角色出现 - /// - private void ScheduleNextAppearance() - { - // 随机间隔3-5秒 - int interval = _random.Next(2000, 3501); - _appearanceTimer.Interval = TimeSpan.FromMilliseconds(interval); - _appearanceTimer.Start(); - } - - /// - /// 显示角色 - /// - private void ShowCharacter() - { - if (_isProcessingHit) return; - - // 随机决定出现地鼠还是兔子(70%地鼠,30%兔子) - bool isMole = _random.Next(100) < 20; - _currentCharacter = isMole ? CharacterType.Mole : CharacterType.Rabbit; - _isCharacterVisible = true; - _characterAppearTime = DateTime.Now; - image2.Visibility = Visibility.Collapsed; - image4.Visibility = Visibility.Collapsed; - if (isMole) - { - image1.Visibility = Visibility.Visible; - image3.Visibility = Visibility.Collapsed; - - //ShowGif(controller1 , 0); - controller1.Play(); - Task.Delay(1450).ContinueWith(_ => - { - controller1.Pause(); - controller1.GotoFrame(0); - _isCharacterVisible = false; - }, TaskScheduler.FromCurrentSynchronizationContext()); - //image3.Visibility = Visibility.Collapsed; + // 显示新图片 + if (targetImage != null) { + ImageBehavior.SetRepeatBehavior(targetImage, new RepeatBehavior(2)); + ImageBehavior.SetRepeatBehavior(targetImage, new RepeatBehavior(1)); + targetImage.Visibility = Visibility.Visible; + _currentImage = targetImage; + ImageBehavior.GetAnimationController(targetImage).Play(); } else { - //ShowGif(controller2 , 0); - image3.Visibility = Visibility.Visible; - image1.Visibility = Visibility.Collapsed; - controller3.Play(); - Task.Delay(1300).ContinueWith(_ => - { - controller3.Pause(); - controller3.GotoFrame(0); - _isCharacterVisible = false; - }, TaskScheduler.FromCurrentSynchronizationContext()); + ImageBehavior.SetRepeatBehavior(image1, new RepeatBehavior(2)); + ImageBehavior.SetRepeatBehavior(image1, new RepeatBehavior(1)); + image1.Visibility = Visibility.Visible; } - } - - /// - /// 隐藏所有角色 - /// - private void HideAllCharacters() - { - //image1.Visibility = Visibility.Collapsed; - image2.Visibility = Visibility.Collapsed; - //image3.Visibility = Visibility.Collapsed; - image4.Visibility = Visibility.Collapsed; - } - - /// - /// 处理打击 - /// - private void ProcessHit() - { - if (!_isCharacterVisible || _isProcessingHit) return; - - _isProcessingHit = true; - image1.Visibility = Visibility.Collapsed; - image3.Visibility = Visibility.Collapsed; - - if (_currentCharacter == CharacterType.Mole) - { - // 打中地鼠 - image2.Visibility = Visibility.Visible; - image4.Visibility = Visibility.Collapsed; - controller2.Play(); - // 分数+10 - _score += 10; - UpdateScoreDisplay(); - UpdateExternalScoreList(); - - // 发送分数改变事件 - ScoreChanged?.Invoke(Index, _score); - Task.Delay(1500).ContinueWith(_ => - { - controller2.Pause(); - controller2.GotoFrame(controller2.FrameCount - 1); - _isCharacterVisible = false; - _currentCharacter = CharacterType.None; - _isProcessingHit = false; - - // 安排下一次出现 - ScheduleNextAppearance(); - }, TaskScheduler.FromCurrentSynchronizationContext()); - - - - - } - else if (_currentCharacter == CharacterType.Rabbit) - { - // 打中兔子(干扰) - image2.Visibility = Visibility.Visible; - image4.Visibility = Visibility.Collapsed; - controller4.Play(); - // 分数-10 - _score -= 5; - UpdateScoreDisplay(); - UpdateExternalScoreList(); - - // 发送分数改变事件 - ScoreChanged?.Invoke(Index, _score); - Task.Delay(1500).ContinueWith(_ => - { - controller4.Pause(); - controller4.GotoFrame(controller4.FrameCount - 1); - _isCharacterVisible = false; - _currentCharacter = CharacterType.None; - _isProcessingHit = false; - - // 安排下一次出现 - ScheduleNextAppearance(); - }, TaskScheduler.FromCurrentSynchronizationContext()); - } - } - - /// - /// 超时未打击 - /// - private void HandleTimeout() - { - if (_isProcessingHit) return; - - _isCharacterVisible = false; - _currentCharacter = CharacterType.None; - - HideAllCharacters(); - - // 安排下一次出现 - ScheduleNextAppearance(); - } - - private void ShowGif(ImageAnimationController controller , double number) - { - //ImageBehavior.SetRepeatBehavior(gif, new RepeatBehavior(2)); - //ImageBehavior.SetRepeatBehavior(gif, new RepeatBehavior(1)); - //ImageBehavior.SetAutoStart(gif, true); - ////播放完成跳转到第一个画面 - //Task.Delay(2000).ContinueWith(_ => { - // gif.Dispatcher.Invoke(() => - // { - // var controller = ImageBehavior.GetAnimationController(gif); - // //ImageBehavior.SetAutoStart(gif, false); - - // controller.GotoFrame(0); - // }); - - //}); - - controller.Play(); - Task.Delay(1500).ContinueWith(_ => + } + + //当状态为2或4时候 不处理 + private void TimeDown1(object? sender, RoutedEventArgs? e) + { + //MessageBox.Show("播放完啦");// 弹提示框22 + if(ImageState == "2" || ImageState == "4" ) { - controller.Pause(); - if(number == 0) - { - controller.GotoFrame(0); - } - else - { - controller.GotoFrame(controller.FrameCount - 1); - } - }, TaskScheduler.FromCurrentSynchronizationContext()); - } - - /// - /// 更新分数显示 - /// - private void UpdateScoreDisplay() - { - NumberText.Text = _score.ToString(); - } - - /// - /// 更新计时器显示 - /// - private void UpdateTimerDisplay() - { - TimerText.Text = _gameTime.ToString(); - } - - /// - /// 检查触发值变化 - /// - private bool CheckTriggerValueChanged() - { - // 检测触发值是否发生变化 - // 根据实际需求调整检测逻辑 - double currentValue = TriggerValue; - bool hasChanged = Math.Abs(currentValue - _lastTriggerValue) > 0.001; - - if (hasChanged) - { - _lastTriggerValue = currentValue; + return; } - - return hasChanged; - } - - /// - /// 检查是否在有效打击窗口内 - /// - private bool IsWithinHitWindow() - { - if (!_isCharacterVisible) return false; - - TimeSpan elapsed = DateTime.Now - _characterAppearTime; - return elapsed.TotalMilliseconds <= 2100; - } - - #endregion - - #region 事件处理 - - /// - /// Index属性改变回调 - /// - private static void OnIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var control = d as WhackAMoleUserControl; - control?.OnPropertyChanged(nameof(Index)); - } - - /// - /// IsActive属性改变回调 - /// - private static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var control = d as WhackAMoleUserControl; - if (control != null) + else { - if ((bool)e.NewValue) - { - control.StartGame(); - } - else - { - control.StopGame(); - } + Task.Delay(1300); + ImageBehavior.GetAnimationController(image1).Pause(); + ImageBehavior.GetAnimationController(image2).Pause(); + ImageBehavior.GetAnimationController(image3).Pause(); + ImageBehavior.GetAnimationController(image4).Pause(); + ImageBehavior.SetRepeatBehavior(image1, new RepeatBehavior(2)); + ImageBehavior.SetRepeatBehavior(image1, new RepeatBehavior(1)); + image1.Visibility = Visibility.Visible; + image2.Visibility = Visibility.Hidden; + image3.Visibility = Visibility.Hidden; + image4.Visibility = Visibility.Hidden; + ImageState = "0"; } } - /// - /// TriggerValue属性改变回调 - /// - private static void OnTriggerValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + private void TimeDown(object? sender, RoutedEventArgs? e) { - var control = d as WhackAMoleUserControl; - control?.OnTriggerValueChangedHandler(); + //MessageBox.Show("播放完啦");// 弹提示框22 + Task.Delay(1300); + ImageBehavior.GetAnimationController(image1).Pause(); + ImageBehavior.GetAnimationController(image2).Pause(); + ImageBehavior.GetAnimationController(image3).Pause(); + ImageBehavior.GetAnimationController(image4).Pause(); + ImageBehavior.SetRepeatBehavior(image1, new RepeatBehavior(2)); + ImageBehavior.SetRepeatBehavior(image1, new RepeatBehavior(1)); + image1.Visibility = Visibility.Visible; + image2.Visibility = Visibility.Hidden; + image3.Visibility = Visibility.Hidden; + image4.Visibility = Visibility.Hidden; + ImageState = "0"; } - /// - /// 触发值改变处理 - /// - private void OnTriggerValueChangedHandler() - { - // 当检测到触发值变化且在有效窗口内时处理打击 - if (IsActive && IsWithinHitWindow()) - { - ProcessHit(); - } - } - - /// - /// 游戏计时器tick - /// - private void GameTimer_Tick(object sender, EventArgs e) - { - _gameTime--; - UpdateTimerDisplay(); - - if (_gameTime <= 0) - { - StopGame(); - } - } - - /// - /// 角色出现计时器tick - /// - private void AppearanceTimer_Tick(object sender, EventArgs e) - { - _appearanceTimer.Stop(); - - if (IsActive && !_isCharacterVisible && !_isProcessingHit) - { - ShowCharacter(); - } - } - - /// - /// 打击检测计时器tick - /// - private void HitDetectionTimer_Tick(object sender, EventArgs e) - { - // 检测是否超时未打击 - if (_isCharacterVisible && !_isProcessingHit) - { - TimeSpan elapsed = DateTime.Now - _characterAppearTime; - if (elapsed.TotalMilliseconds > 2100) - { - HandleTimeout(); - } - } - } - - /// - /// 属性改变通知 - /// - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - - #endregion - - #region 公共方法 - - /// - /// 手动开始游戏 - /// - public void Start() - { - IsActive = true; - } - - /// - /// 手动停止游戏 - /// - public void Stop() - { - IsActive = false; - } - - /// - /// 重置分数 - /// - public void ResetScore() - { - _score = 0; - UpdateScoreDisplay(); - UpdateExternalScoreList(); - } - - /// - /// 设置外部上下文 - /// - /// 外部上下文对象 - public void SetContext(dynamic context) - { - _whackAMoleContext = context; - } - - #endregion } } \ No newline at end of file diff --git a/Wpf_AiSportsMicrospace/Resources/Img/play_img/whack_mole.png b/Wpf_AiSportsMicrospace/Resources/Img/play_img/whack_mole.png new file mode 100644 index 0000000..f8aaeac Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/play_img/whack_mole.png differ diff --git a/Wpf_AiSportsMicrospace/Views/Home.xaml.cs b/Wpf_AiSportsMicrospace/Views/Home.xaml.cs index 880f0de..6f1a856 100644 --- a/Wpf_AiSportsMicrospace/Views/Home.xaml.cs +++ b/Wpf_AiSportsMicrospace/Views/Home.xaml.cs @@ -60,7 +60,8 @@ namespace Wpf_AiSportsMicrospace }); coverFlow.Images.Add(new CoverFlowItem { - ImageUri = GetResourceUri("Album/home_history.png"), + //ImageUri = GetResourceUri("Album/home_history.png"), + ImageUri = GetResourceUri("play_img/whack_mole.png"), ProgressColor1 = "#e73d42", ProgressColor2 = "#215bc7" }); @@ -164,7 +165,6 @@ namespace Wpf_AiSportsMicrospace //mainWin?.SwitchPageWithMaskAnimation(newPage, true); //var newPage = new BambooDragonfly(); - //var newPage = new WhackAMole(); mainWin?.SwitchPageWithMaskAnimation(newPage, true); } else if (coverFlow.SelectedIndex == 1) @@ -175,8 +175,8 @@ namespace Wpf_AiSportsMicrospace else { //var newPage = new TrainingRecords(); - //var newPage = new WhackAMole(); - var newPage = new StandingLeap(); + var newPage = new WhackAMole(); + //var newPage = new StandingLeap(); mainWin?.SwitchPageWithMaskAnimation(newPage, true); } } diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs index 0ea1f99..6a4a5e5 100644 --- a/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs @@ -246,37 +246,37 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope //UpdateCountdown(); //开始人脸识别============================================= - Action handler = null; + //Action handler = null; - handler = async (frame) => - { - double[] xValues = [.. _musicJumpRopeContext.CirclePositions.Select(p => p.XNorm)]; - var buffer = frame.GetImageBuffer(ImageFormat.Jpeg).ToArray(); - var studentList = Utils.FacialRecognition(buffer, xValues); + //handler = async (frame) => + //{ + // double[] xValues = [.. _musicJumpRopeContext.CirclePositions.Select(p => p.XNorm)]; + // var buffer = frame.GetImageBuffer(ImageFormat.Jpeg).ToArray(); + // var studentList = Utils.FacialRecognition(buffer, xValues); - if (studentList != null && studentList.Count > 0) - { - // 解绑事件 - _mainWin.FacialRecognitionEvent -= handler; - name1.Text = studentList[0]?.StudentName ?? "一号玩家"; - name2.Text = studentList[1]?.StudentName ?? "二号玩家"; - if (studentList.Count > 1 && studentList[0].Photo != "") - { - await LoadImageFromUrlAsync(studentList[0]?.Photo ?? "", avatar1); - } - if (studentList.Count > 2 && studentList[1].Photo != "") - { - await LoadImageFromUrlAsync(studentList[1]?.Photo ?? "", avatar2); - } + // if (studentList != null && studentList.Count > 0) + // { + // // 解绑事件 + // _mainWin.FacialRecognitionEvent -= handler; + // name1.Text = studentList[0]?.StudentName ?? "一号玩家"; + // name2.Text = studentList[1]?.StudentName ?? "二号玩家"; + // if (studentList.Count > 1 && studentList[0].Photo != "") + // { + // await LoadImageFromUrlAsync(studentList[0]?.Photo ?? "", avatar1); + // } + // if (studentList.Count > 2 && studentList[1].Photo != "") + // { + // await LoadImageFromUrlAsync(studentList[1]?.Photo ?? "", avatar2); + // } - } + // } - // 这里可以继续处理 studentList - }; + // // 这里可以继续处理 studentList + //}; - //// 绑定事件 - _mainWin.FacialRecognitionEvent += handler; + ////// 绑定事件 + //_mainWin.FacialRecognitionEvent += handler; await Task.Delay(3000); FinishCountdown(); diff --git a/Wpf_AiSportsMicrospace/Views/SquatFu/WhackAMole.xaml b/Wpf_AiSportsMicrospace/Views/SquatFu/WhackAMole.xaml index 0d818b9..0f846ac 100644 --- a/Wpf_AiSportsMicrospace/Views/SquatFu/WhackAMole.xaml +++ b/Wpf_AiSportsMicrospace/Views/SquatFu/WhackAMole.xaml @@ -36,9 +36,12 @@ --> - - - + + + + + + - + diff --git a/Wpf_AiSportsMicrospace/Views/SquatFu/WhackAMole.xaml.cs b/Wpf_AiSportsMicrospace/Views/SquatFu/WhackAMole.xaml.cs index 94f0e2b..0d095de 100644 --- a/Wpf_AiSportsMicrospace/Views/SquatFu/WhackAMole.xaml.cs +++ b/Wpf_AiSportsMicrospace/Views/SquatFu/WhackAMole.xaml.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.DependencyInjection; using SportExpand; using System; using System.ComponentModel; +using System.Diagnostics; using System.IO; using System.Runtime.CompilerServices; using System.Windows; @@ -53,7 +54,7 @@ namespace Views.SquatFu _WhackAMoleContext = new WhackAMoleContext(); } - private async void UserControl_Loaded(object sender, RoutedEventArgs e) + private async void UserControl_Loaded(object sender, RoutedEventArgs e) { // 使用局部变量保存事件处理方法,以便解绑 Action handler = null; @@ -78,9 +79,10 @@ namespace Views.SquatFu _WhackAMoleContext.CirclePositions = pointlist; DrawCirclesWithText(); - // 播放音乐 PlayMusic("raisehand.mp3"); + _mainWin.HumanFrameUpdated += OnHumanFrameUpdated; + } private void UserControl_Unloaded(object sender, RoutedEventArgs e) @@ -106,9 +108,11 @@ namespace Views.SquatFu ShowCenterTip(imgPath, TimeSpan.FromSeconds(3)); // 监听播放完成事件 - _mediaPlayer.MediaEnded += MediaPlayer_MediaEnded; + _mediaPlayer.MediaEnded += MediaPlayer_MediaEnded; //_mainWin.WebcamClient.StartExtract(); _mediaPlayer.Play(); + _mainWin.HumanFrameUpdated += OnHumanFrameUpdated; + } private void ShowCenterTip(string imagePath, TimeSpan duration) { @@ -126,7 +130,7 @@ namespace Views.SquatFu tipImage.Height = 1080 * 0.6; // 高度为 Canvas 高度的 60% // 将图片添加到 Overlay Canvas - userBox.Children.Add(tipImage); + userListBox.Children.Add(tipImage); // 渐变出现动画 var fadeInAnimation = new DoubleAnimation @@ -157,7 +161,7 @@ namespace Views.SquatFu // 完成后移除图片 fadeOutAnimation.Completed += (s, e) => { - userBox.Children.Remove(tipImage); + userListBox.Children.Remove(tipImage); }; }); }); @@ -178,7 +182,7 @@ namespace Views.SquatFu try { if (humans == null || humans.Count == 0) return; - + switch (_currentGameState) { case GameState.NotStarted: // 未开始 @@ -198,7 +202,7 @@ namespace Views.SquatFu } int rightWaving = sportOperate.VerifyRightWavingAction(humans); - if (rightWaving >= 3) + if (rightWaving >= 3 && RankingGrid.Visibility != Visibility.Visible) { switch (rightWaving) { @@ -206,13 +210,13 @@ namespace Views.SquatFu StartCountdown(3); _isCountdownStarted = true; // 倒计时开始,停止左手检测 break; - case (int)WavingAction.Raising: - UpdateCountdown(); - break; - case (int)WavingAction.RaiseHand: - FinishCountdown(); - _currentGameState = GameState.Running; // 倒计时完成 → 游戏开始 - break; + //case (int)WavingAction.Raising: + // UpdateCountdown(); + // break; + //case (int)WavingAction.RaiseHand: + // FinishCountdown(); + // _currentGameState = GameState.Running; // 倒计时完成 → 游戏开始 + // break; } } break; @@ -220,6 +224,19 @@ namespace Views.SquatFu case GameState.Running: // 游戏进行中 UpdateCircleCounts(humans); break; + case GameState.Finished: // 游戏结束 + int leftWave = sportOperate.VerifyLeftWavingAction(humans); + if (leftWave == 5) + { + _mainWin.HumanFrameUpdated -= OnHumanFrameUpdated; + _mainWin.WebcamClient.StopExtract(); + + // 举左手逻辑,例如结束动画或退出 + var newPage = new Home(); + _mainWin?.SwitchPageWithMaskAnimation(newPage, true); + return; // 提前退出 + } + break; } } catch (Exception ex) @@ -230,19 +247,21 @@ namespace Views.SquatFu private double _currentCountdown = 3600; private DateTime _lastUpdateTime = DateTime.Now; - private void StartCountdown(int start = 3) + private async void StartCountdown(int start = 3) { + _currentGameState = GameState.Running; + _mainWin.ShowCountDownAnimation(); Utils.PlayBackgroundMusic("countdown_3.mp3", false); - //开始人脸识别============================================= - //Action handler = null; + //开始人脸识别 ============================================= + //Action < VideoFrame > handler = null; //handler = async (frame) => //{ // var buffer = frame.GetImageBuffer(ImageFormat.Jpeg).ToArray(); - // double[] xValues = [.. _groupJumpRopeContext.CirclePositions.Select(p => p.XNorm)]; + // double[] xValues = [.. _WhackAMoleContext.CirclePositions.Select(p => p.XNorm)]; // var studentList = Utils.FacialRecognition(buffer, xValues); @@ -256,15 +275,17 @@ namespace Views.SquatFu // var student = studentList[i]; // if (student != null) // { - // _groupJumpRopeContext.UserList[i].DisplayText = student.StudentName; + // _WhackAMoleContext.UserList[i].NameText = student.StudentName; // } // } // } //}; - //// 绑定事件 + // 绑定事件 //_mainWin.FacialRecognitionEvent += handler; + await Task.Delay(3000); + FinishCountdown(); } private void UpdateCountdown() @@ -285,19 +306,62 @@ namespace Views.SquatFu } } + private System.Timers.Timer _gameTimer; + private Random _random = new Random(); + private async void FinishCountdown() { countdownText.Text = "GO!"; countdownGrid.Visibility = Visibility.Hidden; - _WhackAMoleContext.UserList.ForEach(x => - { - x.Start(); - }); + // 播放背景音乐(循环) Utils.PlayBackgroundMusic("homeprojectselected1.mp3", true); // 启动60秒倒计时(独立任务) StartGameCountdown(60); + + // 开始游戏定时器,每2-3秒随机选取用户出现地鼠或兔子 + StartGameTimer(); + } + + private void StartGameTimer() + { + _gameTimer = new System.Timers.Timer(); + _gameTimer.Elapsed += OnGameTimerElapsed; + _gameTimer.AutoReset = true; + + // 设置第一次触发时间为2-3秒之间的随机值 + int firstInterval = _random.Next(2000, 3000); + _gameTimer.Interval = firstInterval; + _gameTimer.Start(); + } + + private void OnGameTimerElapsed(object sender, System.Timers.ElapsedEventArgs e) + { + Dispatcher.Invoke(() => + { + // 随机选取2-4个用户 + int userCount = _random.Next(2, 5); // 2-4个 + int actualCount = Math.Min(userCount, _WhackAMoleContext.UserList.Count); + + // 获取所有用户索引 + var allIndices = Enumerable.Range(0, _WhackAMoleContext.UserList.Count).ToList(); + // 随机打乱顺序 + var shuffled = allIndices.OrderBy(x => _random.Next()).Take(actualCount).ToList(); + + foreach (var index in shuffled) + { + // 随机决定是地鼠(1)还是兔子(3) + int imageState = _random.Next(2) == 0 ? 1 : 3; + if(_WhackAMoleContext.UserList[index].ImageState == "0") + { + _WhackAMoleContext.UserList[index].ImageState = imageState.ToString(); + } + } + + // 设置下一次触发时间为2-3秒之间的随机值 + _gameTimer.Interval = _random.Next(2000, 3000); + }); } double Tiggle = 1; private async void StartGameCountdown(int seconds) @@ -311,11 +375,11 @@ namespace Views.SquatFu } countdownGrid.Visibility = Visibility.Hidden; - + _gameTimer.Stop(); _WhackAMoleContext.UserList.ForEach(x => { Tiggle += 1; - x.TriggerValue = Tiggle; + //x.TriggerValue = Tiggle; }); _mainWin.HumanFrameUpdated -= OnHumanFrameUpdated; @@ -325,13 +389,13 @@ namespace Views.SquatFu ShowRankingBoard(RankingItemList); Utils.StopBackgroundMusic(); - _currentGameState = GameState.NotStarted; + _currentGameState = GameState.Finished; _isCountdownStarted = false; _mainWin.HumanFrameUpdated += OnHumanFrameUpdated; _mainWin.WebcamClient.StartExtract(); } - + private DateTime? _raiseStartTime; private bool _firstHandTriggered; private int _lastCountdownSecond = 3; @@ -346,7 +410,7 @@ namespace Views.SquatFu } private void DrawCirclesWithText() { - userBox.Children.Clear(); + userListBox.Children.Clear(); _WhackAMoleContext.Sports.Clear(); _WhackAMoleContext.UserList.Clear(); _WhackAMoleContext.UserNumberList.Clear(); @@ -355,32 +419,59 @@ namespace Views.SquatFu for (int i = 0; i < _WhackAMoleContext.CirclePositions.Count; i++) { var pos = _WhackAMoleContext.CirclePositions[i]; - double x = pos.XNorm ; - double y = pos.YNorm ; + double x = pos.XNorm; + double y = pos.YNorm; // 绘制发光圆 - var userItem = AddUserItem(x, y, i); + AddUserItem(x, y, i); // 绑定运动对象 var sport = new FrontSquat(); - + Debug.WriteLine($"userListBox长度:{userListBox.Children.Count}"); //Optimizes.Optimizeing(sport); //var sport = SportBase.Create("rope-skipping"); int indexCopy = i; - var currentItem = userItem; + //var currentItem = userItem; - // 订阅事件 + // 订阅事件 sport.OnTicked += (count, times) => { - // 更新UI - //userItem.NumberText = count.ToString(); - // 更新数字源 - _WhackAMoleContext.UserNumberList[indexCopy] = count.ToString(); - // 改变状态为“跳绳中” - if (userItem.TriggerValue != 2) - userItem.TriggerValue = 2; + // 获取当前用户的ImageState + var imageState = _WhackAMoleContext.UserList[indexCopy].ImageState; + + // 获取当前分数 + int currentScore = 0; + int.TryParse(_WhackAMoleContext.UserNumberList[indexCopy], out currentScore); + + // 根据ImageState判断加分还是减分 + if (imageState == "1") // 地鼠:加10分 + { + currentScore += 10; + } + else if (imageState == "3") // 兔子:减5分 + { + currentScore -= 5; + // 分数不能为负数 + //if (currentScore < 0) currentScore = 0; + } + + // 更新分数 + string newScore = currentScore.ToString(); + _WhackAMoleContext.UserNumberList[indexCopy] = newScore; + _WhackAMoleContext.UserList[indexCopy].NumberText = newScore; + + // 如果打中地鼠或兔子,重置ImageState为0 + if (imageState == "1") + { + _WhackAMoleContext.UserList[indexCopy].ImageState = "2"; + } + else if(imageState == "3") + { + _WhackAMoleContext.UserList[indexCopy].ImageState = "4"; + + } }; sport.Start(); @@ -424,24 +515,39 @@ namespace Views.SquatFu } } - private WhackAMoleUserControl AddUserItem(double centerX, double centerY, int index) + void AddUserItem(double centerX, double centerY, int index) { - var userItem = new WhackAMoleUserControl(); - userItem.Width = 400; - userItem.Height = 600; - //userItem.DisplayText = _groupJumpRopeContext.UseNameList[index]; //名字 - userItem.VerticalAlignment = VerticalAlignment.Top; - userItem.HorizontalAlignment = HorizontalAlignment.Left; - userItem.Index = index; + //var userItem = new WhackAMoleUserControl(); + //userItem.Width = 400; + //userItem.Height = 600; + //userItem.NameText = _WhackAMoleContext.UserNameList[index]; //名字 + //userItem.VerticalAlignment = VerticalAlignment.Top; + //userItem.HorizontalAlignment = HorizontalAlignment.Left; + //userItem.Index = index; //userItem.ImageState = "1"; //userItem.Margin = new Thickness(centerX - (index == 0 ? 80 : index == 6 ? 190 : 135), centerY - 540, 0, 0); - userItem.Margin = new Thickness(centerX , centerY - 600 - 50, 0, 0); - userBox.Children.Add(userItem); + var userItem = new WhackAMoleUserControl + { + Width = 410, + Height = 580, + NameText = _WhackAMoleContext.UserNameList[index], + VerticalAlignment = VerticalAlignment.Top, + HorizontalAlignment = HorizontalAlignment.Left, + ImageState = "0" + }; + + var top = (centerX - 200) > 0 ? (centerX - 200) : 0; + + + userItem.Margin = new Thickness(top, centerY - 570, 0, 0); + userListBox.Children.Add(userItem); _WhackAMoleContext.UserList.Add(userItem); _WhackAMoleContext.UserNumberList.Add("0"); - return userItem; // + //return userItem; // } + + public void ShowRankingBoard(List list) { var scoreGrid = FindName("ScoreGrid") as Grid; diff --git a/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj b/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj index e14faf7..ca98385 100644 --- a/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj +++ b/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj @@ -69,13 +69,16 @@ + + + @@ -138,6 +141,9 @@ Always + + Always + Always @@ -150,6 +156,9 @@ Always + + Always + Always @@ -159,6 +168,9 @@ Always + + Always + Always