Compare commits

...

2 Commits

Author SHA1 Message Date
ltx
3bd2e0c5b4 Merge branch 'dev' of http://8.153.108.90:3000/YD/Wpf_AiSportsMicrospace into dev
# Conflicts:
#	Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml
2025-10-18 15:16:45 +08:00
ltx
0c1cad3714 update:bottom scorell 2025-10-18 15:14:10 +08:00
13 changed files with 460 additions and 4 deletions

View File

@ -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;
/// <summary>
/// 初始化动画控制器
/// </summary>
/// <param name="targetElement">目标UI元素</param>
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));
}
/// <summary>
/// 开始动画
/// </summary>
/// <param name="targetMargin">目标边距</param>
/// <param name="durationMs">动画时长(毫秒)</param>
/// <param name="easingFunction">缓动函数</param>
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();
}
/// <summary>
/// 开始从当前值到目标值的动画
/// </summary>
public void StartAnimationFromCurrent(Thickness targetMargin, int durationMs = 1000)
{
_thicknessAnimation.From = null; // 从当前值开始
_thicknessAnimation.To = targetMargin;
_thicknessAnimation.Duration = TimeSpan.FromMilliseconds(durationMs);
_storyboard.Begin();
}
/// <summary>
/// 开始从指定值到目标值的动画
/// </summary>
public void StartAnimationFromTo(Thickness fromMargin, Thickness toMargin, int durationMs = 1000)
{
_thicknessAnimation.From = fromMargin;
_thicknessAnimation.To = toMargin;
_thicknessAnimation.Duration = TimeSpan.FromMilliseconds(durationMs);
_storyboard.Begin();
}
/// <summary>
/// 停止动画
/// </summary>
public void StopAnimation()
{
_storyboard.Stop();
}
/// <summary>
/// 暂停动画
/// </summary>
public void PauseAnimation()
{
_storyboard.Pause();
}
/// <summary>
/// 恢复动画
/// </summary>
public void ResumeAnimation()
{
_storyboard.Resume();
}
/// <summary>
/// 设置动画完成回调
/// </summary>
public void SetCompletedCallback(EventHandler callback)
{
_storyboard.Completed += callback;
}
/// <summary>
/// 移除动画完成回调
/// </summary>
public void RemoveCompletedCallback(EventHandler callback)
{
_storyboard.Completed -= callback;
}
/// <summary>
/// 检查动画是否正在运行
/// </summary>
public bool IsAnimating => _storyboard.GetCurrentState() == ClockState.Active;
/// <summary>
/// 设置缓动函数
/// </summary>
public void SetEasingFunction(IEasingFunction easingFunction)
{
_thicknessAnimation.EasingFunction = easingFunction;
}
}
}

View File

@ -0,0 +1,39 @@
<UserControl x:Class="Wpf_AiSportsMicrospace.MyUserControl.PopSilder"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:gif="http://wpfanimatedgif.codeplex.com"
>
<Grid>
<Image x:Name="head_g" Source="/Resources/Img/play_img/music_rope/head_g.png" Visibility="Hidden" HorizontalAlignment="Right" Width="152" Height="85" VerticalAlignment="Top" Margin="0,0,0,0"/>
<Image x:Name="head_m" Source="/Resources/Img/play_img/music_rope/head_m.png" Visibility="Hidden" HorizontalAlignment="Right" Width="152" Height="85" VerticalAlignment="Top" Margin="0,0,0,0"/>
<StackPanel Orientation="Horizontal">
<Grid Width="3" Height="140" Background="#fedd40" ClipToBounds="False" Margin="0,620,0,0"></Grid>
<Grid Width="580" Height="87" Background="#25ffffff" ClipToBounds="False" Margin="0,620,0,0" HorizontalAlignment="Left">
<Border BorderBrush="#25ffffff"
BorderThickness="3"
CornerRadius="5"
Padding="0"
Margin="10">
<Grid Width="564" Height="62" ClipToBounds="True">
<!--<Border BorderThickness="3" BorderBrush="#25ffffff">
</Border>-->
<!--动画区域-->
<StackPanel x:Name="ani" VerticalAlignment="Center" Orientation="Horizontal" MouseDown="ani_MouseDown" Margin="280,0,0,0">
<!--<StackPanel Orientation="Horizontal" x:Name="ever">
<Image Source="/Resources/Img/play_img/music_rope/point.png" Width="52" Height="50" Margin="0,0,0,0"/>
<Grid Width="60" Height="5" Background="#000"></Grid>
</StackPanel>-->
</StackPanel>
</Grid>
</Border>
</Grid>
</StackPanel>
</Grid>
</UserControl>

