import cv2 from utils.get_image import GetImage from utils.mouse import init_mouse_keyboard, Mouse_guiji from ultralytics import YOLO import time import serial import ch9329Comm import random import math from utils import shizi from config import config_manager # 加载YOLO模型 model = YOLO(r"best.pt").to('cuda') model0 = YOLO(r"best0.pt").to('cuda') # 从配置加载 active_group = config_manager.get_active_group() if active_group is None: print("❌ 没有活动的配置组,请在gui_config.py中设置") exit(1) print(f"📋 使用配置组: {active_group['name']}") # 初始化串口和鼠标 init_mouse_keyboard(active_group) # 初始化键盘和鼠标 keyboard = ch9329Comm.keyboard.DataComm() from utils.mouse import mouse, mouse_gui # 导入已初始化的mouse和mouse_gui # 创建全局的mouse_gui实例 mouse_gui = Mouse_guiji() # 初始化采集卡 get_image = GetImage( cam_index=active_group['camera_index'], width=active_group['camera_width'], height=active_group['camera_height'] ) # 检查采集卡是否初始化成功 if get_image.cap is None: print(f"❌ 采集卡 {active_group['camera_index']} 初始化失败") print("请检查:") print("1. 采集卡是否正确连接") print("2. 采集卡索引是否正确") print("3. 采集卡驱动是否安装") exit(1) print(f"✅ 初始化完成 - 串口:{active_group['serial_port']} 采集卡:{active_group['camera_index']}") # 全局变量 left = 0 top = 30 k = 0 # 控制转圈的方向 panduan = False # 是否在图内 boss_pd = False # 是否到boss关卡 rw = (632, 378) # 从配置读取移动速度 v = active_group['move_velocity'] def yolo_shibie(im_PIL, detections, model): detections = { 'center': None, 'next': None, 'npc1': None, 'npc2': None, 'npc3': None, 'npc4': None, 'boss': None, 'daojv': [], 'gw': [], 'zhaozi': None } results = model(im_PIL) # 目标检测 for result in results: for i in range(len(result.boxes.xyxy)): left, top, right, bottom = result.boxes.xyxy[i] scalar_tensor = result.boxes.cls[i] value = scalar_tensor.item() label = result.names[int(value)] if label == 'center' or label == 'next' or label == 'boss' or label == 'zhaozi': player_x = int(left + (right - left) / 2) player_y = int(top + (bottom - top) / 2) + 30 RW = [player_x, player_y] detections[label] = RW elif label == 'daojv' or label == 'gw': player_x = int(left + (right - left) / 2) player_y = int(top + (bottom - top) / 2) + 30 RW = [player_x, player_y] detections[label].append(RW) elif label == 'npc1' or label == 'npc2' or label == 'npc3' or label == 'npc4': player_x = int(left + (right - left) / 2) player_y = int(bottom) + 30 RW = [player_x, player_y] detections[label] = RW return detections def sq(p1, p2): """计算两点之间的欧式距离""" return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2) def process_points(points): if not points: return None # 空列表情况 n = len(points) if n == 1: # 只有一个点,直接返回 return points[0] elif n == 2: # 两个点取中点 x = (points[0][0] + points[1][0]) / 2 y = (points[0][1] + points[1][1]) / 2 return [x, y] else: # 随机选3个点 sample_points = random.sample(points, 3) # 对每个点计算到这3个点的总距离 min_sum = float('inf') best_point = None for p in points: dist_sum = sum(sq(p, sp) for sp in sample_points) if dist_sum < min_sum: min_sum = dist_sum best_point = p return best_point def move_randomly(rw, k): k = k % 4 suiji_t = float(random.randint(10, 13) / 10) if k == 0: keyboard.send_data("66") time.sleep(suiji_t) keyboard.release() # Release elif k == 1: keyboard.send_data("88") time.sleep(suiji_t) keyboard.release() # Release elif k == 2: keyboard.send_data("44") time.sleep(suiji_t) keyboard.release() # Release elif k == 3: keyboard.send_data("22") time.sleep(suiji_t) keyboard.release() # Release return k + 1 def move_to(rw, mb): """使用配置的v值""" global v v = active_group['move_velocity'] # 每次都从配置读取最新值 if rw[0] >= mb[0]: keyboard.send_data("44") time.sleep(float(abs(rw[0] - mb[0]) / v)) keyboard.release() # Release else: keyboard.send_data("66") time.sleep(float(abs(rw[0] - mb[0]) / v)) keyboard.release() # Release if rw[1] >= mb[1]: keyboard.send_data("88") time.sleep(float(abs(rw[1] - mb[1]) / v)) keyboard.release() # Release else: keyboard.send_data("22") time.sleep(float(abs(rw[1] - mb[1]) / v)) keyboard.release() i = 0 print("🚀 开始自动化...") while True: detections = { 'center': None, 'next': None, 'npc1': None, 'npc2': None, 'npc3': None, 'npc4': None, 'boss': None, 'daojv': [], 'gw': [], 'zhaozi': None } im_opencv = get_image.get_frame() # [RGB,PIL] if im_opencv is None: print("⚠️ 无法获取图像帧,跳过本次循环") time.sleep(0.1) continue detections = yolo_shibie(im_opencv[1], detections, model) if shizi.tuwai(im_opencv[0]) or yolo_shibie(im_opencv[1], model0)['npc1'] is not None or yolo_shibie(im_opencv[1], model0)['npc2'] is not None or yolo_shibie(im_opencv[1], model0)['npc3'] is not None or yolo_shibie(im_opencv[1], model0)['npc4'] is not None: # 进图算法 # 进图算法 im_opencv = get_image.get_frame() # [RGB,PIL] if im_opencv is None: print("⚠️ 无法获取图像帧,跳过本次循环") time.sleep(0.1) continue detections = yolo_shibie(im_opencv[1], detections, model0) print('当前在城镇中') if detections['npc1'] is not None and sq(rw, detections['npc1']) > 80: print("向npc1靠近") print(sq(rw, detections['npc1'])) move_to(rw, detections['npc1']) continue elif detections['npc1'] is not None and sq(rw, detections['npc1']) <= 80: print("在npc旁边,向上走") print(sq(rw, detections['npc1'])) mb = (detections['npc1'][0], detections['npc1'][1] - 1010) move_to(rw, mb) continue elif detections['npc3'] is not None and detections['npc4'] is None: print("在npc3旁边,向右走") mb = (rw[0], detections['npc3'][1] - 50) move_to(rw, mb) mb = (rw[0] + 700, rw[1]) move_to(rw, mb) continue elif detections['npc4'] is not None: npc4_pos = detections['npc4'] current_distance = sq(npc4_pos, rw) # 如果已经非常接近,直接进入 if current_distance < 30: print(f"离npc4很近 (距离={current_distance:.1f}),直接进入") keyboard.send_data("DD") time.sleep(0.15) keyboard.release() time.sleep(1) im_opencv = get_image.get_frame() # [RGB,PIL] if im_opencv is None: print("⚠️ 无法获取图像帧") continue if shizi.daoying(im_opencv[0]): mouse_gui.send_data_absolute(rw[0], rw[1] - 110, may=1) time.sleep(1) continue # 循环靠近npc4,直到足够接近或达到最大尝试次数 print(f"开始靠近npc4,当前距离={current_distance:.1f}") max_attempts = 15 # 最大尝试次数 attempt = 0 last_distance = current_distance stuck_count = 0 # 卡住计数器 while attempt < max_attempts: attempt += 1 # 重新获取当前位置和npc4位置 im_opencv = get_image.get_frame() if im_opencv is None: print("⚠️ 无法获取图像帧") break detections_temp = { 'center': None, 'next': None, 'npc1': None, 'npc2': None, 'npc3': None, 'npc4': None, 'boss': None, 'zhaozi': None, 'daojv': [], 'gw': [] } detections_temp = yolo_shibie(im_opencv[1], detections_temp, model0) # 如果npc4丢失,重新检测 if detections_temp['npc4'] is None: print(f"⚠️ npc4丢失,重新检测 (尝试 {attempt}/{max_attempts})") time.sleep(0.5) continue npc4_pos = detections_temp['npc4'] current_distance = sq(npc4_pos, rw) print(f" 尝试 {attempt}/{max_attempts}: 距离npc4={current_distance:.1f}") # 如果已经足够接近,退出循环 if current_distance < 35: print(f"✅ 已足够接近npc4 (距离={current_distance:.1f})") break # 检测是否卡住(距离不再减小) if abs(current_distance - last_distance) < 5: stuck_count += 1 if stuck_count >= 3: print(f"⚠️ 检测到卡住,尝试微调移动") # 尝试向npc4方向微调 dx = npc4_pos[0] - rw[0] dy = npc4_pos[1] - rw[1] # 计算方向向量,但只移动一小段距离 step_size = 50 # 小步移动 distance_to_move = min(step_size, current_distance * 0.3) if abs(dx) > abs(dy): # 主要横向移动 target_x = rw[0] + int(dx / abs(dx) * distance_to_move) if dx != 0 else rw[0] target_y = rw[1] else: # 主要纵向移动 target_x = rw[0] target_y = rw[1] + int(dy / abs(dy) * distance_to_move) if dy != 0 else rw[1] mb = (target_x, target_y) move_to(rw, mb) time.sleep(0.3) stuck_count = 0 else: # 正常移动,但使用小步长 step_size = min(80, current_distance * 0.4) # 移动距离为目标距离的40%,最多80像素 dx = npc4_pos[0] - rw[0] dy = npc4_pos[1] - rw[1] # 归一化方向向量 if abs(dx) > 0.1 or abs(dy) > 0.1: direction_mag = math.sqrt(dx*dx + dy*dy) target_x = rw[0] + int(dx / direction_mag * step_size) target_y = rw[1] + int(dy / direction_mag * step_size) mb = (target_x, target_y) move_to(rw, mb) time.sleep(0.2) # 短暂等待,让角色移动 else: # 距离在减小,正常移动 stuck_count = 0 step_size = min(100, current_distance * 0.5) # 移动距离为目标距离的50%,最多100像素 dx = npc4_pos[0] - rw[0] dy = npc4_pos[1] - rw[1] # 归一化方向向量 if abs(dx) > 0.1 or abs(dy) > 0.1: direction_mag = math.sqrt(dx*dx + dy*dy) target_x = rw[0] + int(dx / direction_mag * step_size) target_y = rw[1] + int(dy / direction_mag * step_size) mb = (target_x, target_y) move_to(rw, mb) time.sleep(0.2) # 短暂等待,让角色移动 last_distance = current_distance # 短暂延迟,让角色位置更新 time.sleep(0.3) # 移动完成后,检查是否可以进入 final_distance = sq(npc4_pos, rw) print(f"靠近完成,最终距离={final_distance:.1f}") if final_distance < 50: print("距离足够近,尝试进入") keyboard.send_data("DD") time.sleep(0.15) keyboard.release() time.sleep(1) im_opencv = get_image.get_frame() if im_opencv is None: print("⚠️ 无法获取图像帧") continue if shizi.daoying(im_opencv[0]): mouse_gui.send_data_absolute(rw[0], rw[1] - 110, may=1) time.sleep(1) else: print(f"⚠️ 未能足够接近npc4 (距离={final_distance:.1f}),尝试点击进入") move_to(rw, npc4_pos) time.sleep(1) im_opencv = get_image.get_frame() if im_opencv is None: print("⚠️ 无法获取图像帧") continue if shizi.daoying(im_opencv[0]): mouse_gui.send_data_absolute(rw[0], rw[1] - 110, may=1) time.sleep(1) continue elif shizi.tiaozhan(im_opencv[0]): # 开启挑战 print('进入塔4') mouse_gui.send_data_absolute(left + 1100, top + 600, may=1) time.sleep(0.3) mouse_gui.send_data_absolute(left + 433, top + 455, may=1) panduan = True continue elif shizi.jieshu(im_opencv[0]): # 结束挑战 print('结束挑战') mouse_gui.send_data_absolute(left + 542, top + 644, may=1) time.sleep(0.8) mouse_gui.send_data_absolute(left + 706, top + 454, may=1) continue elif panduan: # 图内情况 print("在图内") if shizi.shuzi(im_opencv[0]): boss_pd = True print("进入到boss!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") if shizi.fuhuo(im_opencv[0]): print('点击复活') mouse_gui.send_data_absolute(left + 536, top + 627, may=1) time.sleep(0.15) keyboard.release() continue if shizi.tuichu(im_opencv[0]) and detections['next'] is None and len(detections['daojv']) == 0 and len(detections['gw']) == 0 and boss_pd: print("识别到可以退出挑战!!!!!!!!!!!!!!!!!!") for i in range(3): time.sleep(0.5) im_opencv = get_image.get_frame() # [RGB,PIL] if im_opencv is None: print("⚠️ 无法获取图像帧") continue detections = { 'center': None, 'next': None, 'npc1': None, 'npc2': None, 'npc3': None, 'npc4': None, 'boss': None, 'daojv': [], 'gw': [], 'zhaozi': None } detections = yolo_shibie(im_opencv[1], detections, model) if detections['next'] is not None or len(detections['daojv']) != 0 or len(detections['gw']) != 0 or detections['boss'] is not None: break else: mouse_gui.send_data_absolute(left + 640, top + 40, may=1) # 点击退出 panduan = False # 退出挑战 boss_pd = False time.sleep(2.0) continue if detections['center'] is None and detections['next'] is None and (len(detections['gw']) != 0 or detections["boss"] is not None): # 识别不到中心情况 但是有怪物 print("未检测到中心点,但是有怪物") if len(detections['gw']) != 0: move_to(rw, detections['gw'][0]) time.sleep(0.26) elif detections['boss'] is not None: # 跟随boss boss_suiji1 = random.randint(-30, 30) boss_suiji2 = random.randint(-30, 30) detections['boss'] = (detections['boss'][0] + boss_suiji1, detections['boss'][1] + boss_suiji2) move_to(rw, detections['boss']) time.sleep(0.7) continue elif (detections['center'] is not None and detections['next'] is None and len(detections['gw']) != 0) or (boss_pd == True and detections['center'] is not None and detections['next'] is None): # 识别到中心 但是有怪物 if detections['center'][0] >= rw[0] and detections['center'][1] < rw[1]: # 3 mb = (rw[0] + 100, rw[1]) elif detections['center'][0] <= rw[0] and detections['center'][1] < rw[1]: # 4 mb = (rw[0], rw[1] - 100) elif detections['center'][0] <= rw[0] and detections['center'][1] > rw[1]: # 1 mb = (rw[0] - 100, rw[1]) elif detections['center'][0] >= rw[0] and detections['center'][1] > rw[1]: # 2 mb = (rw[0], rw[1] + 100) move_to(rw, mb) time.sleep(0.25) continue elif boss_pd == True and detections['center'] is None and detections['next'] is None: # boss出现了 但是没有中心 k = move_randomly(rw, k) continue elif detections['next'] is not None: print('进入下一层啦啦啦啦啦啦') panduan = True move_to(rw, detections['next']) for i in range(2): keyboard.send_data("DD") time.sleep(0.15) keyboard.release() continue else: k = move_randomly(rw, k) continue elif shizi.daoying(im_opencv[0]): mouse_gui.send_data_absolute(rw[0], rw[1] - 110, may=1) time.sleep(1) continue