#### 一、脚本架构升级:模块化设计与扩展性
在上一篇基础脚本的架构上,我们可以进一步优化设计,采用更先进的模块化架构,提高脚本的可维护性和扩展性。以下是一个升级版的脚本框架:
```python
import pyautogui
import cv2
import numpy as np
import time
import win32gui
import win32con
import random
import logging
from enum import Enum
from typing import Dict, List, Tuple, Optional
# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
class GameState(Enum):
BATTLE = 1 # 战斗状态
PICKING = 2 # 拾取状态
RETURNING = 3 # 回城状态
RESTING = 4 # 休息状态
ERROR = 5 # 错误状态
class ActionType(Enum):
ATTACK = 1 # 攻击
USE_SKILL = 2 # 使用技能
PICK = 3 # 拾取
DRINK_HP = 4 # 喝血药
DRINK_MP = 5 # 喝蓝药
RETURN_TOWN = 6 # 回城
SELL_ITEMS = 7 # 卖物品
REPAIR = 8 # 修理装备
class MonsterType(Enum):
NORMAL = 1 # 普通怪物
ELITE = 2 # 精英怪物
BOSS = 3 # 首领怪物
class LegendAutoScript:
def __init__(self):
# 游戏窗口信息
self.game_window_title = "复古传奇"
self.game_hwnd = None
self.game_rect = None
# 配置参数
self.config = {
"safe_hp_percent": 30,
"safe_mp_percent": 20,
"battle_interval": (1.0, 2.0),
"pick_interval": 3.0,
"max_inventory_percent": 80, # 背包最大占用百分比
"skill_key_mapping": { # 技能键位映射
"basic_attack": "space",
"skill1": "f1",
"skill2": "f2",
"skill3": "f3"
},
"monster_priority": [MonsterType.BOSS, MonsterType.ELITE, MonsterType.NORMAL]
}
# 游戏状态
self.current_state = GameState.BATTLE
self.last_action = None
self.last_action_time = 0
self.current_hp = 100
self.current_mp = 100
self.inventory_percent = 0
self.target_monster = None
# 物品和怪物识别模板
self.item_templates = self._load_templates("items")
self.monster_templates = self._load_templates("monsters")
# 战斗策略
self.combat_strategies = {
MonsterType.NORMAL: ["basic_attack"],
MonsterType.ELITE: ["basic_attack", "skill1"],
MonsterType.BOSS: ["basic_attack", "skill1", "skill2"]
}
# 任务系统
self.current_task = None
self.tasks_queue = []
def _load_templates(self, directory: str) -> Dict[str, Tuple[np.ndarray, Enum]]:
"""加载识别模板"""
templates = {}
# 实际实现中需要从指定目录加载图片并关联类型
# 简化示例,实际使用时需完善
return templates
def initialize(self) -> bool:
"""初始化游戏连接和配置"""
logger.info("正在初始化游戏连接...")
if not self._connect_to_game():
logger.error("游戏连接失败")
return False
logger.info("加载识别模板...")
self.item_templates = self._load_templates("items")
self.monster_templates = self._load_templates("monsters")
logger.info("初始化完成")
return True
def _connect_to_game(self) -> bool:
"""连接到游戏窗口"""
self.game_hwnd = win32gui.FindWindow(None, self.game_window_title)
if not self.game_hwnd:
logger.error(f"未找到游戏窗口: {self.game_window_title}")
return False
rect = win32gui.GetWindowRect(self.game_hwnd)
self.game_rect = (rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1])
logger.info(f"找到游戏窗口: {self.game_window_title}, 位置: {self.game_rect}")
# 激活窗口
win32gui.SetForegroundWindow(self.game_hwnd)
time.sleep(0.5)
return True
def update_game_state(self):
"""更新游戏状态"""
self._update_health_and_mana()
self._update_inventory()
self._detect_monsters()
self._update_state_machine()
def _update_health_and_mana(self):
"""更新角色血量和魔法值"""
# 实际实现中使用图像识别获取血条和魔法条状态
# 简化示例
self.current_hp = random.randint(1, 100)
self.current_mp = random.randint(1, 100)
logger.debug(f"当前状态: HP={self.current_hp}%, MP={self.current_mp}%")
def _update_inventory(self):
"""更新背包状态"""
# 实际实现中识别背包物品数量
# 简化示例
self.inventory_percent = random.randint(0, 100)
logger.debug(f"背包状态: {self.inventory_percent}%")
def _detect_monsters(self):
"""检测周围怪物"""
# 实际实现中使用图像识别检测怪物
# 简化示例
self.target_monster = {
"type": random.choice(list(MonsterType)),
"location": (random.randint(100, 500), random.randint(100, 400))
}
logger.debug(f"检测到怪物: {self.target_monster['type'].name}")
def _update_state_machine(self):
"""更新状态机"""
# 根据当前游戏状态决定行为
if self.current_hp < self.config["safe_hp_percent"]:
self.current_state = GameState.RETURNING
return
if self.current_mp < self.config["safe_mp_percent"]:
self.current_state = GameState.RETURNING
return
if self.inventory_percent > self.config["max_inventory_percent"]:
self.current_state = GameState.RETURNING
return
if self.target_monster:
self.current_state = GameState.BATTLE
else:
self.current_state = GameState.PICKING
def execute_action(self, action_type: ActionType, target: Optional[Tuple[int, int]] = None):
"""执行游戏动作"""
logger.info(f"执行动作: {action_type.name}")
self.last_action = action_type
self.last_action_time = time.time()
# 根据不同动作类型执行不同操作
if action_type == ActionType.ATTACK:
self._perform_attack(target)
elif action_type == ActionType.USE_SKILL:
self._use_skill(target)
elif action_type == ActionType.PICK:
self._pick_item(target)
elif action_type == ActionType.DRINK_HP:
self._drink_hp_potion()
elif action_type == ActionType.DRINK_MP:
self._drink_mp_potion()
elif action_type == ActionType.RETURN_TOWN:
self._return_to_town()
elif action_type == ActionType.SELL_ITEMS:
self._sell_items()
elif action_type == ActionType.REPAIR:
self._repair_equipment()
# 添加随机延迟,模拟人类操作
delay = random.uniform(0.3, 0.7)
time.sleep(delay)
def _perform_attack(self, target: Tuple[int, int]):
"""执行普通攻击"""
x, y = target
screen_x = self.game_rect[0] + x
screen_y = self.game_rect[1] + y
pyautogui.moveTo(screen_x, screen_y, duration=0.2 + random.random() * 0.3)
pyautogui.click()
def _use_skill(self, target: Tuple[int, int]):
"""使用技能"""
# 根据怪物类型选择合适的技能
monster_type = self.target_monster["type"]
skills = self.combat_strategies.get(monster_type, ["basic_attack"])
skill_key = self.config["skill_key_mapping"].get(skills[0], "space")
x, y = target
screen_x = self.game_rect[0] + x
screen_y = self.game_rect[1] + y
pyautogui.moveTo(screen_x, screen_y, duration=0.2 + random.random() * 0.3)
pyautogui.press(skill_key)
def _pick_item(self, target: Tuple[int, int]):
"""拾取物品"""
x, y = target
screen_x = self.game_rect[0] + x
screen_y = self.game_rect[1] + y
pyautogui.moveTo(screen_x, screen_y, duration=0.2 + random.random() * 0.3)
pyautogui.press('space')
def _drink_hp_potion(self):
"""喝血药"""
pyautogui.press('f4') # 假设F4是血药快捷键
def _drink_mp_potion(self):
"""喝蓝药"""
pyautogui.press('f5') # 假设F5是蓝药快捷键
def _return_to_town(self):
"""回城"""
logger.info("正在返回城镇...")
pyautogui.press('f2') # 假设F2是回城快捷键
time.sleep(8 + random.random() * 2) # 等待回城动画
def _sell_items(self):
"""卖物品"""
logger.info("正在出售物品...")
# 实现卖物品逻辑
time.sleep(5 + random.random() * 2)
def _repair_equipment(self):
"""修理装备"""
logger.info("正在修理装备...")
# 实现修理装备逻辑
time.sleep(3 + random.random() * 1)
def combat_loop(self):
"""战斗循环"""
while True:
try:
# 更新游戏状态
self.update_game_state()
# 根据当前状态执行相应动作
if self.current_state == GameState.BATTLE:
if self.target_monster:
# 选择合适的攻击方式
if self.current_mp > 50 and random.random() < 0.3:
self.execute_action(ActionType.USE_SKILL, self.target_monster["location"])
else:
self.execute_action(ActionType.ATTACK, self.target_monster["location"])
else:
# 没有目标,移动寻找怪物
self._move_to_random_location()
elif self.current_state == GameState.PICKING:
items = self._detect_items()
if items:
# 优先拾取价值高的物品
valuable_items = sorted(items, key=lambda x: x[2], reverse=True)
self.execute_action(ActionType.PICK, valuable_items[0][0:2])
else:
# 没有物品可拾取,继续寻找怪物
self.current_state = GameState.BATTLE
elif self.current_state == GameState.RETURNING:
self.execute_action(ActionType.RETURN_TOWN)
# 回城后执行卖物品和修理装备
if self.inventory_percent > self.config["max_inventory_percent"]:
self.execute_action(ActionType.SELL_ITEMS)
# 检查装备耐久度
if self._need_repair():
self.execute_action(ActionType.REPAIR)
# 补充药水
self._buy_potions()
# 回到战斗区域
self._move_to_combat_area()
self.current_state = GameState.BATTLE
elif self.current_state == GameState.RESTING:
# 休息恢复状态
time.sleep(5)
self.current_state = GameState.BATTLE
elif self.current_state == GameState.ERROR:
# 错误处理
logger.error("脚本遇到错误,尝试恢复...")
time.sleep(5)
self.current_state = GameState.BATTLE
# 添加随机延迟,避免行为过于规律
time.sleep(random.uniform(0.5, 1.5))
except Exception as e:
logger.error(f"发生异常: {str(e)}")
self.current_state = GameState.ERROR
time.sleep(5)
def _move_to_random_location(self):
"""移动到随机位置"""
if not self.game_rect:
return
left, top, width, height = self.game_rect
# 计算安全移动区域
move_area = (int(width * 0.3), int(height * 0.3),
int(width * 0.4), int(height * 0.4))
# 随机选择目标位置
x = left + move_area[0] + random.randint(0, move_area[2])
y = top + move_area[1] + random.randint(0, move_area[3])
# 模拟鼠标移动并点击地面
pyautogui.moveTo(x, y, duration=0.5 + random.random())
pyautogui.rightClick()
logger.info(f"移动到位置: ({x}, {y})")
# 等待角色移动
move_time = random.uniform(2.0, 5.0)
time.sleep(move_time)
def _detect_items(self) -> List[Tuple[int, int, int]]:
"""检测地面物品"""
# 实际实现中使用图像识别检测物品
# 返回值格式: [(x坐标, y坐标, 价值), ...]
return [
(random.randint(100, 500), random.randint(100, 400), random.randint(1, 100))
for _ in range(random.randint(0, 3))
]
def _need_repair(self) -> bool:
"""检查装备是否需要修理"""
# 实际实现中使用图像识别检查装备耐久度
# 简化示例
return random.random() < 0.3
def _buy_potions(self):
"""购买药水"""
logger.info("正在购买药水...")
# 实现购买药水逻辑
time.sleep(3 + random.random() * 2)
def _move_to_combat_area(self):
"""移动到战斗区域"""
logger.info("正在前往战斗区域...")
# 实现移动到预设战斗区域的逻辑
time.sleep(5 + random.random() * 3)
# 脚本入口
if __name__ == "__main__":
script = LegendAutoScript()
if script.initialize():
script.combat_loop()
```
#### 二、高级功能实现:智能战斗系统
在上一版基础脚本的基础上,我们实现了更高级的战斗系统,具有以下特性:
1. **状态机设计**:使用状态机管理不同游戏状态(战斗、拾取、回城等)
2. **怪物分类与优先级**:区分普通怪物、精英怪物和首领,设置不同的攻击策略
3. **技能系统**:根据怪物类型和角色状态智能选择技能
4. **背包管理**:自动回城卖物品,保持背包空间
5. **装备维护**:检测装备耐久度,自动修理装备
战斗系统的核心是根据不同怪物类型应用不同的战斗策略:
```python
# 战斗策略配置
self.combat_strategies = {
MonsterType.NORMAL: ["basic_attack"],
MonsterType.ELITE: ["basic_attack", "skill1"],
MonsterType.BOSS: ["basic_attack", "skill1", "skill2"]
}
# 根据怪物类型选择合适的技能
monster_type = self.target_monster["type"]
skills = self.combat_strategies.get(monster_type, ["basic_attack"])
skill_key = self.config["skill_key_mapping"].get(skills[0], "space")
```
#### 三、图像识别优化:提高准确性与性能
为了提高脚本的稳定性和可靠性,我们可以采用以下图像识别优化技术:
1. **多分辨率模板匹配**:支持不同分辨率的游戏窗口
2. **特征点匹配**:使用ORB或SIFT特征点匹配,提高复杂场景下的识别率
3. **图像预处理**:灰度化、二值化、降噪等预处理技术
4. **置信度阈值自适应**:根据场景复杂度自动调整匹配阈值
以下是一个优化后的图像识别函数:
```python
def find_template_on_screen(self, template, threshold=0.8, use_feature_matching=False) -> Optional[Tuple[int, int, float]]:
"""在屏幕上查找模板图像,支持特征点匹配"""
screen = self.capture_game_screen()
if screen is None:
return None
screen_gray = cv2.cvtColor(screen, cv2.COLOR_BGR2GRAY)
if use_feature_matching:
# 使用特征点匹配
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(template, None)
kp2, des2 = orb.detectAndCompute(screen_gray, None)
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)
matches = sorted(matches, by=lambda x: x.distance)
if len(matches) > 10: # 至少需要10个匹配点
src_pts = np.float32([kp1[m.queryIdx].pt for m in matches]).reshape(-1, 1, 2)
dst_pts = np.float32([kp2[m.trainIdx].pt for m in matches]).reshape(-1, 1, 2)
M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
if M is not None:
h, w = template.shape
pts = np.float32([[0, 0], [0, h-1], [w-1, h-1], [w-1, 0]]).reshape(-1, 1, 2)
dst = cv2.perspectiveTranorm(pts, M)
# 计算中心点
center_x = int(np.mean(dst[:, :, 0]))
center_y = int(np.mean(dst[:, :, 1]))
# 计算匹配置信度
confidence = len(matches) / max(len(kp1), len(kp2))
return (center_x, center_y, confidence)
return None
else:
# 使用模板匹配
result = cv2.matchTemplate(screen_gray, template, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
if max_val >= threshold:
h, w = template.shape
center_x = max_loc[0] + w // 2
center_y = max_loc[1] + h // 2
return (center_x, center_y, max_val)
return None
```
#### 四、任务系统设计:实现自动化游戏流程
为了实现更复杂的游戏自动化功能,我们可以设计一个任务系统,使脚本能够按照预设流程完成一系列任务:
```python
class Task:
def __init__(self, task_type, target=None, params=None):
self.task_type = task_type # 任务类型:打怪、采集、任务等
self.target = target # 任务目标:怪物ID、NPC位置等
self.params = params or {} # 任务参数
self.status = "pending" # 任务状态:pending, running, completed, failed
self.progress = 0 # 任务进度
self.start_time = 0 # 任务开始时间
self.end_time = 0 # 任务结束时间
def update(self, script):
"""更新任务状态"""
if self.status == "pending":
self._start(script)
elif self.status == "running":
self._execute(script)
def _start(self, script):
"""开始任务"""
self.status = "running"
self.start_time = time.time()
logger.info(f"开始任务: {self.task_type}, 目标: {self.target}")
def _execute(self, script):
"""执行任务逻辑,由子类实现"""
pass
def complete(self):
"""完成任务"""
self.status = "completed"
self.end_time = time.time()
logger.info(f"任务完成: {self.task_type}, 耗时: {self.end_time - self.start_time:.2f}秒")
def fail(self, reason="未知原因"):
"""任务失败"""
self.status = "failed"
self.end_time = time.time()
logger.info(f"任务失败: {self.task_type}, 原因: {reason}, 耗时: {self.end_time - self.start_time:.2f}秒")
class KillMonsterTask(Task):
def __init__(self, monster_type, count=1):
super().__init__("kill_monster", monster_type, {"count": count})
self.killed_count = 0
def _execute(self, script):
# 检查是否达到目标数量
if self.killed_count >= self.params["count"]:
self.complete()
return
# 如果没有目标,寻找目标
if not script.target_monster or script.target_monster["type"] != self.target:
script._find_specific_monster(self.target)
return
# 攻击目标
script.execute_action(ActionType.ATTACK, script.target_monster["location"])
# 模拟击杀逻辑
if random.random() < 0.3: # 假设30%的攻击能击杀怪物
self.killed_count += 1
self.progress = self.killed_count / self.params["count"] * 100
logger.info(f"击杀怪物 {self.target.name}, 进度: {self.killed_count}/{self.params['count']}")
# 在脚本中添加任务管理功能
class LegendAutoScript:
def __init__(self):
# ... 已有代码 ...
# 任务系统
self.current_task = None
self.tasks_queue = []
def add_task(self, task):
"""添加任务到队列"""
self.tasks_queue.append(task)
logger.info(f"添加任务到队列: {task.task_type}, 目标: {task.target}")
def process_tasks(self):
"""处理任务队列"""
if self.current_task is None and self.tasks_queue:
self.current_task = self.tasks_queue.pop(0)
if self.current_task:
self.current_task.update(self)
if self.current_task.status in ["completed", "failed"]:
self.current_task = None if not self.tasks_queue else self.tasks_queue.pop(0)
```
#### 五、反检测技术:保持脚本使用安全
使用游戏辅助脚本存在被游戏检测的风险,以下是一些常用的反检测技术:
1. **操作随机化**:在鼠标移动、点击间隔、按键时间等加入随机变化
2. **行为模式多样化**:模拟人类玩家的不规则行为,避免固定模式
3. **响应延迟**:添加随机思考时间,模拟人类决策过程
4. **异常处理**:添加意外情况处理机制,如游戏掉线、UI变化等
5. **使用频率控制**:不要长时间连续运行脚本,适当休息
在我们的脚本中,已经实现了部分反检测措施:
```python
# 添加随机延迟,模拟人类操作
delay = random.uniform(0.3, 0.7)
time.sleep(delay)
# 随机选择目标位置
x = left + move_area[0] + random.randint(0, move_area[2])
y = top + move_area[1] + random.randint(0, move_area[3])
# 模拟鼠标移动曲线,更像人类操作
pyautogui.moveTo(x, y, duration=0.5 + random.random())
```
#### 六、脚本部署与调试指南
1. **环境准备**
- 安装Python 3.7+
- 安装必要的库:`pip install pyautogui opencv-python numpy pywin32`
- 准备模板图片:在项目目录下创建`items`和`monsters`文件夹,放入对应的模板图片
2. **配置调整**
- 修改脚本中的游戏窗口标题,确保能正确找到游戏窗口
- 根据自己的快捷键设置,调整技能键位映射
- 根据游戏界面,调整血条、魔法条的识别区域
3. **调试技巧**
- 使用日志系统查看脚本运行状态
- 先在小范围内测试脚本功能,确保各部分正常工作
- 使用截图功能保存游戏画面,便于分析识别问题
- 逐步增加功能复杂度,不要一次性添加太多功能
4. **常见问题解决**
- 脚本无法找到游戏窗口:检查窗口标题是否正确,确保游戏已启动
- 图像识别不准确:调整模板图片质量,尝试不同的匹配阈值
- 脚本操作无响应:检查游戏窗口是否被遮挡,是否有焦点
通过这些技术,你可以开发出一个功能强大、稳定可靠的复古传奇自动化脚本,帮助你更轻松地体验游戏。记住合理使用脚本,避免过度依赖,保持游戏的乐趣。

