打地鼠

This commit is contained in:
tanglong 2026-02-06 15:53:21 +08:00
parent 2803691094
commit d9e2a90a22
4 changed files with 59 additions and 88 deletions

View File

@ -18,7 +18,7 @@ namespace Dto
public List<WhackAMoleUserControl> UserList { get; private set; } public List<WhackAMoleUserControl> UserList { get; private set; }
public List<string> UserNumberList { get; private set; } public List<string> UserNumberList { get; private set; }
public List<SportBase> Sports { get; private set; } public List<SportBase> Sports { get; private set; }
public List<string> UseNameList { get; private set; } = new() public List<string> UserNameList { get; private set; } = new()
{ {
"游客-A", "游客-B", "游客-C", "游客-D", "游客-E", "游客-F", "游客-G", "游客-H", "游客-I", "游客-F", "游客-J" "游客-A", "游客-B", "游客-C", "游客-D", "游客-E", "游客-F", "游客-G", "游客-H", "游客-I", "游客-F", "游客-J"
}; };
@ -47,7 +47,7 @@ namespace Dto
.Select((numStr, index) => new .Select((numStr, index) => new
{ {
Index = index, Index = index,
Name = UseNameList[index], Name = UserNameList[index],
Number = int.TryParse(numStr, out var n) ? n : 0 Number = int.TryParse(numStr, out var n) ? n : 0
}) })
.OrderByDescending(x => x.Number) .OrderByDescending(x => x.Number)

View File

