6 Star 53 Fork 20

LanRenZhiNeng/懒人原神AI

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
wayfinding.py 53.43 KB
一键复制 编辑 原始数据 按行查看 历史
老大哥 提交于 2024-09-28 12:13 . 1.89
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127
# -*- coding: utf-8 -*-
#opencv 必须 4.8.1.78
from pynput import keyboard
from pynput.keyboard import Key
from lanrenauto.tools.screenshot import *
from lanrenauto.moni.hookkeymose import HookKeyMose
from auto import *
def setresize():
pyautogui.keyUp('w')
pyautogui.keyDown("esc")
time.sleep(0.2)
pyautogui.keyUp("esc")
class YuanShenAutoMap(HookKeyMose):
def __init__(self):
HookKeyMose.__init__(self, hookKey=True)
pyautogui.PAUSE = 0.01
pyautogui.FAILSAFE=False
self.on_rec=False
self.map_matrix = []
self.now_point=(0,0)#当前的位置
self.old_point=(0,0)#上一次的位置
self.isRunRec=False
self.小地图区域=(87-10,45-10,246+10,204+10 )
# 让yolov接手的兴趣点用来存可能出现怪物,或者需要捡东西的地方
self.interest_point = []
def run_rec(self, image_path,image_path_lujin):
'''
录制路径
:param image_path_map: 地图路径 有障碍物的
:param image_path: 原图
:return:
'''
self.on_rec = True
self.isRunRec=True
self.interest_point=[]
# 获取窗口句柄
hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE) # 替换成你实际的窗口句柄
rect = win32gui.GetWindowRect(hwnd)
w_p, h_p = (rect[2] - rect[0]) - 1920, (rect[3] - rect[1]) - 1080
# 设定截图区域的左上角坐标 (x, y) 和右下角坐标 (x, y)
left, top, right, bottom =self.小地图区域 # 替换成你实际的区域坐标
roi = None
result_post=(0,0)
big_img = cv2.imdecode(np.fromfile(file=image_path, dtype=np.uint8), cv2.IMREAD_COLOR) # 加载大图
big_height, big_width, _ = big_img.shape
big_img_yt = big_img.copy()
# height, width, _ = big_img.shape
# window_height=500
# window_width = int(window_height * width / height)
# sj=str(random.randint(1000,9999))
# # 创建窗口
# cv2.namedWindow('Genshin navigation'+sj, cv2.WINDOW_NORMAL)
# cv2.resizeWindow('Genshin navigation'+sj, window_width, window_height)
# cv2.setWindowProperty("Genshin navigation"+sj, cv2.WND_PROP_TOPMOST, 1)
logger.info("载入地图成功")
while True:
if self.get_window_handle_at_mouse_position() != hwnd:
logger.info("鼠标离开游戏了!")
time.sleep(0.5)
continue
# #time.sleep(interval)
if state.开关_是否展预测结果:
#cv2.waitKey(100)
pass
if self.on_rec == False:
# 分割路径为目录和文件名
dir_path, filename = os.path.split(image_path)
# 分割文件名和后缀
name, extension = os.path.splitext(filename)
new_file=image_path_lujin
cv2.circle(big_img, result_post, 2, (0,0, 255), -1)
for point in self.interest_point:
cv2.circle(big_img, point, 2, (0, 255, 0), -1)
# 保存图像
with open(new_file, 'wb') as f:
f.write( cv2.imencode(extension, big_img)[1].tobytes())
logger.info("录制完成! 保存在了:"+new_file)
return
# big_img = big_img_bk.copy()
small_img = screenshot(hwnd, left, top, right, bottom, None)
ret = find_img_all_sift(big_img_yt, small_img,roi)
try:
for result in ret:
result_post = [result["result"][0], result["result"][1]]
sm_width,sm_height= result["rectangle"][2][0]-result["rectangle"][0][0],result["rectangle"][2][1]-result["rectangle"][0][1]
cv2.circle(big_img, result_post, 2, (255, 0, 0), -1)
roi = [result["rectangle"][0][0]-40 ,result["rectangle"][0][1]-40, sm_width+80 , sm_height+80 ]
if roi[0] < 0:
roi[0] = 0
if roi[1] < 0:
roi[1] = 0
if roi[2] > big_width:
roi[0] = big_width - roi[2]
if roi[3] > big_height:
roi[1] = big_height - roi[3]
self.now_point = result_post
# 显示匹配结果
break
except :
logger.error(traceback.format_exc())
roi=None
if state.开关_是否展预测结果:
if big_img.shape[2] == 4:
state.图片_找图 = cv2.cvtColor(big_img, cv2.COLOR_BGRA2BGR)
else:
state.图片_找图 = big_img
state.QT_信号.mysig_show_xunlu.emit()
#cv2.imshow('Genshin navigation'+sj, big_img)
if state.开关_是否展预测结果:
pass
#cv2.destroyAllWindows()
return True
def run_chuansong(self, image_path,maodian_path=""):
'''
传送
:param image_path_map: 地图路径 有障碍物的
:param image_path: 原图
:return:
'''
# 获取窗口句柄
hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE) # 替换成你实际的窗口句柄
rect = win32gui.GetWindowRect(hwnd)
w_p, h_p = (rect[2] - rect[0]) - 1920, (rect[3] - rect[1]) - 1080
# 设定截图区域的左上角坐标 (x, y) 和右下角坐标 (x, y)
left, top, right, bottom =0,0,1920,1080 # 替换成你实际的区域坐标
p_left = rect[0] + w_p+left
p_top = rect[1] + h_p+top
roi = None
moban_img = cv2.imdecode(np.fromfile(file=image_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
if maodian_path!="":
moban_maodian_img = cv2.imdecode(np.fromfile(file=maodian_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
else:
moban_maodian_img=None
chuangsong_img=cv2.imdecode(np.fromfile(file="./datas/传送按钮.png", dtype=np.uint8), cv2.IMREAD_UNCHANGED)
def ddd():
paimeng_img = cv2.imdecode(np.fromfile(file="./datas/派蒙.png", dtype=np.uint8), cv2.IMREAD_UNCHANGED)
for _ in range(20):
time.sleep(1)
big_img = screenshot(hwnd, left, top, right, bottom, None)
res = template_matching(big_img, paimeng_img, mask=None)
if state.状态_循环开关 == False:
logger.info("强制退出!")
state.状态_需重新传送 = False
return False
for result in res:
result_post = [result["result"][0], result["result"][1]]
logger.info("传送完成!")
# 将数组从行向量转换为列向量
# pts = pts.reshape((-1, 1, 2))
if state.开关_是否展预测结果:
# 转换为 NumPy 数组
pts = np.array(
(
result['rectangle'][0], result['rectangle'][1], result['rectangle'][3],
result['rectangle'][2]),
np.int32)
cv2.circle(big_img, result_post, 10, (0, 0, 255), -1)
cv2.polylines(big_img, [pts], True, (0, 255, 0), 5)
# cv2.imshow('Genshin navigation' , big_img)
if big_img.shape[2] == 4:
state.图片_找图 = cv2.cvtColor(big_img, cv2.COLOR_BGRA2BGR)
else:
state.图片_找图 = big_img
state.QT_信号.mysig_show_xunlu.emit()
state.状态_传送中 = False
state.状态_需重新传送 = False
return True
state.状态_需重新传送 = True
logger.info("需要重新传送! (注意检查一下 桌面缩放是否为100%)")
return False
big_img = screenshot(hwnd, left, top, right, bottom, None)
res = find_img_all_sift(big_img, moban_img,roi)
time.sleep(1)
hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE) # 替换成你实际的窗口句柄
set_window_activate(hwnd)
time.sleep(0.2)
if state.状态_循环开关== False:
logger.info("强制退出!")
state.状态_需重新传送 = False
return False
try:
if len(res) == 0:
logger.info(f"没定位到传送模板")
state.状态_需重新传送 = True
return False
for result in res:
logger.info("找到了传送位置")
result_post = [result["result"][0], result["result"][1]]
if state.开关_是否展预测结果:
cv2.circle(big_img, result_post, 10, (0, 0, 255), -1)
cv2.polylines(big_img, result['dst_pot'], True, (0, 255, 0), 5)
#cv2.imshow('Genshin navigation' , big_img)
#cv2.imwrite("./output.jpg", big_img)
if big_img.shape[2] == 4:
state.图片_找图 = cv2.cvtColor(big_img, cv2.COLOR_BGRA2BGR)
else:
state.图片_找图 = big_img
state.QT_信号.mysig_show_xunlu.emit()
#cv2.waitKey(100)
# 显示匹配结果
mouse_move(p_left +result_post[0], p_top + result_post[1])
time.sleep(0.1)
mouse_left_down()
time.sleep(0.1)
mouse_left_up()
time.sleep(0.5)
break
except Exception as err:
logger.info(f"没找到传送位置{err}")
state.状态_需重新传送 = True
return False
time.sleep(0.5)
if state.状态_循环开关 == False:
state.状态_需重新传送 = False
logger.info("强制退出!")
return False
big_img = screenshot(hwnd, left, top, right, bottom, None)
res=template_matching(big_img, chuangsong_img, mask=None)
ret = False
try:
for result in res:
result_post = [result["result"][0], result["result"][1]]
logger.info(f"找到了传送按钮1{result_post} {result['confidence']}")
# 转换为 NumPy 数组
pts = np.array((result['rectangle'][0], result['rectangle'][1], result['rectangle'][3], result['rectangle'][2]), np.int32)
# 将数组从行向量转换为列向量
#pts = pts.reshape((-1, 1, 2))
if state.开关_是否展预测结果:
cv2.circle(big_img, result_post, 10, (0, 0, 255), -1)
cv2.polylines(big_img, [pts], True, (0, 255, 0), 5)
# cv2.imshow('Genshin navigation' , big_img)
#cv2.imwrite("./output.jpg", big_img)
if big_img.shape[2] == 4:
state.图片_找图 = cv2.cvtColor(big_img, cv2.COLOR_BGRA2BGR)
else:
state.图片_找图 = big_img
state.QT_信号.mysig_show_xunlu.emit()
# cv2.waitKey(100)
# 显示匹配结果
mouse_move(p_left + result_post[0]+100, p_top + result_post[1])
time.sleep(0.1)
mouse_left_down()
time.sleep(0.1)
mouse_left_up()
time.sleep(0.5)
return ddd()
except Exception as err:
logger.info(f"没有找到传送按钮{err}")
state.状态_需重新传送 = True
return False
if ret != True:
time.sleep(0.5)
if state.状态_循环开关== False:
state.状态_需重新传送 = False
logger.info("强制退出!")
return False
big_img = screenshot(hwnd, left, top, right, bottom, None)
res = find_img_all_sift(big_img, moban_maodian_img, None)
ret = False
try:
if res == []:
logger.info("传送失败")
state.状态_需重新传送 = True
return False
for result in res:
result_post = [result["result"][0], result["result"][1]]
if result["result"][0]<581 and result["result"][1]<401:
ret = False
continue
if result['confidence']<0.8:
ret = False
continue
logger.info(f"找到了锚点选项 {result_post} {result['confidence']}")
if state.开关_是否展预测结果:
cv2.circle(big_img, result_post, 10, (0, 0, 255), -1)
cv2.polylines(big_img, result['dst_pot'], True, (0, 255, 0), 5)
# cv2.imshow('Genshin navigation' , big_img)
#cv2.imwrite("./output.jpg", big_img)
if big_img.shape[2] == 4:
state.图片_找图 = cv2.cvtColor(big_img, cv2.COLOR_BGRA2BGR)
else:
state.图片_找图 = big_img
state.QT_信号.mysig_show_xunlu.emit()
# cv2.waitKey(100)
# 显示匹配结果
mouse_move(p_left + result_post[0], p_top + result_post[1])
time.sleep(0.1)
mouse_left_down()
time.sleep(0.1)
mouse_left_up()
time.sleep(0.5)
ret = True
break
except Exception as err:
logger.info(f"没找到锚点选项{err}" )
state.状态_需重新传送 = True
pyautogui.keyDown("esc")
time.sleep(0.2)
pyautogui.keyUp("esc")
time.sleep(1)
pyautogui.keyDown("esc")
time.sleep(0.2)
pyautogui.keyUp("esc")
return False
if ret == True:
big_img = screenshot(hwnd, left, top, right, bottom, None)
res = template_matching(big_img, chuangsong_img, mask=None)
if state.状态_循环开关 == False:
logger.info("强制退出!")
state.状态_需重新传送 = False
return False
try:
if res==[]:
logger.info("传送失败")
state.状态_需重新传送 = True
pyautogui.keyDown("esc")
time.sleep(0.2)
pyautogui.keyUp("esc")
time.sleep(1)
pyautogui.keyDown("esc")
time.sleep(0.2)
pyautogui.keyUp("esc")
return False
for result in res:
result_post = [result["result"][0], result["result"][1]]
logger.info(f"找到了传送按钮2{result_post} {result['confidence']}" )
# 转换为 NumPy 数组
pts = np.array((result['rectangle'][0], result['rectangle'][1], result['rectangle'][3],
result['rectangle'][2]), np.int32)
# 将数组从行向量转换为列向量
# pts = pts.reshape((-1, 1, 2))
if state.开关_是否展预测结果:
cv2.circle(big_img, result_post, 10, (0, 0, 255), -1)
cv2.polylines(big_img, [pts], True, (0, 255, 0), 5)
# cv2.imshow('Genshin navigation' , big_img)
#cv2.imwrite("./output.jpg", big_img)
if big_img.shape[2] == 4:
state.图片_找图 = cv2.cvtColor(big_img, cv2.COLOR_BGRA2BGR)
else:
state.图片_找图 = big_img
state.QT_信号.mysig_show_xunlu.emit()
# cv2.waitKey(100)
# 显示匹配结果
mouse_move(p_left + result_post[0]+100, p_top + result_post[1])
time.sleep(0.1)
mouse_left_down()
time.sleep(0.1)
mouse_left_up()
time.sleep(0.5)
return ddd()
except Exception as err:
logger.info(f"传送失败{err}" )
state.状态_需重新传送 = True
pyautogui.keyDown("esc")
time.sleep(0.2)
pyautogui.keyUp("esc")
time.sleep(1)
pyautogui.keyDown("esc")
time.sleep(0.2)
pyautogui.keyUp("esc")
return False
else:
logger.info("传送失败")
state.状态_需重新传送 = True
pyautogui.keyDown("esc")
time.sleep(0.2)
pyautogui.keyUp("esc")
time.sleep(1)
pyautogui.keyDown("esc")
time.sleep(0.2)
pyautogui.keyUp("esc")
return False
#cv2.destroyAllWindows()
return True
def run_playback(self, image_path_map, image_path,wakuang=False,caiji=False,quickening_keys=None):
'''
执行寻路 直到移动到目标为止
:param image_path_map: 地图路径 有障碍物的
:param image_path: 原图
:param isShow: 是否显示地图
:param quickening_keys: 用来随机赶路的按钮 比如
[{"probability":0.1,"keys":[ {"key":"1","time":0.2 }, {"key":"e","time":0.5}]}]
代表概率10%(100毫秒一次判断) 按1 0.2秒 然后 按E 1秒 支持无数组合
:return:
'''
self.isRunRec = False
state.状态_循环开关= True
state.状态_已经有寻路了=True
self.load_map(image_path_map)
self.map_matrix_copy = self.map_matrix.copy()
def setangle(angle_now, angle_target, fault=6):
nonlocal best_angle,quickening_keys
ret=True
angle_diff = abs(angle_now - angle_target)
if angle_diff <= fault:
ret= False
if state.状态_循环开关== False:
logger.info("强制退出1!")
pyautogui.keyUp('w')
ret= False
if ret==False:
return False
angle_diff = int((angle_target - angle_now) % 360)
if angle_diff > 180:
fangxiang = -1
angle_diff = 360 - angle_diff
else:
fangxiang = 1
if abs(angle_diff < fault):
return True
#print(f"调整视角 相差:{fangxiang * angle_diff}° 当前:{angle_now}° 目标:{angle_target}° ")
mouse_moveR(int(fangxiang * 5 * angle_diff), 0)
time.sleep(0.05)
return True
state.计次_定位失败=0
# 获取窗口句柄
hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE) # 替换成你实际的窗口句柄
rect = win32gui.GetWindowRect(hwnd)
w_p, h_p = (rect[2] - rect[0]) - 1920, (rect[3] - rect[1]) - 1080
p_left = rect[0] + w_p
p_top = rect[1] + h_p
while True:
time.sleep(1)
if self.get_window_handle_at_mouse_position() == hwnd:
break
if state.状态_循环开关== False:
logger.info("强制退出!")
pyautogui.keyUp('w')
state.状态_已经有寻路了 = False
state.状态_需重新传送 = False
return False
# 设定保存截图的文件夹路径和文件名前缀
#folder_path = "./datas/img/"
# 设定定时器间隔(秒)
roi=None
big_img_bk = cv2.imdecode(np.fromfile(file=image_path, dtype=np.uint8),cv2.IMREAD_UNCHANGED) # 加载大图
big_height, big_width, big_td = big_img_bk.shape
if big_td==3:
# # 将24位彩色图片转换为32位彩色图片
big_img_bk = cv2.cvtColor(big_img_bk, cv2.COLOR_BGR2BGRA)#BGRA COLOR_BGR2BGRA
template = cv2.imdecode(np.fromfile(file=r"./datas/小图.png", dtype=np.uint8), cv2.IMREAD_UNCHANGED) # 加载透明图
mask = template[:, :, 3] # 提取透明度通道作为掩码
paimeng_img = cv2.imdecode(np.fromfile(file="./datas/派蒙.png", dtype=np.uint8),
cv2.IMREAD_UNCHANGED)
img = cv2.imdecode(np.fromfile(file="./datas/注意敌人.png", dtype=np.uint8),
cv2.IMREAD_UNCHANGED)
result_old = {"result": [0, 0]}
state.计数_卡主次数=0
state.状态_在爬墙=False
interest_coordinate2=None
interest_coordinate=None
state.游戏_打怪前坐标 = [0, 0]
state.游戏_当前目标坐标 = [0, 0]
state.计次_误差过大=0
self.old_point= [0, 0]
state.计次_识别次数=0
state.计次_移动停滞 =0
while True:
#old_time = time.time()
try:
time.sleep(0.01)
if state.状态_循环开关 == False:
logger.info("强制退出!")
pyautogui.keyUp('w')
state.状态_已经有寻路了 = False
state.状态_需重新传送 = False
return False
# 设定截图区域的左上角坐标 (x, y) 和右下角坐标 (x, y)
left, top, right, bottom = self.小地图区域 # 替换成你实际的区域坐标
if state.状态_全局暂停:
time.sleep(1)
continue
if not state.状态_YOLOV :
time.sleep(1)
continue
if state.计次_误差过大 == 20:
self.old_point = copy.copy(state.游戏_当前目标坐标)
if state.计次_误差过大>= 30:
logger.info("误差过大了30次,重新运行这个任务")
pyautogui.keyUp('w')
state.状态_已经有寻路了 = False
state.状态_需重新传送 = True
return False
if state.计次_移动停滞>=20:
logger.info("移动停滞了20次,重新运行这个任务")
pyautogui.keyUp('w')
state.状态_已经有寻路了 = False
state.状态_需重新传送 = True
return False
if state.计次_定位失败>=30:
logger.info("定位失败次数超过30次,重新运行这个任务")
pyautogui.keyUp('w')
state.状态_已经有寻路了 = False
state.状态_需重新传送 = True
return False
self.quickening(quickening_keys)
big_img = big_img_bk.copy()
#filename = f"{folder_path}{int(time.time())}.png"
height = bottom - top
width = right - left
small_img = screenshot(hwnd, left, top, right, bottom, filename=None)#RGBA
if type(small_img)==bool:
hwnd = win32gui.FindWindow("UnityWndClass", state.GAME_TITLE) # 替换成你实际的窗口句柄
time.sleep(1)
continue
# 识别位置和方向
_, max_similarity, best_angle, best_rotated_template = pyramid_template_matching(
small_img[int(height / 2) - 30:int(height / 2) + 30, int(width / 2) - 30:int(width / 2) + 30],
template,
mask=mask)
best_angle = int(best_angle)
#cv2.imwrite(filename,small_img)
#cv2.imwrite(f"{folder_path}{int(time.time())}_111.png",small_img[int(height / 2) - 30:int(height / 2) + 30, int(width / 2) - 30:int(width / 2) + 30])
# 识别位置和方向
state.游戏_当前视野角度= get_view(small_img[int(height / 2) - 70:int(height / 2) + 70, int(width / 2) - 70:int(width / 2) + 70],70)
if state.游戏_当前视野角度==-1:
state.游戏_当前视野角度=best_angle
state.游戏_当前导航角度=best_angle
#print(state.游戏_当前视野角度,state.游戏_当前导航角度)
# 裁剪图像,去除Alpha通道
# small_img=small_img[:, :, :3]
ret = find_img_all_sift(big_img, small_img,roi)
if ret==None or ret == []:
logger.info(f"定位失败{state.计次_定位失败}" )
state.计数_卡主次数 += 1
state.计次_定位失败 += 1
if state.计次_定位失败>=15:
pyautogui.keyDown('shift')
time.sleep(0.3)
pyautogui.keyUp('shift')
# 如果定位失败,判断派蒙是否存在
#如果派蒙不在 并且不是在连招过程中,则说明现在 在不明界面中,尝试按ESC键和点击指定位置跳过对话
res__ = template_matching(screenshot(hwnd, 0, 0, 1920, 1080, filename=None), paimeng_img, mask=None)
if res__==[] and state.状态_是否回放中==False:
logger.info("发现不明界面,尝试按ESC键和点击指定位置跳过对话")
rect = win32gui.GetWindowRect(hwnd)
w_p, h_p = (rect[2] - rect[0]) - 1920, (rect[3] - rect[1]) - 1080
# 设定截图区域的左上角坐标 (x, y) 和右下角坐标 (x, y)
p_left = rect[0] + w_p
p_top = rect[1] + h_p
mouse_move(p_left+1400,p_top+584)
time.sleep(0.2)
mouse_left_down()
time.sleep(0.2)
mouse_left_up()
time.sleep(0.2)
mouse_move(p_left + 1412, p_top + 652)
time.sleep(0.2)
mouse_left_down()
time.sleep(0.2)
mouse_left_up()
time.sleep(0.2)
mouse_move(p_left + 1419, p_top + 729)
time.sleep(0.2)
mouse_left_down()
time.sleep(0.2)
mouse_left_up()
time.sleep(0.2)
mouse_move(p_left + 1380, p_top + 801)
time.sleep(0.2)
mouse_left_down()
time.sleep(0.2)
mouse_left_up()
if random.randint(0,2)==1:
time.sleep(0.2)
pyautogui.keyDown("esc")
time.sleep(0.2)
pyautogui.keyUp("esc")
if state.状态_寻路中:
if roi==None:
if result_old!={"result": [0, 0]}:
ret = [result_old]
else:
roi = None
continue
else:
roi = None
continue
roi=None
for result in ret:
if result["result"] !=result_old["result"] :
state.计次_定位失败 = 0
sm_width,sm_height= result["rectangle"][2][0]-result["rectangle"][0][0],result["rectangle"][2][1]-result["rectangle"][0][1]
state.游戏_当前坐标 = [result["result"][0], result["result"][1]]
roi = [result["rectangle"][0][0]-40 ,result["rectangle"][0][1]-40, sm_width+80 , sm_height+80 ]
if roi[0]<0:
roi[0]=0
if roi[1]<0:
roi[1]=0
if roi[2]>big_width:
roi[0]=big_width-roi[2]
if roi[3] > big_height:
roi[1] = big_height - roi[3]
self.update_map_show(big_img)
if state.状态_寻路中:
if state.游戏_当前坐标[0] < 0 or state.游戏_当前坐标[1] < 0:
roi = None
break
if abs(state.游戏_当前坐标[0] - self.end[0]) <= 120 and abs(
state.游戏_当前坐标[1] - self.end[1]) <= 120 and quickening_keys != None:
# 快到终点了,ban掉这些赶路的,防止走错地方
quickening_keys = None
if abs(state.游戏_当前坐标[0] - self.end[0]) <= 4 and abs(state.游戏_当前坐标[1] - self.end[1]) <= 4:
logger.info("已经到达目的地")
pyautogui.keyUp('w')
state.状态_已经有寻路了 = False
state.状态_需重新传送 = False
return True
state.计次_识别次数+=1
if state.计次_识别次数>=8:
if state.状态_是否回放中==False and state.状态_寻路中:
if abs(state.游戏_当前坐标[0] - result_old["result"][0]) <=3 and abs(
state.游戏_当前坐标[1] - result_old["result"][1]) <= 3 :
state.计次_移动停滞 += 1
state.计数_卡主次数+=1
if state.计数_卡主次数 >= 10:
if abs(state.游戏_当前坐标[0] - self.end[0]) <= 20 and abs(
state.游戏_当前坐标[1] - self.end[1]) <= 20:
logger.info("非常接近目的地了!但是遇到意外,因此跳过这个任务!")
pyautogui.keyUp('w')
state.状态_已经有寻路了 = False
state.状态_需重新传送 = False
return True
if random.randint(0, 1):
pyautogui.keyDown('a')
aaa = -90
else:
pyautogui.keyDown('d')
aaa = 90
pyautogui.keyUp('w')
mouse_moveR(6 * aaa, 0)
state.计数_卡主次数 = 0
logger.info("卡主太多次,尝试按X")
pyautogui.keyDown('x')
time.sleep(0.2)
pyautogui.keyUp('x')
time.sleep(1)
pyautogui.keyUp('d')
pyautogui.keyUp('a')
pyautogui.keyDown('w')
pyautogui.keyDown('x')
time.sleep(0.2)
pyautogui.keyUp('x')
time.sleep(5)
pyautogui.keyUp('w')
else:
# 判断是否死亡
if find_img_and_click(img, hwnd, 0, 0, 1920, 1080, p_left, p_top,
"点击 注意敌人", 2,
step=0.01,
threshold=0.85, is_click=True):
state.状态_检测中 = False
state.状态_是否回放中 = False
state.计数_没找到任何目标 = 0
tangbaowss.send_msg("是否回放#@@#假")
pyautogui.keyUp('w')
state.状态_已经有寻路了 = False
state.状态_需重新传送 = True
logger.info("全局覆没" )
return False
logger.info("尝试脱困"+str(state.计数_卡主次数))
pyautogui.keyDown('w')
pyautogui.keyDown('space')
time.sleep(0.2)
pyautogui.keyUp('space')
rrrr = random.randint(1, 20)
if rrrr == 3:
pyautogui.keyDown('a')
time.sleep(1)
pyautogui.keyUp('a')
elif rrrr == 1:
pyautogui.keyDown('d')
time.sleep(1)
pyautogui.keyUp('d')
elif rrrr == 2:
pyautogui.keyUp('w')
pyautogui.keyDown('d')
pyautogui.keyDown('s')
time.sleep(1)
pyautogui.keyUp('s')
pyautogui.keyUp('d')
time.sleep(2)
pyautogui.keyDown('w')
elif rrrr == 4:
pyautogui.keyUp('w')
pyautogui.keyDown('a')
pyautogui.keyDown('s')
time.sleep(1)
pyautogui.keyUp('s')
pyautogui.keyUp('a')
time.sleep(2)
pyautogui.keyDown('w')
time.sleep(0.2)
pyautogui.keyUp('w')
else:
state.计次_移动停滞 -=1
if state.计次_移动停滞 <= 0:
state.计次_移动停滞=0
state.计数_卡主次数=0
if state.计次_识别次数 >= 8:
result_old = result.copy()
state.计次_识别次数=0
if state.开关_是否展预测结果:
#cv2.polylines(big_img, result['dst_pot'], True, (0, 255, 0), 5)
# 获取小图的宽度和高度
small_height, small_width, small_channels = best_rotated_template.shape
best_rotated_template = cv2.resize(best_rotated_template,
(int(small_width * 2), int(small_height * 2)))
small_height, small_width, small_channels = best_rotated_template.shape
# 计算放置小图像的左上角坐标,使其居中在result位置
x = state.游戏_当前坐标[0] - int(small_width / 2)
y = state.游戏_当前坐标[1] - int(small_height / 2)
# 将小图叠加到大图上
for c in range(small_channels):
big_img[y:y + small_height, x:x + small_width, c] = \
best_rotated_template[:, :, c] * (best_rotated_template[:, :, 3] / 255.0) + \
big_img[y:y + small_height, x:x + small_width, c] * (
1.0 - best_rotated_template[:, :, 3] / 255.0)
self.draw_arrow( big_img, state.游戏_当前坐标[0] , state.游戏_当前坐标[1], length=200, angle=state.游戏_当前视野角度)
if state.状态_寻路中:
#如果刚刚打完怪.需要回到原位
if state.游戏_打怪前坐标!=[0,0]:
state.游戏_当前目标坐标= copy.copy(state.游戏_打怪前坐标)
try:
if abs(state.游戏_当前坐标[0] - state.游戏_打怪前坐标[0]) <= 55 and abs(state.游戏_当前坐标[1] - state.游戏_打怪前坐标[1]) <= 55:
state.游戏_打怪前坐标 = [0, 0]
logger.info("回到之前的位置了")
continue
except:
state.游戏_打怪前坐标 = [0, 0]
logger.info("回到之前的位置了")
continue
else:
state.游戏_当前目标坐标,interest_coordinate = self.find_nearest_coordinate(self.map_matrix_copy, state.游戏_当前坐标,50,distance_min=8)
if state.游戏_当前目标坐标 == None:
state.游戏_当前目标坐标,interest_coordinate = self.find_nearest_coordinate(self.map_matrix_copy,state.游戏_当前坐标, None, distance_min=8)
if state.游戏_当前目标坐标 == None:
state.游戏_当前目标坐标 = copy.copy(self.old_point)
if self.old_point!=[0,0] and state.游戏_当前目标坐标!=[0,0]:
if abs(state.游戏_当前坐标[0]-self.old_point[0])>=70 or abs(state.游戏_当前坐标[1]-self.old_point[1])>=70:
state.游戏_当前坐标=copy.copy(self.old_point )
logger.info("定位误差过大!!")
state.计次_误差过大+=1
else:
state.计次_误差过大=0
if state.计次_误差过大==0:
self.old_point = copy.copy(state.游戏_当前坐标)
if interest_coordinate!=None:
interest_coordinate2=copy.copy(interest_coordinate)
if interest_coordinate2!=None:
if abs(state.游戏_当前坐标[0] - interest_coordinate2[0]) <= 5 and abs(state.游戏_当前坐标[1] - interest_coordinate2[1]) <= 5:
logger.info("附近有兴趣点!")
state.计时_未寻路 = int(time.time())
state.状态_寻路中 = False
state.游戏_打怪前坐标 = copy.copy(state.游戏_当前目标坐标)
state.计数_没找到任何目标 = 0
state.计数_没找到怪物 = 0
pyautogui.keyUp('w')
state.计数_卡主次数 = 0
state.计次_识别次数 = 0
mouse_left_down()
mouse_left_up()
if wakuang or caiji:
logger.info("在连招中....")
pyautogui.keyDown('x')
time.sleep(0.2)
pyautogui.keyUp('x')
state.状态_是否回放中 = True
tangbaowss.send_msg(" 脚本执行#@@#2")
time.sleep(1)
self.remove_coordinates_in_range_map(self.map_matrix_copy, interest_coordinate2, 5,state.游戏_当前目标坐标)
if self.map_matrix_copy[interest_coordinate2[0]][interest_coordinate2[1]]==-1:
interest_coordinate=None
interest_coordinate2=None
self.map_matrix_copy = self.remove_coordinates_in_range_map(self.map_matrix_copy,state.游戏_当前坐标,8, state.游戏_当前目标坐标)
if state.游戏_当前目标坐标 == None:
for _ in range(30):
if not state.状态_寻路中:
break
small_img = screenshot(hwnd, left, top, right, bottom, filename=None) # RGBA
# 识别位置和方向
state.游戏_当前视野角度 = get_view(small_img[int(height / 2) - 70:int(height / 2) + 70,
int(width / 2) - 70:int(width / 2) + 70], 70)
rrr=setangle(state.游戏_当前视野角度, self.get_next_angle(state.游戏_当前坐标, self.end))
if rrr==False:
break
else:
for _ in range(30):
if not state.状态_寻路中:
break
small_img = screenshot(hwnd, left, top, right, bottom, filename=None) # RGBA
# 识别位置和方向
state.游戏_当前视野角度 = get_view(small_img[int(height / 2) - 70:int(height / 2) + 70,
int(width / 2) - 70:int(width / 2) + 70], 70)
rrr=setangle(state.游戏_当前视野角度, self.get_next_angle(state.游戏_当前坐标, state.游戏_当前目标坐标))
if rrr==False:
break
pyautogui.keyDown('w')
if state.开关_是否展预测结果:
cv2.circle(big_img, state.游戏_当前目标坐标, 10, (255, 24, 255), -1)
if big_img.shape[2] == 4:
state.图片_找图 = cv2.cvtColor(big_img, cv2.COLOR_BGRA2BGR)
else:
state.图片_找图 = big_img
state.QT_信号.mysig_show_xunlu.emit()
# # 显示匹配结果
# cv2.imshow('Genshin navigation', big_img)
#print(f"识别时间:{time.time() - old_time}")
break
except :
time.sleep(0.3)
state.计数_卡主次数 += 1
state.计次_定位失败 += 1
if state.计次_定位失败 >= 15:
pyautogui.keyDown('shift')
time.sleep(0.3)
pyautogui.keyUp('shift')
roi = None
traceback.print_exc()
def update_map_show(self,big_img):
for rdex, rowitem in enumerate(self.map_matrix_copy):
for cdex, column in enumerate(rowitem):
# 只判断符合范围内的 并且是 >1则是路线范围的坐标
if column > 0:
point=(rdex,cdex)
if column==1:
cv2.circle(big_img, point, 2, (255, 0, 0), -1)
elif column==2:
cv2.circle(big_img, point, 4, (0, 255, 0), -1)
elif column==3:
cv2.circle(big_img, point, 4, (0, 0, 255), -1)
def quickening(self,quickening_keys=None):
'''
:param quickening_keys: 用来随机赶路的按钮 比如 [{"probability":0.1,"keys":[ {"key":"1","time":0.2 }, {"key":"e","time":0.5}]}] 代表概率10% 按1 0.2秒 然后 按E 1秒 支持无数组合
:return:
'''
if quickening_keys==None:
return False
for quickening_key in quickening_keys:
if random.randint(1,100)<quickening_key["probability"]*100:
for key in quickening_key["keys"]:
if state.状态_循环开关== False:
logger.info("强制退出!")
pyautogui.keyUp('w')
return False
logger.info(f"触发赶路按键:{key['key']}")
pyautogui.keyDown(key["key"])
time.sleep(key["time"])
pyautogui.keyUp(key["key"])
time.sleep(0.1)
return True
def get_next_angle(self, start_pos, next_pos):
# 计算方向向量
direction_x = next_pos[0] - start_pos[0]
direction_y = next_pos[1] - start_pos[1]
# 使用反正切函数计算弧度角度值
angle_rad = math.atan2(direction_y, direction_x)
# 将弧度角度值转换为以北方向为0度的角度
angle_deg = math.degrees(angle_rad)
# 将角度值转换为顺时针方向
angle_deg = int((angle_deg + 360 + 90) % 360)
return angle_deg
def find_nearest_coordinate(self,coordinates, my_position,range_limit=100,distance_min=0):
'''
寻找当前位置最近的坐标点 顺便返回最近的兴趣点
:param coordinates:
:param my_position:
:param range_limit: # 搜索范围半径为50 提高效率
:return:
'''
min_distance_coordinate = float('inf')
nearest_coordinate =None
interest_coordinate=None
for rdex,rowitem in enumerate(coordinates) :
for cdex,column in enumerate(rowitem):
#只判断符合范围内的 并且是 >1则是路线范围的坐标
if column>0:
#x 附近 range_limit 范围的点 y 附近 range_limit 范围的点
if range_limit!=None:
if abs(my_position[0]-rdex)<=range_limit and abs(my_position[1]-cdex)<=range_limit :
#计算两个坐标点之间的距离 但是不要判断和自己一样的坐标.那没意义
if (my_position[0],my_position[1])!=(rdex,cdex):
distance = math.sqrt((my_position[0] - rdex) ** 2 + (my_position[1] - cdex) ** 2)
if distance>=distance_min:#要比最近小距离大.这样走位才不会老歪歪扭扭
if distance < min_distance_coordinate:
min_distance_coordinate = distance
if column==2:
interest_coordinate=[rdex,cdex]
nearest_coordinate = [rdex,cdex]
else:
# 计算两个坐标点之间的距离 但是不要判断和自己一样的坐标.那没意义
if (my_position[0], my_position[1]) != (rdex, cdex):
distance = math.sqrt((my_position[0] - rdex) ** 2 + (my_position[1] - cdex) ** 2)
if distance >= distance_min: # 要比最近小距离大.这样走位才不会老歪歪扭扭
if distance < min_distance_coordinate:
min_distance_coordinate = distance
if column == 2:
interest_coordinate = [rdex, cdex]
nearest_coordinate = [rdex, cdex]
return nearest_coordinate,interest_coordinate
def on_release(self, key: keyboard.KeyCode):
"""定义释放时候的响应"""
if key == Key.f9:#停止
state.状态_循环开关= False
state.状态_全局暂停=True
state.状态_已经有寻路了 = False
state.状态_是否禁止录制=True
self.on_rec = False
elif key == Key.f8:
self.on_rec = False
if state.状态_是否禁止录制:
if state.状态_循环开关== False:
return
state.状态_全局暂停=not state.状态_全局暂停
logger.info(f"state.状态_全局暂停{state.状态_全局暂停}")
if state.状态_全局暂停:
time.sleep(0.3)
pyautogui.keyUp('w')
elif key ==Key.f10:
if self.isRunRec:
self.interest_point.append(self.now_point)
logger.info(f"标记坐标{self.now_point}")
def load_map(self, image_path):
'''
加载地图 这个地图要障碍物地图
:param image_path:
:return:
'''
logger.info("加载地图中...")
# 读取图片
self.image = Image.open(image_path)
# 获取图片尺寸
self.width, self.height = self.image.size
# 定义地图
self.map_matrix = []
# 根据像素颜色生成地图数据
for x in range(self.width):
row=[]
for y in range(self.height):
pixel = self.image.getpixel((x, y))
if pixel[2] >= 240 and pixel[0] < 20 and pixel[1] < 20: # 蓝色
row.append(1)
elif pixel[0] >= 240 and pixel[1] < 20 and pixel[2] < 20: # 红色
self.end = (x, y)
row.append(3)
elif pixel[1] >= 240 and pixel[0] < 20 and pixel[2] < 20: # 绿色
row.append(2)
else:
row.append(0)
self.map_matrix.append(row)
logger.info("地图加载完毕!")
def get_window_handle_at_mouse_position(self, ):
active_hwnd = ctypes.windll.user32.GetForegroundWindow()
return active_hwnd
def remove_coordinates_in_range_map(self, coordinates, center, range_limit,nex_pos):
new_coordinates=coordinates.copy()
for rdex, rowitem in enumerate(new_coordinates):
for cdex, column in enumerate(rowitem):
# 只判断符合范围内的 并且是 >1则是路线范围的坐标
if column > 0:
if (rdex,cdex) == self.end: # 终点不能删除
continue
#将附近的点标记为走过了
elif abs(center[0]-rdex)<=range_limit and abs(center[1]-cdex)<=range_limit:
new_coordinates[rdex][cdex]=-1# 将该点标记为已经走过的,标记为-1
elif abs(center[0] - rdex) <= range_limit*2 and abs(center[1] - cdex) <= range_limit*2:
angle_target = self.get_next_angle(center, nex_pos) # 当前位置对准兴趣点的角度
angle_coordinate = self.get_next_angle(center, (rdex,cdex)) # 当前成员位置对准结束点的角度
angle_diff = abs(angle_target - angle_coordinate)
if angle_diff > 160 and angle_diff<=220 :
new_coordinates[rdex][cdex]=-1# 将该点标记为已经走过的,标记为-1
return new_coordinates
def draw_arrow(self,img, x, y, length=50, angle=45):
# 箭头的长度和角度(以北方向为0度,顺时针为正方向)
# 将角度转换为以北方向为0度的角度
degrees = (450 - angle) % 360
# 计算箭头末端的坐标
end_x = int(x + length * np.cos(np.radians(degrees)))
end_y = int(y - length * np.sin(np.radians(degrees)))
# 在图像上画线段
cv2.line(img, (x, y), (end_x, end_y), (0, 0,255), 5)
# 画箭头头部
theta = np.radians(degrees)
arrow_length = 10
arrow_angle = np.radians(30)
# 箭头头部的两个端点
arrow_pt1 = (end_x - int(arrow_length * np.cos(theta + arrow_angle)),
end_y + int(arrow_length * np.sin(theta + arrow_angle)))
arrow_pt2 = (end_x - int(arrow_length * np.cos(theta - arrow_angle)),
end_y + int(arrow_length * np.sin(theta - arrow_angle)))
# 画箭头头部
cv2.line(img, (end_x, end_y), arrow_pt1, (0, 0,255), 5)
cv2.line(img, (end_x, end_y), arrow_pt2, (0, 0,255), 5)
return img
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Python
1
https://gitee.com/LanRenZhiNeng/lanren-genshin-impact-ai.git
git@gitee.com:LanRenZhiNeng/lanren-genshin-impact-ai.git
LanRenZhiNeng
lanren-genshin-impact-ai
懒人原神AI
master

搜索帮助

23e8dbc6 1850385 7e0993f3 1850385