音乐跳绳

This commit is contained in:
tanglong 2025-10-15 14:14:59 +08:00
parent 01abba4321
commit b83b3c3b42
6 changed files with 237 additions and 30 deletions

View File

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using Wpf_AiSportsMicrospace.MyUserControl;
using Yztob.AiSports.Postures.Sports;
namespace Dto
{
public class MusicJumpRopeContext
{
// 静态字段,保存排名列表
public static List<RankItem> RankList { get; set; } = new List<RankItem>();
public List<(double XNorm, double YNorm)> CirclePositions { get; private set; }
public List<SportUserItem> UserList { get; private set; }
public List<string> UserNumberList { get; private set; }
public List<string> UserScoreList { get; private set; }
public List<string> UserBeatSyncList { get; private set; }
public List<SportBase> Sports { get; private set; }
public List<string> UseNameList { get; private set; } = new() { "一号位", "二号位" };
public MusicJumpRopeContext()
{
CirclePositions = new List<(double XNorm, double YNorm)>
{
(0.21, 0.88),
//(0.50, 0.88),
(0.78, 0.88),
};
UserList = new List<SportUserItem>();
UserNumberList = new List<string>();
Sports = new List<SportBase>();
}
// 更新排行榜方法
public void 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();
}
}
}

View File

@ -19,6 +19,7 @@ using Wpf_AiSportsMicrospace.Common;
using Wpf_AiSportsMicrospace.Enum;
using Wpf_AiSportsMicrospace.MyUserControl;
using Wpf_AiSportsMicrospace.Views;
using Wpf_AiSportsMicrospace.Views.JumpRope;
using Yztob.AiSports.Inferences.Abstractions;
using Yztob.AiSports.Inferences.Things;
using Yztob.AiSports.Postures;
@ -42,11 +43,11 @@ namespace Wpf_AiSportsMicrospace
InitializeComponent();
string projectRoot = Path.Combine(AppContext.BaseDirectory, @"..\..\..");
string albumPath = Path.Combine(projectRoot, "Resources", "Img", "Album");
string albumPath = Path.Combine(projectRoot, "Resources", "Img");
coverFlow.Images.Add(new CoverFlowItem { ImageUri = new Uri(Path.Combine(albumPath, "home_test.png")), ProgressColor1 = "#215bc7", ProgressColor2 = "#fc640e" });
coverFlow.Images.Add(new CoverFlowItem { ImageUri = new Uri(Path.Combine(albumPath, "home_play.png")), ProgressColor1 = "#e73d42", ProgressColor2 = "#fd8212" });
coverFlow.Images.Add(new CoverFlowItem { ImageUri = new Uri(Path.Combine(albumPath, "home_history.png")), ProgressColor1 = "#e73d42", ProgressColor2 = "#215bc7" });
coverFlow.Images.Add(new CoverFlowItem { ImageUri = new Uri(Path.Combine(albumPath, "test_img/test_rope.png")), ProgressColor1 = "#215bc7", ProgressColor2 = "#fc640e" });
coverFlow.Images.Add(new CoverFlowItem { ImageUri = new Uri(Path.Combine(albumPath, "play_img/play_music.png")), ProgressColor1 = "#e73d42", ProgressColor2 = "#fd8212" });
coverFlow.Images.Add(new CoverFlowItem { ImageUri = new Uri(Path.Combine(albumPath, "Album/home_history.png")), ProgressColor1 = "#e73d42", ProgressColor2 = "#215bc7" });
// 默认选中第3张
coverFlow.SelectedIndex = 0;
@ -118,12 +119,23 @@ namespace Wpf_AiSportsMicrospace
// 跳转逻辑(如导航到新页面并传递参数)
//例如RaiseEvent、调用外部委托、或使用导航框架
var mainWin = Application.Current.MainWindow as Main;
var newPage = new CenterHome
//var newPage = new CenterHome
//{
// NowSelect = coverFlow.SelectedIndex == 0 ? "test" : "play"
//};
//mainWin?.SwitchPage(newPage, true);
if (coverFlow.SelectedIndex == 0)
{
NowSelect = coverFlow.SelectedIndex == 0 ? "test" : "play"
};
var newPage = new GroupJumpRope();
mainWin?.SwitchPage(newPage, true);
}
else
{
var newPage = new MusicJumpRope();
mainWin?.SwitchPage(newPage, true);
}
}
//跳转二级页面
private void RouterGoNew()
@ -131,11 +143,17 @@ namespace Wpf_AiSportsMicrospace
// 跳转逻辑(如导航到新页面并传递参数)
// 例如RaiseEvent、调用外部委托、或使用导航框架
var mainWin = Application.Current.MainWindow as Main;
var newPage = new CenterHome
if (coverFlow.SelectedIndex == 0)
{
NowSelect = coverFlow.SelectedIndex == 0 ? "test" : "play"
};
var newPage = new GroupJumpRope();
mainWin?.SwitchPage(newPage, true);
}
else
{
var newPage = new MusicJumpRope();
mainWin?.SwitchPage(newPage, true);
}
}
}
}

View File

