149 lines
5.6 KiB
Python
149 lines
5.6 KiB
Python
|
|
"""
|
|||
|
|
玩家位置模块,用于获取人物当前所在坐标
|
|||
|
|
"""
|
|||
|
|
import os
|
|||
|
|
import time
|
|||
|
|
import re
|
|||
|
|
from typing import Optional, Tuple
|
|||
|
|
import cv2
|
|||
|
|
import numpy as np
|
|||
|
|
import pyautogui
|
|||
|
|
from text_finder import TextFinder
|
|||
|
|
|
|||
|
|
|
|||
|
|
class PlayerPosition:
|
|||
|
|
"""玩家位置类,用于获取人物当前所在坐标"""
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
self.screen_width, self.screen_height = pyautogui.size()
|
|||
|
|
self.text_finder = TextFinder()
|
|||
|
|
|
|||
|
|
def get_position(self) -> Optional[Tuple[float, float]]:
|
|||
|
|
"""获取人物当前所在坐标
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
Optional[Tuple[float, float]]: 坐标 (x, y),如果识别失败返回 None
|
|||
|
|
"""
|
|||
|
|
try:
|
|||
|
|
# 截图左上角区域
|
|||
|
|
region_width = self.screen_width // 3
|
|||
|
|
region_height = self.screen_height // 4
|
|||
|
|
screenshot = pyautogui.screenshot(region=(0, 0, region_width, region_height))
|
|||
|
|
os.makedirs('screenshot', exist_ok=True)
|
|||
|
|
screenshot.save('screenshot/position_screenshot.png')
|
|||
|
|
|
|||
|
|
# 使用 text_finder 识别所有文字
|
|||
|
|
text_info_list = self.text_finder.recognize_text_from_image(screenshot)
|
|||
|
|
|
|||
|
|
if not text_info_list:
|
|||
|
|
print("未识别到任何文字")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
# 打印识别到的所有文字,用于调试
|
|||
|
|
print(f"识别到的文字: {[info['text'] for info in text_info_list]}")
|
|||
|
|
|
|||
|
|
# 匹配坐标格式 xx / xx
|
|||
|
|
# 匹配格式:坐标:x:25.77y:68.82 或 坐标:x25.77y:68.82(冒号可能被OCR漏识别)
|
|||
|
|
coord_pattern = re.compile(r'坐标[::]?\s*[xX][::]?\s*(\d+\.?\d*)\s*[yY][::]?\s*(\d+\.?\d*)')
|
|||
|
|
|
|||
|
|
for text_info in text_info_list:
|
|||
|
|
text = text_info.get('text', '')
|
|||
|
|
match = coord_pattern.search(text)
|
|||
|
|
if match:
|
|||
|
|
x_coord = float(match.group(1))
|
|||
|
|
y_coord = float(match.group(2))
|
|||
|
|
print(f"找到坐标: ({x_coord}, {y_coord})")
|
|||
|
|
return (x_coord, y_coord)
|
|||
|
|
|
|||
|
|
print("未找到坐标格式")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"获取位置失败: {str(e)}")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
def get_position_with_retry(self, max_retries: int = 3, retry_delay: float = 0.5) -> Optional[Tuple[float, float]]:
|
|||
|
|
"""带重试机制的获取人物当前所在坐标
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
max_retries (int): 最大重试次数,默认为 3
|
|||
|
|
retry_delay (float): 每次重试的间隔时间(秒),默认为 0.5
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
Optional[Tuple[float, float]]: 坐标 (x, y),如果识别失败返回 None
|
|||
|
|
"""
|
|||
|
|
for i in range(max_retries):
|
|||
|
|
position = self.get_position()
|
|||
|
|
if position:
|
|||
|
|
return position
|
|||
|
|
|
|||
|
|
if i < max_retries - 1:
|
|||
|
|
print(f"第 {i + 1} 次尝试失败,{retry_delay} 秒后重试...")
|
|||
|
|
time.sleep(retry_delay)
|
|||
|
|
|
|||
|
|
print(f"经过 {max_retries} 次尝试,仍未获取到坐标")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
def get_heading(self) -> Optional[float]:
|
|||
|
|
"""获取人物当前朝向
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
Optional[float]: 朝向角度,如果识别失败返回 None
|
|||
|
|
"""
|
|||
|
|
try:
|
|||
|
|
region_width = self.screen_width // 3
|
|||
|
|
region_height = self.screen_height // 4
|
|||
|
|
screenshot = pyautogui.screenshot(region=(0, 0, region_width, region_height))
|
|||
|
|
os.makedirs('screenshot', exist_ok=True)
|
|||
|
|
screenshot.save('screenshot/heading_screenshot.png')
|
|||
|
|
|
|||
|
|
text_info_list = self.text_finder.recognize_text_from_image(screenshot)
|
|||
|
|
|
|||
|
|
if not text_info_list:
|
|||
|
|
print("未识别到任何文字")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
print(f"识别到的文字: {[info['text'] for info in text_info_list]}")
|
|||
|
|
|
|||
|
|
# 朝向格式可能有冒号也可能没有:朝向:123 或 朝向123
|
|||
|
|
heading_pattern = re.compile(r'朝向[::]?\s*(\d+\.?\d*)\s*')
|
|||
|
|
|
|||
|
|
for text_info in text_info_list:
|
|||
|
|
text = text_info.get('text', '')
|
|||
|
|
text = text.replace(' ', '')
|
|||
|
|
|
|||
|
|
match = heading_pattern.search(text)
|
|||
|
|
if match:
|
|||
|
|
heading = float(match.group(1))
|
|||
|
|
print(f"找到朝向: {heading}°")
|
|||
|
|
return heading
|
|||
|
|
|
|||
|
|
print("未找到朝向格式")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"获取朝向失败: {str(e)}")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
def get_heading_with_retry(self, max_retries: int = 3, retry_delay: float = 0.5) -> Optional[float]:
|
|||
|
|
"""带重试机制的获取人物当前朝向
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
max_retries (int): 最大重试次数,默认为 3
|
|||
|
|
retry_delay (float): 每次重试的间隔时间(秒),默认为 0.5
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
Optional[float]: 朝向角度,如果识别失败返回 None
|
|||
|
|
"""
|
|||
|
|
for i in range(max_retries):
|
|||
|
|
heading = self.get_heading()
|
|||
|
|
if heading is not None:
|
|||
|
|
return heading
|
|||
|
|
|
|||
|
|
if i < max_retries - 1:
|
|||
|
|
print(f"第 {i + 1} 次尝试失败,{retry_delay} 秒后重试...")
|
|||
|
|
time.sleep(retry_delay)
|
|||
|
|
|
|||
|
|
print(f"经过 {max_retries} 次尝试,仍未获取到朝向")
|
|||
|
|
return None
|