fix: 更高效的领奖算法

This commit is contained in:
秋云
2025-05-12 05:25:00 +08:00
parent 992134b5ff
commit 1d47acf6b0

View File

@@ -1144,131 +1144,157 @@ async function openCustomMarks() {
} }
} }
const paimonMenuRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/icon/paimon_menu.png"), 0, 0, genshin.width / 3.0, genshin.width / 5.0);
const boxIconRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/icon/box.png"));
/** /**
* 自动导航到地脉花奖励点 * 自动导航到地脉花奖励点
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
async function autoNavigateToReward() { async function autoNavigateToReward() {
// 定义识别对象 // 定义识别对象
const boxIconRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/icon/box.png"));
const rewardTextRo = RecognitionObject.Ocr(1210, 515, 200, 50); // 领奖区域检测 const cts = new CancellationTokenSource();
let advanceNum = 0; // 前进次数
try {
// 调整初始视角为俯视角
log.info("调整视角...");
middleButtonClick();
await sleep(300);
// 调整初始视角为俯视角 log.info("开始自动导航到地脉花...");
log.info("调整为俯视视角...");
middleButtonClick(); // 启动文字检测任务
await sleep(1000); let rewardDetectionPromise = startRewardTextDetection(cts);
moveMouseBy(0, 1030);
await sleep(500); // 启动导航任务
moveMouseBy(0, 920); navigateTowardReward(cts.token);
await sleep(500);
moveMouseBy(0, 710); // 等待文字检测任务完成
await sleep(500); await rewardDetectionPromise;
log.info("开始自动导航到地脉花..."); // 取消导航任务
while (true) { cts.cancel();
// 1. 优先检查是否已到达领奖点 keyUp("w");
let captureRegion = captureGameRegion(); log.info("已到达领奖点");
let rewardTextArea = captureRegion.DeriveCrop(1210, 515, 200, 50); } catch (error) {
let ocrResults = rewardTextArea.findMulti(RecognitionObject.ocrThis); cts.cancel();
log.error(`导航过程中出错: ${error}`);
throw error;
if (advanceNum % 15 == 0 && advanceNum >= 10) { }
log.warn("前进又超时15次啦先往旁边挪挪再继续试试") }
keyDown("s");
await sleep(500); /**
keyUp("s"); * 监测文字区域,检测到地脉之花文字时返回
middleButtonClick(); * @param {CancellationTokenSource} cts - 取消令牌源
await sleep(1000); * @returns {Promise<boolean>} - 是否检测到文字
keyDown("w"); */
await sleep(1000); async function startRewardTextDetection(cts) {
keyUp("w"); return new Promise((resolve, reject) => {
} (async () => {
else if (advanceNum > 45) { try {
throw new Error('前进时间超时'); while (!cts.token.isCancellationRequested) {
} let captureRegion = captureGameRegion();
// 检测到地脉之花文字则结束 let rewardTextArea = captureRegion.DeriveCrop(1210, 515, 200, 200);
else if (ocrResults.count > 0 && ocrResults[0].text.trim().length > 0) { let ocrResults = rewardTextArea.findMulti(RecognitionObject.ocrThis);
for (let i = 0; i < ocrResults.count; i++) {
if (ocrResults[i].text.includes("地脉之花")) { if (ocrResults.count > 0) {
log.info("已到达领奖点,检测到文字: " + ocrResults[i].text); for (let i = 0; i < ocrResults.count; i++) {
return; if (ocrResults[i].text.includes("接触")
} || ocrResults[i].text.includes("地脉")
} || ocrResults[i].text.includes("之花")
} ) {
log.info("检测到文字: " + ocrResults[i].text);
// 2. 未到达领奖点,则调整视野 resolve(true);
await adjustViewForReward(boxIconRo, advanceNum); return;
}
// 3. 前进一小步 }
keyDown("w"); }
await sleep(900);
await sleep(200);
}
} catch (error) {
reject(error);
}
})();
});
}
/**
* 导航向奖励点
* @param {CancellationToken} token - 取消令牌
* @returns {Promise<void>}
*/
async function navigateTowardReward(token) {
let advanceNum = 0; // 前进次数
try {
while (!token.isCancellationRequested) {
if (advanceNum % 15 == 0 && advanceNum >= 10) {
log.warn("前进又超时15次啦先往旁边挪挪再继续试试")
keyUp("w");
keyDown("s");
await sleep(1000);
keyUp("s");
keyDown("w"); // 恢复前进
}
else if (advanceNum > 45) {
keyUp("w");
throw new Error('前进时间超时');
}
// 调整视野
await adjustViewForReward(boxIconRo, advanceNum);
keyDown("w");
// 小暂停让角色移动
await sleep(300);
advanceNum++;
}
} finally {
// 确保任何情况下都会释放按键
keyUp("w"); keyUp("w");
await sleep(100); // 等待角色移动稳定
advanceNum++;
} }
} }
/** /**
* 调整视野直到图标位于正前方 * 调整视野直到图标位于正前方
* @param {Object} boxIconRo - 宝箱图标识别对象 * @param {Object} boxIconRo - 宝箱图标识别对象
* @param {number} advanceNum - 当前前进次数
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
async function adjustViewForReward(boxIconRo, advanceNum) { async function adjustViewForReward(boxIconRo) {
for (let i = 0; i < 100; i++) { const screenCenterX = 960;
const screenCenterY = 540;
// 每10次执行一轮异常页面检查
if (i % 10 == 0) { let captureRegion = captureGameRegion();
// 识别误触发领取导致超时的情况 let resList = captureRegion.findMulti(RecognitionObject.ocrThis)
let resList = captureGameRegion().findMulti(RecognitionObject.ocrThis); if(captureRegion.Find(paimonMenuRo).IsEmpty()) {
if (resList && resList.count > 0) { log.info("误触发其他页面,尝试关闭页面")
for (let i = 0; i < resList.count; i++) { await genshin.returnMainUi();
let res = resList[i]; } else if(resList.count > 0) {
if (res.text.includes("原粹树脂")) { for (let i = 0; i < resList.count; i++) {
log.info("误触发领取页面,尝试关闭页面") let res = resList[i];
keyPress("ESCAPE"); if (res.text.includes("原粹树脂")) {
await sleep(500); log.info("误触发领取页面,尝试关闭页面")
keyPress("ESCAPE");
await sleep(500);
await genshin.returnMainUi();
}
}
}
// 识别误触发其他页面导致超时的情况
const paimonMenuRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/icon/paimon_menu.png"), 0, 0, genshin.width / 3.0, genshin.width / 5.0);
let res = captureGameRegion().Find(paimonMenuRo);
if (res.isEmpty()) {
log.info("误触发其他页面,尝试关闭页面")
click(960, 800);
keyPress("ESCAPE");
await sleep(500);
keyPress("ESCAPE");
await sleep(500);
await genshin.returnMainUi(); await genshin.returnMainUi();
} }
} }
let captureRegion = captureGameRegion();
let iconRes = captureRegion.Find(boxIconRo);
if (!iconRes) {
// 未找到图标,小幅度转动视角
moveMouseBy(20, 0);
await sleep(100);
continue;
}
if (iconRes.x >= 920 && iconRes.x <= 980 && iconRes.y <= 540) {
log.info(`视野已调正,前进第 ${advanceNum}`);
return;
} else {
// 小幅度调整
let adjustAmount = iconRes.x < 920 ? -20 : 20;
let adjustAmount2 = iconRes.y < 540 ? 1 : 10;
moveMouseBy(adjustAmount * adjustAmount2, 0);
await sleep(100);
}
} }
// throw new Error('视野调整超时'); let iconRes = captureRegion.Find(boxIconRo);
if (!iconRes) {
throw new Error('未找到图标,没有地脉花');
}
// 检查图标是否位于中心正上方
const xOffset = iconRes.x - screenCenterX;
const horizontalTolerance = 40;
const isHorizontallyAligned = Math.abs(xOffset) <= horizontalTolerance;
const isAboveCenter = iconRes.y < screenCenterY;
if (isHorizontallyAligned && isAboveCenter) {
return true;
} else {
moveMouseBy(xOffset, 0);
await sleep(100);
}
} }