打地鼠

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<string> UserNumberList { 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"
};
@ -47,7 +47,7 @@ namespace Dto
.Select((numStr, index) => new
{
Index = index,
Name = UseNameList[index],
Name = UserNameList[index],
Number = int.TryParse(numStr, out var n) ? n : 0
})
.OrderByDescending(x => x.Number)

View File

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

View File

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

View File

@ -43,14 +43,14 @@ namespace Views.SquatFu
private GameState _currentGameState = GameState.NotStarted;
private readonly object _updateLock = new object();
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()
{
InitializeComponent();
Loaded += UserControl_Loaded;
Unloaded += UserControl_Unloaded;
_groupJumpRopeContext = new WhackAMoleContext();
_WhackAMoleContext = new WhackAMoleContext();
}
private async void UserControl_Loaded(object sender, RoutedEventArgs e)
@ -62,13 +62,20 @@ namespace Views.SquatFu
using var scope = App.AppHost.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
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 =
[(cfg.Point1.X, cfg.Point1.Y),(cfg.Point2.X, cfg.Point2.Y),
(cfg.Point3.X, cfg.Point3.Y), (cfg.Point4.X, cfg.Point4.Y),
(cfg.Point5.X, cfg.Point5.Y),(cfg.Point6.X, cfg.Point6.Y)];
_groupJumpRopeContext.CirclePositions = pointlist;
var points = new[] { cfg.Point1, cfg.Point2, cfg.Point3,
cfg.Point4, cfg.Point5, cfg.Point6,
cfg.Point7, cfg.Point8, cfg.Point9, cfg.Point10 };
foreach (var point in points)
{
if (point != null)
{
pointlist.Add((point.X, point.Y));
}
}
_WhackAMoleContext.CirclePositions = pointlist;
DrawCirclesWithText();
@ -282,7 +289,7 @@ namespace Views.SquatFu
{
countdownText.Text = "GO!";
countdownGrid.Visibility = Visibility.Hidden;
_groupJumpRopeContext.UserList.ForEach(x =>
_WhackAMoleContext.UserList.ForEach(x =>
{
x.Start();
});
@ -305,7 +312,7 @@ namespace Views.SquatFu
countdownGrid.Visibility = Visibility.Hidden;
_groupJumpRopeContext.UserList.ForEach(x =>
_WhackAMoleContext.UserList.ForEach(x =>
{
Tiggle += 1;
x.TriggerValue = Tiggle;
@ -314,7 +321,7 @@ namespace Views.SquatFu
_mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
_mainWin.WebcamClient.StopExtract();
RankingItemList = _groupJumpRopeContext.UpdateWhackAMoleRankList();
RankingItemList = _WhackAMoleContext.UpdateWhackAMoleRankList();
ShowRankingBoard(RankingItemList);
Utils.StopBackgroundMusic();
@ -340,14 +347,14 @@ namespace Views.SquatFu
private void DrawCirclesWithText()
{
userBox.Children.Clear();
_groupJumpRopeContext.Sports.Clear();
_groupJumpRopeContext.UserList.Clear();
_groupJumpRopeContext.UserNumberList.Clear();
_WhackAMoleContext.Sports.Clear();
_WhackAMoleContext.UserList.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 y = pos.YNorm ;
@ -370,85 +377,49 @@ namespace Views.SquatFu
// 更新UI
//userItem.NumberText = count.ToString();
// 更新数字源
_groupJumpRopeContext.UserNumberList[indexCopy] = count.ToString();
_WhackAMoleContext.UserNumberList[indexCopy] = count.ToString();
// 改变状态为“跳绳中”
if (userItem.TriggerValue != 2)
userItem.TriggerValue = 2;
};
sport.Start();
_groupJumpRopeContext.Sports.Add(sport);
_WhackAMoleContext.Sports.Add(sport);
}
}
private void UpdateCircleCounts(List<Human> humans)
{
// 放宽一点的圈半径(归一化)
double radiusNormX = 0.10;
double radiusNormY = 0.14;
double halfW = AppSettings.AreaSize.X;
double halfH = AppSettings.AreaSize.Y;
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 circleY = _groupJumpRopeContext.CirclePositions[i].YNorm;
var circle = _WhackAMoleContext.CirclePositions[i];
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");
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)
if (sportOperate.IsAnyFootInCircle(h, cx, cy, halfW, halfH))
{
double xRightNorm = rightFoot.X / userBox.ActualWidth;
double yRightNorm = rightFoot.Y / userBox.ActualHeight;
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;
targetHuman = h;
break; // 每个圈只认一个人
}
}
bool hasHuman = humanInCircle != null;
//lock (_updateLock)
//{
// _groupJumpRopeContext.UserList[i].ImageState =
// GetJumpState(i, hasHuman);
//}
bool hasHuman = targetHuman != null;
// 3️⃣ 推送跳绳计数
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 , centerY - 600 - 50, 0, 0);
userBox.Children.Add(userItem);
_groupJumpRopeContext.UserList.Add(userItem);
_groupJumpRopeContext.UserNumberList.Add("0");
_WhackAMoleContext.UserList.Add(userItem);
_WhackAMoleContext.UserNumberList.Add("0");
return userItem; //
}