Files
better-genshin-impact/BetterGenshinImpact/GameTask/AutoPathing/TrapEscaper.cs
2024-10-31 23:10:11 +08:00

196 lines
7.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BetterGenshinImpact.Core.Simulator;
using BetterGenshinImpact.GameTask.AutoPathing.Model;
using BetterGenshinImpact.GameTask.AutoPathing.Model.Enum;
using BetterGenshinImpact.GameTask.Common.BgiVision;
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Vanara.PInvoke;
using static BetterGenshinImpact.GameTask.Common.TaskControl;
namespace BetterGenshinImpact.GameTask.AutoPathing;
public class TrapEscaper(CancellationToken ct)
{
private readonly CameraRotateTask _rotateTask = new(ct);
private static readonly Random _random = new Random();
private int _lastActionIndex = 0;
public static DateTime LastActionTime = DateTime.UtcNow;
private static int _randomAngle = 0;
private void IncreaseRandomAngle()
{
_randomAngle += _random.Next(30, 45);
}
private void ReduceRandomAngle()
{
_randomAngle += _random.Next(-45, -30);
}
public async Task MoveTo(WaypointForTrack waypoint)
{
var startTime = DateTime.UtcNow;
bool left = false;
var screen = CaptureToRectArea();
var position = Navigation.GetPosition(screen);
LastActionTime = DateTime.UtcNow;
var targetOrientation = Navigation.GetTargetOrientation(waypoint, position);
await _rotateTask.WaitUntilRotatedTo(targetOrientation, 5);
// 按下w一直走
Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W);
while (!ct.IsCancellationRequested)
{
var now = DateTime.UtcNow;
if ((now - LastActionTime).TotalSeconds > 5)
{
break;
}
if ((now - startTime).TotalSeconds > 25)
{
Logger.LogError("卡死脱困超时!");
break;
}
screen = CaptureToRectArea();
position = Navigation.GetPosition(screen);
// 旋转视角
/* 这里的角度增加了一个randomAngle角度用来在原角度不适用的情况下修改角度以适应复杂环境
randomAngle会定期归零不会任何程度上影响路径追踪的结果指到达既设点位
randomAngle为类变量会在需要修改角度的情况下进行更改更改时会附带有重置计时器_lastActionTime的代码
总体的自动避障逻辑为:
0. 检测是否卡在障碍物上,如果是则执行大脱困
1. 检测前面是否有障碍物,如果是则执行小脱困
2. 重复0和1角度会一直增加达到“转一圈”的360度脱困效果若成功脱困则将randomAngle归零
*/
targetOrientation = Navigation.GetTargetOrientation(waypoint, position) + _randomAngle;
//执行旋转
await _rotateTask.WaitUntilRotatedTo(targetOrientation, 5);
Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_W);
//
//这里是随机角度的归零逻辑在脱困执行一秒后将randomAngle设为0以将实际角度重置为正面向点位的角度
//其实就是在一段时间内进行角度的修改以实现自动避障
if (_randomAngle != 0)
{
_randomAngle %= 360; //角度增加到360度时也会归零
if ((DateTime.UtcNow - LastActionTime).TotalSeconds > 1.5)
{
_randomAngle = 0;
}
}
// 设置为非攀爬时误进入攀爬,自动脱离(小脱困)
// 小脱困逻辑,在进入攀爬时,即后一帧会自动脱离,因此无需再执行脱困代码
// 进入攀爬就代表前面有较高的物体(障碍物)阻挡,所以必须“旋转角度”以辅助绕过障碍物!!!
// 先排除攀爬和飞行的情况
if (waypoint.MoveMode != MoveModeEnum.Climb.Code &&
waypoint.MoveMode != MoveModeEnum.Fly.Code)
if (Bv.GetMotionStatus(screen) == MotionStatus.Climb)
{
Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W);
Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_X);
Sleep(75);
Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_S);
Sleep(700);
Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_S);
LastActionTime = DateTime.UtcNow;
//这里修改了randomAngle的值用于在脱困后随机旋转角度
if (!left)
{
IncreaseRandomAngle();
}
else
{
ReduceRandomAngle();
}
continue;
}
await Delay(100, ct);
}
// 抬起w键
Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W);
}
public async Task RotateAndMove()
{
IncreaseRandomAngle();
// 脱离攀爬状态
Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_W);
Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_X);
await Delay(75, ct);
Simulation.SendInput.Mouse.LeftButtonClick();
await Delay(500, ct);
TimeSpan timeSinceLastAction = DateTime.UtcNow - LastActionTime;
if (timeSinceLastAction.TotalSeconds >= 10)
{
_lastActionIndex = 0;
}
else
{
_lastActionIndex++;
}
var difference = _lastActionIndex * 1000;
switch (_lastActionIndex % 3)
{
case 0:
// 向后移动
MoveBackward(1000 + difference);
break;
case 1:
// 向左移动
MoveLeft(700 + difference);
break;
case 2:
// 向右移动
MoveRight(700 + difference);
break;
}
LastActionTime = DateTime.UtcNow;
}
private void MoveBackward(int delay)
{
Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_S);
Sleep(500);
Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE);
Sleep(delay);
Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_S);
}
private void MoveLeft(int delay)
{
Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_A);
Sleep(300);
Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE);
Sleep(delay);
Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_A);
Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_X);
}
private void MoveRight(int delay)
{
Simulation.SendInput.Keyboard.KeyDown(User32.VK.VK_D);
Sleep(300);
Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_SPACE);
Sleep(delay);
Simulation.SendInput.Keyboard.KeyUp(User32.VK.VK_D);
Simulation.SendInput.Keyboard.KeyPress(User32.VK.VK_X);
}
}