@ -98,7 +98,7 @@ namespace Wpf_AiSportsMicrospace.MyUserControl
/// 外部上下文,用于更新用户分数列表 /// 外部上下文,用于更新用户分数列表
/// 注意:需要根据实际项目调整这个引用方式 /// 注意:需要根据实际项目调整这个引用方式
/// </summary> /// </summary>
private dynamic _groupJumpRopeContext; private WhackAMoleContext _whackAMoleContext;
#endregion #endregion
@ -153,8 +153,6 @@ namespace Wpf_AiSportsMicrospace.MyUserControl
#region 私有方法 #region 私有方法
/// <summary> /// <summary>
/// 初始化计时器 /// 初始化计时器
/// </summary> /// </summary>
@ -173,6 +171,8 @@ namespace Wpf_AiSportsMicrospace.MyUserControl
_hitDetectionTimer = new DispatcherTimer(); _hitDetectionTimer = new DispatcherTimer();
_hitDetectionTimer.Interval = TimeSpan.FromMilliseconds(50); _hitDetectionTimer.Interval = TimeSpan.FromMilliseconds(50);
_hitDetectionTimer.Tick += HitDetectionTimer_Tick; _hitDetectionTimer.Tick += HitDetectionTimer_Tick;
_whackAMoleContext = new WhackAMoleContext();
} }
/// <summary> /// <summary>
@ -191,10 +191,10 @@ namespace Wpf_AiSportsMicrospace.MyUserControl
var parent = this.Parent as FrameworkElement; var parent = this.Parent as FrameworkElement;
while (parent != null) while (parent != null)
{ {
var contextProperty = parent.GetType().GetProperty("_groupJumpRopeContext"); var contextProperty = parent.GetType().GetProperty("_whackAMoleContext");
if (contextProperty != null) if (contextProperty != null)
{ {
_groupJumpRopeContext = contextProperty.GetValue(parent); _whackAMoleContext = (WhackAMoleContext)contextProperty.GetValue(parent);
break; break;
} }
parent = parent.Parent as FrameworkElement; parent = parent.Parent as FrameworkElement;
@ -227,7 +227,7 @@ namespace Wpf_AiSportsMicrospace.MyUserControl
/// </summary> /// </summary>
private void TryGetContext() private void TryGetContext()
{ {
if (_groupJumpRopeContext == null) if (_whackAMoleContext == null)
{ {
InitializeContext(); InitializeContext();
} }
@ -240,11 +240,11 @@ namespace Wpf_AiSportsMicrospace.MyUserControl
{ {
TryGetContext(); TryGetContext();
if (_groupJumpRopeContext != null) if (_whackAMoleContext != null)
{ {
try try
{ {
var userNumberList = _groupJumpRopeContext.GetType().GetProperty("UserNumberList")?.GetValue(_groupJumpRopeContext) as List<int>; var userNumberList = _whackAMoleContext.GetType().GetProperty("UserNumberList")?.GetValue(_whackAMoleContext) as List<int>;
if (userNumberList != null && Index >= 0 && Index < userNumberList.Count) if (userNumberList != null && Index >= 0 && Index < userNumberList.Count)
{ {
userNumberList[Index] = _score; userNumberList[Index] = _score;
@ -264,7 +264,7 @@ namespace Wpf_AiSportsMicrospace.MyUserControl
{ {
if (!_isInitialized) { if (!_isInitialized) {
InitImageContal(); InitImageContal();
name.Text = _groupJumpRopeContext.UserNameList[Index]; name.Text = _whackAMoleContext.UserNameList[Index];
} }
// 重置分数 // 重置分数
@ -680,7 +680,7 @@ namespace Wpf_AiSportsMicrospace.MyUserControl
/// <param name="context">外部上下文对象</param> /// <param name="context">外部上下文对象</param>
public void SetContext(dynamic context) public void SetContext(dynamic context)
{ {
_groupJumpRopeContext = context; _whackAMoleContext = context;
} }
#endregion #endregion

View File

@ -175,7 +175,7 @@ namespace Wpf_AiSportsMicrospace
else else
{ {
//var newPage = new TrainingRecords(); //var newPage = new TrainingRecords();
var newPage = new StandingLeap(); var newPage = new WhackAMole();
mainWin?.SwitchPageWithMaskAnimation(newPage, true); mainWin?.SwitchPageWithMaskAnimation(newPage, true);
} }
} }

View File

@ -43,14 +43,14 @@ namespace Views.SquatFu
private GameState _currentGameState = GameState.NotStarted; private GameState _currentGameState = GameState.NotStarted;
private readonly object _updateLock = new object(); private readonly object _updateLock = new object();
private readonly Dictionary<int, (string lastNumber, DateTime lastChangeTime, string currentState)> _jumpStatus = new Dictionary<int, (string, DateTime, string)>(); private readonly Dictionary<int, (string lastNumber, DateTime lastChangeTime, string currentState)> _jumpStatus = new Dictionary<int, (string, DateTime, string)>();
private WhackAMoleContext _groupJumpRopeContext; private WhackAMoleContext _WhackAMoleContext;
public WhackAMole() public WhackAMole()
{ {
InitializeComponent(); InitializeComponent();
Loaded += UserControl_Loaded; Loaded += UserControl_Loaded;
Unloaded += UserControl_Unloaded; Unloaded += UserControl_Unloaded;
_groupJumpRopeContext = new WhackAMoleContext(); _WhackAMoleContext = new WhackAMoleContext();
} }
private async void UserControl_Loaded(object sender, RoutedEventArgs e) private async void UserControl_Loaded(object sender, RoutedEventArgs e)
@ -62,13 +62,20 @@ namespace Views.SquatFu
using var scope = App.AppHost.Services.CreateScope(); using var scope = App.AppHost.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>(); var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var cfg = await db.GroupPoints.FirstOrDefaultAsync(x => x.Code == AppSettings.Code); var cfg = await db.GroupPoints.FirstOrDefaultAsync(x => x.Code == AppSettings.Code);
//var pointlist = JsonSerializer.Deserialize<List<(double, double)>>(cfg!.PointsJson); List<(double XNorm, double YNorm)> pointlist = new List<(double XNorm, double YNorm)>();
List<(double XNorm, double YNorm)> pointlist = var points = new[] { cfg.Point1, cfg.Point2, cfg.Point3,
[(cfg.Point1.X, cfg.Point1.Y),(cfg.Point2.X, cfg.Point2.Y), cfg.Point4, cfg.Point5, cfg.Point6,
(cfg.Point3.X, cfg.Point3.Y), (cfg.Point4.X, cfg.Point4.Y), cfg.Point7, cfg.Point8, cfg.Point9, cfg.Point10 };
(cfg.Point5.X, cfg.Point5.Y),(cfg.Point6.X, cfg.Point6.Y)];
_groupJumpRopeContext.CirclePositions = pointlist; foreach (var point in points)
{
if (point != null)
{
pointlist.Add((point.X, point.Y));
}
}
_WhackAMoleContext.CirclePositions = pointlist;
DrawCirclesWithText(); DrawCirclesWithText();
@ -282,7 +289,7 @@ namespace Views.SquatFu
{ {
countdownText.Text = "GO!"; countdownText.Text = "GO!";
countdownGrid.Visibility = Visibility.Hidden; countdownGrid.Visibility = Visibility.Hidden;
_groupJumpRopeContext.UserList.ForEach(x => _WhackAMoleContext.UserList.ForEach(x =>
{ {
x.Start(); x.Start();
}); });
@ -305,7 +312,7 @@ namespace Views.SquatFu
countdownGrid.Visibility = Visibility.Hidden; countdownGrid.Visibility = Visibility.Hidden;
_groupJumpRopeContext.UserList.ForEach(x => _WhackAMoleContext.UserList.ForEach(x =>
{ {
Tiggle += 1; Tiggle += 1;
x.TriggerValue = Tiggle; x.TriggerValue = Tiggle;
@ -314,7 +321,7 @@ namespace Views.SquatFu
_mainWin.HumanFrameUpdated -= OnHumanFrameUpdated; _mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
_mainWin.WebcamClient.StopExtract(); _mainWin.WebcamClient.StopExtract();
RankingItemList = _groupJumpRopeContext.UpdateWhackAMoleRankList(); RankingItemList = _WhackAMoleContext.UpdateWhackAMoleRankList();
ShowRankingBoard(RankingItemList); ShowRankingBoard(RankingItemList);
Utils.StopBackgroundMusic(); Utils.StopBackgroundMusic();
@ -340,14 +347,14 @@ namespace Views.SquatFu
private void DrawCirclesWithText() private void DrawCirclesWithText()
{ {
userBox.Children.Clear(); userBox.Children.Clear();
_groupJumpRopeContext.Sports.Clear(); _WhackAMoleContext.Sports.Clear();
_groupJumpRopeContext.UserList.Clear(); _WhackAMoleContext.UserList.Clear();
_groupJumpRopeContext.UserNumberList.Clear(); _WhackAMoleContext.UserNumberList.Clear();
for (int i = 0; i < _groupJumpRopeContext.CirclePositions.Count; i++) for (int i = 0; i < _WhackAMoleContext.CirclePositions.Count; i++)
{ {
var pos = _groupJumpRopeContext.CirclePositions[i]; var pos = _WhackAMoleContext.CirclePositions[i];
double x = pos.XNorm ; double x = pos.XNorm ;
double y = pos.YNorm ; double y = pos.YNorm ;
@ -370,85 +377,49 @@ namespace Views.SquatFu
// 更新UI // 更新UI
//userItem.NumberText = count.ToString(); //userItem.NumberText = count.ToString();
// 更新数字源 // 更新数字源
_groupJumpRopeContext.UserNumberList[indexCopy] = count.ToString(); _WhackAMoleContext.UserNumberList[indexCopy] = count.ToString();
// 改变状态为“跳绳中” // 改变状态为“跳绳中”
if (userItem.TriggerValue != 2) if (userItem.TriggerValue != 2)
userItem.TriggerValue = 2; userItem.TriggerValue = 2;
}; };
sport.Start(); sport.Start();
_groupJumpRopeContext.Sports.Add(sport); _WhackAMoleContext.Sports.Add(sport);
} }
} }
private void UpdateCircleCounts(List<Human> humans) private void UpdateCircleCounts(List<Human> humans)
{ {
// 放宽一点的圈半径(归一化) double halfW = AppSettings.AreaSize.X;
double radiusNormX = 0.10; double halfH = AppSettings.AreaSize.Y;
double radiusNormY = 0.14;
for (int i = 0; i < _groupJumpRopeContext.CirclePositions.Count; i++) int circleCount = _WhackAMoleContext.CirclePositions.Count;
for (int i = 0; i < circleCount; i++)
{ {
var circleX = _groupJumpRopeContext.CirclePositions[i].XNorm; var circle = _WhackAMoleContext.CirclePositions[i];
var circleY = _groupJumpRopeContext.CirclePositions[i].YNorm; double cx = circle.XNorm;
double cy = circle.YNorm;
Human humanInCircle = null; Human targetHuman = null;
foreach (var hu in humans) // 1️⃣ 找圈内的人(单脚命中即可)
foreach (var h in humans)
{ {
var rightFoot = hu.Keypoints.FirstOrDefault(k => k.Name == "right_ankle"); if (sportOperate.IsAnyFootInCircle(h, cx, cy, halfW, halfH))
var leftFoot = hu.Keypoints.FirstOrDefault(k => k.Name == "left_ankle");
if (rightFoot == null && leftFoot == null)
continue;
bool rightInCircle = false;
bool leftInCircle = false;
// 右脚判断
if (rightFoot != null)
{ {
double xRightNorm = rightFoot.X / userBox.ActualWidth; targetHuman = h;
double yRightNorm = rightFoot.Y / userBox.ActualHeight; break; // 每个圈只认一个人
rightInCircle =
xRightNorm >= (circleX - radiusNormX) &&
xRightNorm <= (circleX + radiusNormX) &&
yRightNorm >= (circleY - radiusNormY) &&
yRightNorm <= (circleY + radiusNormY);
}
// 左脚判断
if (leftFoot != null)
{
double xLeftNorm = leftFoot.X / userBox.ActualWidth;
double yLeftNorm = leftFoot.Y / userBox.ActualHeight;
leftInCircle =
xLeftNorm >= (circleX - radiusNormX) &&
xLeftNorm <= (circleX + radiusNormX) &&
yLeftNorm >= (circleY - radiusNormY) &&
yLeftNorm <= (circleY + radiusNormY);
}
// ✅ 只要有一只脚在圈内
if (rightInCircle || leftInCircle)
{
humanInCircle = hu;
break;
} }
} }
bool hasHuman = humanInCircle != null; bool hasHuman = targetHuman != null;
//lock (_updateLock)
//{
// _groupJumpRopeContext.UserList[i].ImageState =
// GetJumpState(i, hasHuman);
//}
// 3️⃣ 推送跳绳计数
if (hasHuman) if (hasHuman)
{ {
_groupJumpRopeContext.Sports[i].Pushing(humanInCircle); _WhackAMoleContext.Sports[i].Pushing(targetHuman);
} }
} }
} }
@ -466,8 +437,8 @@ namespace Views.SquatFu
//userItem.Margin = new Thickness(centerX - (index == 0 ? 80 : index == 6 ? 190 : 135), centerY - 540, 0, 0); //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); userItem.Margin = new Thickness(centerX , centerY - 600 - 50, 0, 0);
userBox.Children.Add(userItem); userBox.Children.Add(userItem);
_groupJumpRopeContext.UserList.Add(userItem); _WhackAMoleContext.UserList.Add(userItem);
_groupJumpRopeContext.UserNumberList.Add("0"); _WhackAMoleContext.UserNumberList.Add("0");
return userItem; // return userItem; //
} }