View File

@ -0,0 +1,230 @@
using 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
{
/// <summary>
/// CoverFlowControl.xaml 的交互逻辑
/// </summary>
/// ST
///
public partial class PopSilder : UserControl
{
private List<double> _musicBeats = new List<double>()
{
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<double> _timePoints;
private int _currentIndex;
private DateTime _startTime;
public TimedEventTrigger(List<double> 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<double> TimePointReached;
protected virtual void OnTimePointReached(double timePoint)
{
TimePointReached?.Invoke(timePoint);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -8,14 +8,14 @@
Height="1080" Width="1920" Loaded="UserControl_Loaded" Unloaded="UserControl_Unloaded">
<Grid>
<Grid.Background>
<ImageBrush ImageSource="/Resources/Img/test_img/test_home_bg.png" Stretch="UniformToFill"/>
<ImageBrush ImageSource="/Resources/Img/play_img/music_rope/play_bg.png" Stretch="UniformToFill"/>
</Grid.Background>
<Image
Source="/Resources/Img/test_img/one_rope/title.png"
Source="/Resources/Img/play_img/music_rope/title.png"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Width="615"
Margin="0,0,0,0"
Width="905"
Margin="0,70,0,0"
/>
<Grid Height="1080" Width="1920" x:Name="userBox">
<Canvas x:Name="beatCanvas" />
@ -38,5 +38,23 @@
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" >
<local:WxProgressBar x:Name="PkBar"/>
</StackPanel>
<!--<Grid Width="3" Height="140" Margin="00,600,580,0" Background="#fedd40" ClipToBounds="False"></Grid>
<Grid Width="580" Height="87" Margin="00,600,0,0" Background="#25ffffff" ClipToBounds="False">
<Grid Width="564" Height="72" >
<Border BorderThickness="3" BorderBrush="#25ffffff">
</Border>
--><!--动画区域--><!--
<StackPanel x:Name="ani" VerticalAlignment="Center" Orientation="Horizontal">
<StackPanel Orientation="Horizontal">
<Image Source="/Resources/Img/play_img/music_rope/point.png" Width="50" Height="50" HorizontalAlignment="Left" Margin="0,0,0,0"/>
<Grid Width="60" Height="5" Background="#000"></Grid>
</StackPanel>
</StackPanel>
</Grid>
</Grid>-->
<local:PopSilder x:Name="popSilder" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</Grid>
</UserControl>

View File

@ -43,6 +43,14 @@
<None Remove="Resources\Img\gif\bottom_animation_image.png" />
<None Remove="Resources\Img\gif\time_3.gif" />
<None Remove="Resources\Img\gif\top_animation_image.png" />
<None Remove="Resources\Img\play_img\music_rope\great-p.png" />
<None Remove="Resources\Img\play_img\music_rope\great.png" />
<None Remove="Resources\Img\play_img\music_rope\head_g.png" />
<None Remove="Resources\Img\play_img\music_rope\head_m.png" />
<None Remove="Resources\Img\play_img\music_rope\miss.png" />
<None Remove="Resources\Img\play_img\music_rope\play_bg.png" />
<None Remove="Resources\Img\play_img\music_rope\point.png" />
<None Remove="Resources\Img\play_img\music_rope\title.png" />
<None Remove="Resources\Img\play_img\play_home_bg.png" />
<None Remove="Resources\Img\play_img\play_home_title.png" />
<None Remove="Resources\Img\play_img\play_jump.png" />
@ -78,6 +86,24 @@
<None Remove="Resources\Music\raisehand.mp3" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\Img\play_img\music_rope\great-p.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Resource>
<Resource Include="Resources\Img\play_img\music_rope\great.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Resource>
<Resource Include="Resources\Img\play_img\music_rope\head_g.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Resource>
<Resource Include="Resources\Img\play_img\music_rope\head_m.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Resource>
<Resource Include="Resources\Img\play_img\music_rope\miss.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Resource>
</ItemGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="14.0.0" />
<PackageReference Include="Emgu.CV" Version="4.12.0.5764" />
@ -219,6 +245,15 @@
<Resource Include="Resources\Img\gif\top_animation_image.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Resource>
<Resource Include="Resources\Img\play_img\music_rope\play_bg.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Resource>
<Resource Include="Resources\Img\play_img\music_rope\point.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Resource>
<Resource Include="Resources\Img\play_img\music_rope\title.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Resource>
<Resource Include="Resources\Img\play_img\play_home_bg.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Resource>