diff --git a/BetterGenshinImpact/Core/Recognition/OpenCv/FeatureMatch/FeatureMatcher.cs b/BetterGenshinImpact/Core/Recognition/OpenCv/FeatureMatch/FeatureMatcher.cs
index 6dae152e..1b074a1d 100644
--- a/BetterGenshinImpact/Core/Recognition/OpenCv/FeatureMatch/FeatureMatcher.cs
+++ b/BetterGenshinImpact/Core/Recognition/OpenCv/FeatureMatch/FeatureMatcher.cs
@@ -68,19 +68,20 @@ public class FeatureMatcher
///
///
///
- public Point2f[]? Match(Mat queryMat)
+ public Point2f[]? Match(Mat queryMat, Mat? queryMatMask = null)
{
- return Match(_trainKeyPoints, _trainRet, queryMat);
+ return Match(_trainKeyPoints, _trainRet, queryMat, queryMatMask);
}
///
/// 合并邻近的特征点后匹配(临近特征)
///
- ///
+ /// 查询的图
/// 上次匹配到的坐标x
/// 上次匹配到的坐标y
+ /// 查询Mask
///
- public Point2f[]? Match(Mat queryMat, int prevX, int prevY)
+ public Point2f[]? Match(Mat queryMat, int prevX, int prevY, Mat? queryMatMask = null)
{
var (cellRow, cellCol) = KeyPointFeatureBlockHelper.GetCellIndex(_trainMat, _splitRow, _splitCol, prevX, prevY);
Debug.WriteLine($"当前坐标({prevX},{prevY})在特征块({cellRow},{cellCol})中");
@@ -90,7 +91,7 @@ public class FeatureMatcher
_lastMergedBlock = KeyPointFeatureBlockHelper.MergeNeighboringFeatures(_blocks, _trainRet, cellRow, cellCol);
}
- return Match(_lastMergedBlock.KeyPointArray, _lastMergedBlock.Descriptor!, queryMat);
+ return Match(_lastMergedBlock.KeyPointArray, _lastMergedBlock.Descriptor!, queryMat, queryMatMask);
}
///
@@ -99,14 +100,15 @@ public class FeatureMatcher
///
///
///
+ ///
///
- public Point2f[]? Match(KeyPoint[] trainKeyPoints, Mat trainRet, Mat queryMat)
+ public Point2f[]? Match(KeyPoint[] trainKeyPoints, Mat trainRet, Mat queryMat, Mat? queryMatMask = null)
{
SpeedTimer speedTimer = new();
using var queryRet = new Mat();
- _feature2D.DetectAndCompute(queryMat, null, out var queryKeyPoints, queryRet);
+ _feature2D.DetectAndCompute(queryMat, queryMatMask, out var queryKeyPoints, queryRet);
speedTimer.Record("模板生成KeyPoint");
using var flnMatcher = new FlannBasedMatcher();
diff --git a/BetterGenshinImpact/GameTask/AutoTrackPath/AutoTrackPathTask.cs b/BetterGenshinImpact/GameTask/AutoTrackPath/AutoTrackPathTask.cs
index bbf89b44..d7d0ffca 100644
--- a/BetterGenshinImpact/GameTask/AutoTrackPath/AutoTrackPathTask.cs
+++ b/BetterGenshinImpact/GameTask/AutoTrackPath/AutoTrackPathTask.cs
@@ -12,6 +12,8 @@ using BetterGenshinImpact.GameTask.AutoFight.Assets;
using BetterGenshinImpact.GameTask.AutoFight.Config;
using BetterGenshinImpact.GameTask.AutoGeniusInvokation.Exception;
using BetterGenshinImpact.GameTask.AutoTrackPath.Model;
+using BetterGenshinImpact.GameTask.Common;
+using BetterGenshinImpact.GameTask.Common.Element.Assets;
using BetterGenshinImpact.GameTask.Common.Map;
using BetterGenshinImpact.GameTask.Model.Area;
using BetterGenshinImpact.GameTask.Model.Enum;
@@ -42,11 +44,19 @@ public class AutoTrackPathTask
{ "枫丹", [4515, 3631] },
};
+ private GiPath _way;
+
+ // 视角偏移移动单位
+ private const int CharMovingUnit = 100;
+
public AutoTrackPathTask(AutoTrackPathParam taskParam)
{
_taskParam = taskParam;
var json = File.ReadAllText(Global.Absolute(@"GameTask\AutoTrackPath\Assets\tp.json"));
- _tpPositions = JsonSerializer.Deserialize>(json, ConfigService.JsonOptions) ?? throw new Exception("tp.json deserialize failed"); ;
+ _tpPositions = JsonSerializer.Deserialize>(json, ConfigService.JsonOptions) ?? throw new Exception("tp.json deserialize failed");
+
+ var wayJson = File.ReadAllText(Global.Absolute(@"log\way\way1.json"));
+ _way = JsonSerializer.Deserialize(wayJson, ConfigService.JsonOptions) ?? throw new Exception("way json deserialize failed");
}
public async void Start()
@@ -103,40 +113,88 @@ public class AutoTrackPathTask
public void DoTask()
{
- // 解析路线,第一个点为起点
+ // 1. 传送到最近的传送点
+ var first = _way.WayPointList[0]; // 解析路线,第一个点为起点
+ Tp(first.Pt.X, first.Pt.Y);
- // 找到起点最近的传送点位置
+ // 2. 等待传送完成
+ Sleep(1000);
+ NewRetry.Do(() =>
+ {
+ var ra = GetRectAreaFromDispatcher();
+ var miniMapMat = GetMiniMapMat(ra);
+ if (miniMapMat == null)
+ {
+ throw new RetryException("等待传送完成");
+ }
+ }, TimeSpan.FromSeconds(1), 100);
+ Logger.LogInformation("传送完成");
- // 初始化全地图特征
+ // 3. 横向移动偏移量校准,移动指定偏移、按下W后识别朝向
+ var angleOffset = GetOffsetAngle();
- // --- 地图传送模块 ---
+ // 4. 针对点位进行直线追踪
- // M 打开地图识别当前位置,中心点为当前位置
+ // 循环每个点位
- // 计算传送点位置离哪个地图切换后的中心点最近,切换到该地图
+ // 识别当前位置、人物朝向任务 偏差太大要修正
- // 快速移动到目标传送点所在的区域
+ // 计算当前位置到目标点的角度
- // 计算坐标后点击
+ // 旋转到目标角度
- // 触发一次快速传送功能
+ // 移动到目标点 不用太精准,只要在一定范围内就行
- // --- 地图传送模块 ---
-
- // 横向移动偏移量校准,移动指定偏移、按下W后识别朝向
-
- // 针对点位进行直线追踪
+ // 移动时循环识别当前位置、人物朝向任务
}
- public void Tp(string name)
+ public void Track(List pList)
{
- // 通过大地图传送到指定传送点
}
+ public int GetOffsetAngle()
+ {
+ var angle1 = GetCharacterOrientationAngle();
+ Simulation.SendInput.Mouse.MoveMouseBy(CharMovingUnit, 0).Sleep(200)
+ .Keyboard.KeyPress(User32.VK.VK_W).Sleep(500);
+ var angle2 = GetCharacterOrientationAngle();
+ var angleOffset = angle2 - angle1;
+ Logger.LogInformation("横向移动偏移量校准:鼠标平移100单位,角度转动{AngleOffset}", angleOffset);
+ return angleOffset;
+ }
+
+ public Mat? GetMiniMapMat(ImageRegion ra)
+ {
+ var paimon = ra.Find(ElementAssets.Instance.PaimonMenuRo);
+ if (paimon.IsExist())
+ {
+ return new Mat(ra.SrcMat, new Rect(paimon.X + 24, paimon.Y - 15, 210, 210));
+ }
+ return null;
+ }
+
+ public int GetCharacterOrientationAngle()
+ {
+ var ra = GetRectAreaFromDispatcher();
+ var miniMapMat = GetMiniMapMat(ra);
+ if (miniMapMat == null)
+ {
+ throw new InvalidOperationException("当前不在主界面");
+ }
+
+ var angle = CharacterOrientation.Compute(miniMapMat);
+ Logger.LogInformation("当前角度:{Angle}", angle);
+ CameraOrientation.DrawDirection(ra, angle);
+ return angle;
+ }
+
+ ///
+ /// 通过大地图传送到指定坐标最近的传送点,然后移动到指定坐标
+ ///
+ ///
+ ///
public void Tp(double tpX, double tpY)
{
- // 通过大地图传送到指定坐标最近的传送点,然后移动到指定坐标
-
// 获取最近的传送点位置
var (x, y) = GetRecentlyTpPoint(tpX, tpY);
Logger.LogInformation("({TpX},{TpY}) 最近的传送点位置 ({X},{Y})", tpX, tpY, x, y);
@@ -337,6 +395,11 @@ public class AutoTrackPathTask
}
}
+ public void Tp(string name)
+ {
+ // 通过大地图传送到指定传送点
+ }
+
public void TpByF1(string name)
{
// 传送到指定传送点
diff --git a/BetterGenshinImpact/GameTask/AutoTrackPath/Model/GiPathPoint.cs b/BetterGenshinImpact/GameTask/AutoTrackPath/Model/GiPathPoint.cs
index 0719bf63..0c6978e2 100644
--- a/BetterGenshinImpact/GameTask/AutoTrackPath/Model/GiPathPoint.cs
+++ b/BetterGenshinImpact/GameTask/AutoTrackPath/Model/GiPathPoint.cs
@@ -22,11 +22,11 @@ public class GiPathPoint
public static GiPathPoint BuildFrom(Rect matchRect, int index)
{
- var pt = MapCoordinate.Main1024ToGame(matchRect.GetCenterPoint());
+ var pt = MapCoordinate.Main2048ToGame(matchRect.GetCenterPoint());
return new GiPathPoint
{
Pt = pt,
- MatchRect = new Rect(pt, matchRect.Size),
+ MatchRect = matchRect,
Index = index,
Time = DateTime.Now
};
diff --git a/BetterGenshinImpact/GameTask/AutoTrackPath/MovementControl.cs b/BetterGenshinImpact/GameTask/AutoTrackPath/MovementControl.cs
new file mode 100644
index 00000000..dc90c748
--- /dev/null
+++ b/BetterGenshinImpact/GameTask/AutoTrackPath/MovementControl.cs
@@ -0,0 +1,33 @@
+using BetterGenshinImpact.Core.Simulator;
+using BetterGenshinImpact.Model;
+using Vanara.PInvoke;
+
+namespace BetterGenshinImpact.GameTask.AutoTrackPath;
+
+public class MovementControl : Singleton
+{
+ private bool _wDown = false;
+
+ public void WDown()
+ {
+ if (!_wDown)
+ {
+ _wDown = true;
+ Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W);
+ }
+ }
+
+ public void WUp()
+ {
+ if (_wDown)
+ {
+ _wDown = false;
+ Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W);
+ }
+ }
+
+ public void SpacePress()
+ {
+ Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE);
+ }
+}
diff --git a/BetterGenshinImpact/GameTask/Common/Map/CameraOrientation.cs b/BetterGenshinImpact/GameTask/Common/Map/CameraOrientation.cs
index 979c4677..c7e52031 100644
--- a/BetterGenshinImpact/GameTask/Common/Map/CameraOrientation.cs
+++ b/BetterGenshinImpact/GameTask/Common/Map/CameraOrientation.cs
@@ -1,10 +1,9 @@
-using System;
+using BetterGenshinImpact.GameTask.Model.Area;
+using OpenCvSharp;
+using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
-using BetterGenshinImpact.GameTask.Model.Area;
-using BetterGenshinImpact.View.Drawable;
-using OpenCvSharp;
using Point = OpenCvSharp.Point;
using Size = OpenCvSharp.Size;
diff --git a/BetterGenshinImpact/GameTask/Common/Map/CharacterOrientation.cs b/BetterGenshinImpact/GameTask/Common/Map/CharacterOrientation.cs
index d5a487f2..391dade3 100644
--- a/BetterGenshinImpact/GameTask/Common/Map/CharacterOrientation.cs
+++ b/BetterGenshinImpact/GameTask/Common/Map/CharacterOrientation.cs
@@ -1,14 +1,12 @@
-using BetterGenshinImpact.View.Drawable;
-using OpenCvSharp;
+using OpenCvSharp;
+using System;
namespace BetterGenshinImpact.GameTask.Common.Map;
public class CharacterOrientation
{
- public static void Compute(CaptureContent content)
+ public static int Compute(Mat mat)
{
- var mat = new Mat(content.CaptureRectArea.SrcMat, new Rect(62, 19, 212, 212));
-
var splitMat = mat.Split();
// 1. 红蓝通道按位与
@@ -93,12 +91,20 @@ public class CharacterOrientation
maxBlackCount = blackCount;
correctP1 = midPoint; // 底边中点
correctP2 = targetPoint; // 顶点
+
+ // 计算弧度
+ double radians = Math.Atan2(correctP2.Y - correctP1.Y, correctP2.X - correctP1.X);
+
+ // 将弧度转换为度数
+ double angle = radians * (180.0 / Math.PI);
+ return (int)angle;
}
}
// VisionContext.Instance().DrawContent.PutLine("co", new LineDrawable(correctP1, correctP2 + (correctP2 - correctP1) * 3));
}
}
+ return -1;
}
static Point Midpoint(Point p1, Point p2)
diff --git a/BetterGenshinImpact/GameTask/Common/Map/EntireMap.cs b/BetterGenshinImpact/GameTask/Common/Map/EntireMap.cs
index 826313b7..daeade1d 100644
--- a/BetterGenshinImpact/GameTask/Common/Map/EntireMap.cs
+++ b/BetterGenshinImpact/GameTask/Common/Map/EntireMap.cs
@@ -81,19 +81,20 @@ public class EntireMap : Singleton
/// 移动匹配
///
/// 灰度图
+ /// 遮罩
///
- public Rect GetMiniMapPositionByFeatureMatch(Mat greyMat)
+ public Rect GetMiniMapPositionByFeatureMatch(Mat greyMat, Mat? mask = null)
{
try
{
Point2f[]? pArray;
if (_prevX != -1 && _prevY != -1)
{
- pArray = _featureMatcher.Match(greyMat, _prevX, _prevY);
+ pArray = _featureMatcher.Match(greyMat, _prevX, _prevY, mask);
}
else
{
- pArray = _featureMatcher.Match(greyMat);
+ pArray = _featureMatcher.Match(greyMat, mask);
}
if (pArray == null || pArray.Length < 4)
diff --git a/BetterGenshinImpact/Helpers/MathHelper.cs b/BetterGenshinImpact/Helpers/MathHelper.cs
new file mode 100644
index 00000000..07900863
--- /dev/null
+++ b/BetterGenshinImpact/Helpers/MathHelper.cs
@@ -0,0 +1,29 @@
+using System;
+using OpenCvSharp;
+
+namespace BetterGenshinImpact.Helpers;
+
+public class MathHelper
+{
+ ///
+ /// 点到直线的最短距离
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static double CalculateDistance(Point point, Point point1, Point point2)
+ {
+ // 直线的方向向量
+ double a = point2.Y - point1.Y;
+ double b = point1.X - point2.X;
+ double c = point2.X * point1.Y - point1.X * point2.Y;
+
+ // 使用距离公式计算点到直线的最短距离
+ double numerator = Math.Abs(a * point.X + b * point.Y + c);
+ double denominator = Math.Sqrt(a * a + b * b);
+ double distance = numerator / denominator;
+
+ return distance;
+ }
+}