@ -492,9 +492,6 @@ namespace Wpf_AiSportsMicrospace.Views
return lastState;
}
/// <summary>
/// 添加带渐变光的圆圈(中心红色,边缘蓝色)
/// </summary>
private SportUserItem AddUserItem(double centerX, double centerY, int index)
{
var userItem = new SportUserItem();

View File

@ -1,12 +1,37 @@
<Window x:Class="Wpf_AiSportsMicrospace.Views.MusicJumpRope"
<UserControl x:Class="Wpf_AiSportsMicrospace.Views.JumpRope.MusicJumpRope"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl"
mc:Ignorable="d"
Title="MusicJumpRope" Height="450" Width="800">
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"/>
</Grid.Background>
<Image
Source="/Resources/Img/test_img/one_rope/title.png"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Width="615"
Margin="0,0,0,0"
/>
<Grid Height="1080" Width="1920" x:Name="userBox"/>
<Grid Width="220" Height="130" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="00,40,60,0" Visibility="Hidden" x:Name="countdownGrid">
<Border Background="#005fff" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" CornerRadius="30" />
<TextBlock x:Name="countdownText"
Text="60"
FontSize="120"
FontWeight="Bold"
Foreground="#fff"
FontStyle="Italic"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="0,10,0,0"
TextAlignment="Center"
/>
</Grid>
</Window>
</Grid>
</UserControl>

View File

@ -1,8 +1,7 @@
using System;
using Dto;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
@ -10,18 +9,128 @@ using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Wpf_AiSportsMicrospace.Common;
using Wpf_AiSportsMicrospace.Enum;
using Wpf_AiSportsMicrospace.MyUserControl;
using Wpf_AiSportsMicrospace.Views;
using Yztob.AiSports.Inferences.Things;
using Yztob.AiSports.Postures.Sports;
namespace Wpf_AiSportsMicrospace.Views
namespace Wpf_AiSportsMicrospace.Views.JumpRope
{
/// <summary>
/// MusicJumpRope.xaml 的交互逻辑
/// </summary>
public partial class MusicJumpRope : Window
public partial class MusicJumpRope : UserControl
{
private Main _mainWin => Application.Current.MainWindow as Main;
private MediaPlayer _mediaPlayer = new MediaPlayer();
private bool IsGameStarted = false;
private readonly object _updateLock = new object();
private readonly Dictionary<int, (string lastNumber, DateTime lastChangeTime, string currentState)> _jumpStatus = new Dictionary<int, (string, DateTime, string)>();
private MusicJumpRopeContext _musicJumpRopeContext;
public MusicJumpRope()
{
InitializeComponent();
Loaded += UserControl_Loaded;
Unloaded += UserControl_Unloaded;
_musicJumpRopeContext = new MusicJumpRopeContext();
}
private async void UserControl_Loaded(object sender, RoutedEventArgs e)
{
DrawCirclesWithText();
}
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
{
_mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
}
private void OnHumanFrameUpdated(object sender, List<Human> humans)
{
}
private void DrawCirclesWithText()
{
userBox.Children.Clear();
_musicJumpRopeContext.Sports.Clear();
_musicJumpRopeContext.UserList.Clear();
_musicJumpRopeContext.UserNumberList.Clear();
double imgWidth = userBox.ActualWidth;
double imgHeight = userBox.ActualHeight;
double radius = 100;
for (int i = 0; i < _musicJumpRopeContext.CirclePositions.Count; i++)
{
var pos = _musicJumpRopeContext.CirclePositions[i];
double x = pos.XNorm * imgWidth;
double y = pos.YNorm * imgHeight;
// 绘制发光圆
var userItem = AddUserItem(x, y, i);
// 绑定运动对象
var sport = SportBase.Create("rope-skipping");
int indexCopy = i;
var currentItem = userItem;
// 订阅事件
sport.OnTicked += (count, times) =>
{
// 更新UI
userItem.NumberText = count.ToString();
// 更新数字源
_musicJumpRopeContext.UserNumberList[indexCopy] = count.ToString();
// 改变状态为“跳绳中”
if (userItem.ImageState != "2")
userItem.ImageState = "2";
};
sport.Start();
_musicJumpRopeContext.Sports.Add(sport);
}
}
private SportUserItem AddUserItem(double centerX, double centerY, int index)
{
var userItem = new SportUserItem();
userItem.Width = 270;
userItem.Height = 560;
userItem.DisplayText = _musicJumpRopeContext.UseNameList[index];
userItem.VerticalAlignment = VerticalAlignment.Top;
userItem.HorizontalAlignment = HorizontalAlignment.Left;
userItem.ImageState = "1";
userItem.Margin = new Thickness(centerX - 120, centerY - 700, 0, 0);
// ----------- 创建上方 TextBlock ------------
var textBlock = new TextBlock
{
Text = "0", // 卡点个数
FontSize = 36,
FontWeight = FontWeights.Bold,
Foreground = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
TextAlignment = TextAlignment.Center,
Width = userItem.Width // 文本宽度和 userItem 一样
};
// 设置 TextBlock 的 Margin使其在 userItem 上方居中
double textLeft = userItem.Margin.Left;
double textTop = userItem.Margin.Top - 50; // 50 可以根据需要调整高度
textBlock.Margin = new Thickness(textLeft, textTop, 0, 0);
// 添加控件
userBox.Children.Add(userItem);
userBox.Children.Add(textBlock);
_musicJumpRopeContext.UserList.Add(userItem);
_musicJumpRopeContext.UserNumberList.Add("0");
return userItem;
}
}
}

View File

@ -260,5 +260,7 @@ namespace Wpf_AiSportsMicrospace.Views
translate.BeginAnimation(TranslateTransform.XProperty, translateAnim);
newPage.BeginAnimation(OpacityProperty, fadeAnim);
}
}
}