You need to enable JavaScript to run this app. 如何用Python实现游戏瓦片全遍历并优化pydirectinput控制代码
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python实现游戏瓦片全遍历并优化pydirectinput控制代码

问题背景

我需要实现游戏内的全瓦片扫描功能,此处“扫描”指控制角色移动到对应瓦片上并保存其坐标。如果角色碰撞到障碍物,需要尝试向下移动一个瓦片后继续前进,目前已经可以正常获取角色的当前朝向。
我使用pydirectinput库实现按键控制,因为pyautogui在我的目标游戏中无法正常生效。

现有代码

def coordinates():
    visited_coordinates = []
    t_end = time.time() + 90
    movements = []
    while time.time() < t_end:
        for message in generated_object():  # generated object returns a list with 4 elements
            if [message[0], message[1]] in visited_coordinates:
                if "left" in movements:
                    if "down" in movements:
                        if "right" in movements:
                            pydirectinput.press("up")
                            if message[3] != 4:  # 4 means it is facing up
                                pydirectinput.press("up")  # if it isn't facing up, it needs to be pressed twice
                            movements.append("up")
                        else:
                            pydirectinput.press("right")
                            if message[3] != 12:  # 12 means it is facing right
                                pydirectinput.press("right")  # same with facing right, and so on
                            movements.append("right")
                    else:
                        pydirectinput.press("down")
                        if message[3] != 0:  # 0 means it is facing down
                            pydirectinput.press("down")
                        movements.append("down")
                else:
                    pydirectinput.press("left")
                    if message[3] != 8:  # 8 means it is facing left
                        pydirectinput.press("left")
                    movements.append("left")
                continue
            movements = []
            if message[2] != 4:  # this means it went beyond the border, and it must return
                pydirectinput.press("right", presses=2)
            visited_coordinates.append([message[0], message[1]])

    return visited_coordinates

存在的问题

  • 用命名管道通信,需要读取每一条收到的消息,导致代码执行动作耗时极长
  • 嵌套判断过多属于典型的面条代码,可读性极差
  • 角色一旦超出边界后就无法返回,需要限制角色不再向左移动,但因为会重置movements列表,不知道该如何实现该逻辑

优化方案

1. 运行效率优化

  • 把已访问坐标从列表改为集合存储,in查询的时间复杂度从O(n)降到O(1),大幅提升重复坐标判断速度。注意集合不能存列表,所以可以把坐标转成元组存储:visited_coordinates = set(),添加时用visited_coordinates.add((message[0], message[1])),判断时直接查(message[0], message[1]) in visited_coordinates即可。
  • 管道读取部分可以加缓冲区批量读取消息,不要逐次阻塞读取单条消息,减少IO等待耗时。如果generated_object()是逐次返回消息的生成器,可以调整为每次批量拉取N条消息后统一处理,减少上下文切换开销。

2. 可读性优化:消除嵌套判断

把方向相关的配置抽成映射字典,避免多层if嵌套:

# 方向配置:方向名称 -> (朝向编码, 按键名)
DIR_CONFIG = {
    "left": (8, "left"),
    "down": (0, "down"),
    "right": (12, "right"),
    "up": (4, "up")
}
# 尝试移动的优先级顺序
MOVE_PRIORITY = ["left", "down", "right", "up"]

原来的多层嵌套判断可以直接简化为:

current_coord = (message[0], message[1])
if current_coord in visited_coordinates:
    # 按优先级找第一个没试过的方向
    for dir_name in MOVE_PRIORITY:
        if dir_name not in movements:
            target_facing, key = DIR_CONFIG[dir_name]
            press_count = 1 if message[3] == target_facing else 2
            pydirectinput.press(key, presses=press_count)
            movements.append(dir_name)
            break
    continue

3. 边界限制逻辑实现

不需要依赖movements列表存左移限制状态,单独加一个全局的边界标记即可:

# 初始化时加一个禁止左移的标记
ban_left_move = False

在触发越界的逻辑里设置标记:

if message[2] != 4:  # 触发越界
    pydirectinput.press("right", presses=2)
    ban_left_move = True  # 设置禁止左移标记

然后在判断移动方向的时候,优先排除左移选项:

for dir_name in MOVE_PRIORITY:
    # 禁止左移时直接跳过left方向
    if ban_left_move and dir_name == "left":
        continue
    if dir_name not in movements:
        # 后续移动逻辑不变

优化后完整代码示例

import time
import pydirectinput

# 方向配置:方向名称 -> (朝向编码, 按键名)
DIR_CONFIG = {
    "left": (8, "left"),
    "down": (0, "down"),
    "right": (12, "right"),
    "up": (4, "up")
}
# 尝试移动的优先级顺序
MOVE_PRIORITY = ["left", "down", "right", "up"]

def coordinates():
    visited_coordinates = set()
    t_end = time.time() + 90
    movements = []
    ban_left_move = False  # 越界后禁止左移的标记
    
    while time.time() < t_end:
        # 可根据需要调整generated_object为批量拉取消息
        for message in generated_object():
            current_coord = (message[0], message[1])
            if current_coord in visited_coordinates:
                # 按优先级找合法的移动方向
                for dir_name in MOVE_PRIORITY:
                    if ban_left_move and dir_name == "left":
                        continue
                    if dir_name not in movements:
                        target_facing, key = DIR_CONFIG[dir_name]
                        press_count = 1 if message[3] == target_facing else 2
                        pydirectinput.press(key, presses=press_count)
                        movements.append(dir_name)
                        break
                continue
            
            movements = []
            if message[2] != 4:  # 触发越界
                pydirectinput.press("right", presses=2)
                ban_left_move = True
            
            visited_coordinates.add(current_coord)
    
    # 如果需要返回列表格式可以转一下
    return [list(coord) for coord in visited_coordinates]

内容的提问来源于stack exchange,提问作者comodin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 03:54:08